@cheqd/sdk-esm 5.3.4-develop.2

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 (68) hide show
  1. package/build/index.d.ts +140 -0
  2. package/build/index.d.ts.map +1 -0
  3. package/build/index.js +182 -0
  4. package/build/index.js.map +1 -0
  5. package/build/modules/_.d.ts +62 -0
  6. package/build/modules/_.d.ts.map +1 -0
  7. package/build/modules/_.js +75 -0
  8. package/build/modules/_.js.map +1 -0
  9. package/build/modules/did.d.ts +386 -0
  10. package/build/modules/did.d.ts.map +1 -0
  11. package/build/modules/did.js +1013 -0
  12. package/build/modules/did.js.map +1 -0
  13. package/build/modules/feeabstraction.d.ts +409 -0
  14. package/build/modules/feeabstraction.d.ts.map +1 -0
  15. package/build/modules/feeabstraction.js +462 -0
  16. package/build/modules/feeabstraction.js.map +1 -0
  17. package/build/modules/feemarket.d.ts +242 -0
  18. package/build/modules/feemarket.d.ts.map +1 -0
  19. package/build/modules/feemarket.js +296 -0
  20. package/build/modules/feemarket.js.map +1 -0
  21. package/build/modules/resource.d.ts +204 -0
  22. package/build/modules/resource.d.ts.map +1 -0
  23. package/build/modules/resource.js +297 -0
  24. package/build/modules/resource.js.map +1 -0
  25. package/build/package.json +64 -0
  26. package/build/querier.d.ts +62 -0
  27. package/build/querier.d.ts.map +1 -0
  28. package/build/querier.js +86 -0
  29. package/build/querier.js.map +1 -0
  30. package/build/registry.d.ts +18 -0
  31. package/build/registry.d.ts.map +1 -0
  32. package/build/registry.js +23 -0
  33. package/build/registry.js.map +1 -0
  34. package/build/signer.d.ts +190 -0
  35. package/build/signer.d.ts.map +1 -0
  36. package/build/signer.js +547 -0
  37. package/build/signer.js.map +1 -0
  38. package/build/types/index.d.ts +140 -0
  39. package/build/types/index.d.ts.map +1 -0
  40. package/build/types/modules/_.d.ts +62 -0
  41. package/build/types/modules/_.d.ts.map +1 -0
  42. package/build/types/modules/did.d.ts +386 -0
  43. package/build/types/modules/did.d.ts.map +1 -0
  44. package/build/types/modules/feeabstraction.d.ts +409 -0
  45. package/build/types/modules/feeabstraction.d.ts.map +1 -0
  46. package/build/types/modules/feemarket.d.ts +242 -0
  47. package/build/types/modules/feemarket.d.ts.map +1 -0
  48. package/build/types/modules/resource.d.ts +204 -0
  49. package/build/types/modules/resource.d.ts.map +1 -0
  50. package/build/types/querier.d.ts +62 -0
  51. package/build/types/querier.d.ts.map +1 -0
  52. package/build/types/registry.d.ts +18 -0
  53. package/build/types/registry.d.ts.map +1 -0
  54. package/build/types/signer.d.ts +190 -0
  55. package/build/types/signer.d.ts.map +1 -0
  56. package/build/types/types.d.ts +196 -0
  57. package/build/types/types.d.ts.map +1 -0
  58. package/build/types/utils.d.ts +223 -0
  59. package/build/types/utils.d.ts.map +1 -0
  60. package/build/types.d.ts +196 -0
  61. package/build/types.d.ts.map +1 -0
  62. package/build/types.js +43 -0
  63. package/build/types.js.map +1 -0
  64. package/build/utils.d.ts +223 -0
  65. package/build/utils.d.ts.map +1 -0
  66. package/build/utils.js +541 -0
  67. package/build/utils.js.map +1 -0
  68. package/package.json +64 -0
@@ -0,0 +1,1013 @@
1
+ import { createPagination, createProtobufRpcClient } from '@cosmjs/stargate';
2
+ import { AbstractCheqdSDKModule } from './_.js';
3
+ import { ISignInputs, VerificationMethods, } from '../types.js';
4
+ import { MsgCreateDidDoc, MsgCreateDidDocPayload, MsgCreateDidDocResponse, MsgDeactivateDidDoc, MsgDeactivateDidDocPayload, MsgDeactivateDidDocResponse, MsgUpdateDidDoc, MsgUpdateDidDocPayload, MsgUpdateDidDocResponse, protobufPackage, QueryClientImpl, VerificationMethod, } from '@cheqd/ts-proto/cheqd/did/v2/index.js';
5
+ import { v4 } from 'uuid';
6
+ import { assert } from '@cosmjs/utils';
7
+ import { denormalizeService, normalizeAuthentication, normalizeController, normalizeService } from '../utils.js';
8
+ /** Default extension key for DID-related query operations */
9
+ export const defaultDidExtensionKey = 'did';
10
+ /**
11
+ * Standard W3C and DID-related context URIs used in DID documents.
12
+ * These contexts define the semantic meaning of properties in DID documents.
13
+ */
14
+ export const contexts = {
15
+ /** W3C DID Core v1 context */
16
+ W3CDIDv1: 'https://www.w3.org/ns/did/v1',
17
+ /** Ed25519 Signature Suite 2020 context */
18
+ W3CSuiteEd255192020: 'https://w3id.org/security/suites/ed25519-2020/v1',
19
+ /** Ed25519 Signature Suite 2018 context */
20
+ W3CSuiteEd255192018: 'https://w3id.org/security/suites/ed25519-2018/v1',
21
+ /** JSON Web Signature Suite 2020 context */
22
+ W3CSuiteJws2020: 'https://w3id.org/security/suites/jws-2020/v1',
23
+ /** Linked Domains context for domain verification */
24
+ LinkedDomainsContext: 'https://identity.foundation/.well-known/did-configuration/v1',
25
+ };
26
+ /**
27
+ * Protobuf message type literals for DID operations.
28
+ * Used for consistent message type identification across the module.
29
+ */
30
+ export const protobufLiterals = {
31
+ /** Create DID document message type */
32
+ MsgCreateDidDoc: 'MsgCreateDidDoc',
33
+ /** Create DID document response message type */
34
+ MsgCreateDidDocResponse: 'MsgCreateDidDocResponse',
35
+ /** Update DID document message type */
36
+ MsgUpdateDidDoc: 'MsgUpdateDidDoc',
37
+ /** Update DID document response message type */
38
+ MsgUpdateDidDocResponse: 'MsgUpdateDidDocResponse',
39
+ /** Deactivate DID document message type */
40
+ MsgDeactivateDidDoc: 'MsgDeactivateDidDoc',
41
+ /** Deactivate DID document response message type */
42
+ MsgDeactivateDidDocResponse: 'MsgDeactivateDidDocResponse',
43
+ };
44
+ /** Type URL for MsgCreateDidDoc messages */
45
+ export const typeUrlMsgCreateDidDoc = `/${protobufPackage}.${protobufLiterals.MsgCreateDidDoc}`;
46
+ /** Type URL for MsgCreateDidDocResponse messages */
47
+ export const typeUrlMsgCreateDidDocResponse = `/${protobufPackage}.${protobufLiterals.MsgCreateDidDocResponse}`;
48
+ /** Type URL for MsgUpdateDidDoc messages */
49
+ export const typeUrlMsgUpdateDidDoc = `/${protobufPackage}.${protobufLiterals.MsgUpdateDidDoc}`;
50
+ /** Type URL for MsgUpdateDidDocResponse messages */
51
+ export const typeUrlMsgUpdateDidDocResponse = `/${protobufPackage}.${protobufLiterals.MsgUpdateDidDocResponse}`;
52
+ /** Type URL for MsgDeactivateDidDoc messages */
53
+ export const typeUrlMsgDeactivateDidDoc = `/${protobufPackage}.${protobufLiterals.MsgDeactivateDidDoc}`;
54
+ /** Type URL for MsgDeactivateDidDocResponse messages */
55
+ export const typeUrlMsgDeactivateDidDocResponse = `/${protobufPackage}.${protobufLiterals.MsgDeactivateDidDocResponse}`;
56
+ /**
57
+ * Type guard function to check if an object is a MsgCreateDidDocEncodeObject.
58
+ *
59
+ * @param obj - EncodeObject to check
60
+ * @returns True if the object is a MsgCreateDidDocEncodeObject
61
+ */
62
+ export function isMsgCreateDidDocEncodeObject(obj) {
63
+ return obj.typeUrl === typeUrlMsgCreateDidDoc;
64
+ }
65
+ /**
66
+ * Type guard function to check if an object is a MsgUpdateDidDocEncodeObject.
67
+ *
68
+ * @param obj - EncodeObject to check
69
+ * @returns True if the object is a MsgUpdateDidDocEncodeObject
70
+ */
71
+ export function isMsgUpdateDidDocEncodeObject(obj) {
72
+ return obj.typeUrl === typeUrlMsgUpdateDidDoc;
73
+ }
74
+ /**
75
+ * Type guard function to check if an object is a MsgDeactivateDidDocEncodeObject.
76
+ *
77
+ * @param obj - EncodeObject to check
78
+ * @returns True if the object is a MsgDeactivateDidDocEncodeObject
79
+ */
80
+ export function isMsgDeactivateDidDocEncodeObject(obj) {
81
+ return obj.typeUrl === typeUrlMsgDeactivateDidDoc;
82
+ }
83
+ /**
84
+ * Type guard function to check if an object is a MsgCreateDidDocResponseEncodeObject.
85
+ *
86
+ * @param obj - EncodeObject to check
87
+ * @returns True if the object is a MsgCreateDidDocResponseEncodeObject
88
+ */
89
+ export function MsgCreateDidDocResponseEncodeObject(obj) {
90
+ return obj.typeUrl === typeUrlMsgCreateDidDocResponse;
91
+ }
92
+ /**
93
+ * Type guard function to check if an object is a MsgUpdateDidDocEncodeObject.
94
+ *
95
+ * @param obj - EncodeObject to check
96
+ * @returns True if the object is a MsgUpdateDidDocEncodeObject
97
+ */
98
+ export function MsgUpdateDidDocEncodeObject(obj) {
99
+ return obj.typeUrl === typeUrlMsgUpdateDidDoc;
100
+ }
101
+ /**
102
+ * Type guard function to check if an object is a MsgUpdateDidDocResponseEncodeObject.
103
+ *
104
+ * @param obj - EncodeObject to check
105
+ * @returns True if the object is a MsgUpdateDidDocResponseEncodeObject
106
+ */
107
+ export function MsgUpdateDidDocResponseEncodeObject(obj) {
108
+ return obj.typeUrl === typeUrlMsgUpdateDidDocResponse;
109
+ }
110
+ /**
111
+ * Type guard function to check if an object is a MsgDeactivateDidDocEncodeObject.
112
+ *
113
+ * @param obj - EncodeObject to check
114
+ * @returns True if the object is a MsgDeactivateDidDocEncodeObject
115
+ */
116
+ export function MsgDeactivateDidDocEncodeObject(obj) {
117
+ return obj.typeUrl === typeUrlMsgDeactivateDidDoc;
118
+ }
119
+ /**
120
+ * Type guard function to check if an object is a MsgDeactivateDidDocResponseEncodeObject.
121
+ *
122
+ * @param obj - EncodeObject to check
123
+ * @returns True if the object is a MsgDeactivateDidDocResponseEncodeObject
124
+ */
125
+ export function MsgDeactiveDidDocResponseEncodeObject(obj) {
126
+ return obj.typeUrl === typeUrlMsgUpdateDidDocResponse;
127
+ }
128
+ /**
129
+ * Sets up the DID extension for the querier client.
130
+ * Creates and configures the DID-specific query methods.
131
+ *
132
+ * @param base - Base QueryClient to extend
133
+ * @returns Configured DID extension with query methods
134
+ */
135
+ export const setupDidExtension = (base) => {
136
+ const rpc = createProtobufRpcClient(base);
137
+ const queryService = new QueryClientImpl(rpc);
138
+ return {
139
+ [defaultDidExtensionKey]: {
140
+ didDoc: async (id) => {
141
+ const { value } = await queryService.DidDoc({ id });
142
+ assert(value);
143
+ return value;
144
+ },
145
+ didDocVersion: async (id, versionId) => {
146
+ const { value } = await queryService.DidDocVersion({ id, version: versionId });
147
+ assert(value);
148
+ return value;
149
+ },
150
+ allDidDocVersionsMetadata: async (id, paginationKey) => {
151
+ const response = await queryService.AllDidDocVersionsMetadata({
152
+ id,
153
+ pagination: createPagination(paginationKey),
154
+ });
155
+ return response;
156
+ },
157
+ },
158
+ };
159
+ };
160
+ /**
161
+ * DID Module class providing comprehensive DID document management functionality.
162
+ * Handles creation, updates, deactivation, and querying of DID documents on the Cheqd blockchain.
163
+ */
164
+ export class DIDModule extends AbstractCheqdSDKModule {
165
+ // @ts-expect-error underlying type `GeneratedType` is intentionally wider
166
+ static registryTypes = [
167
+ [typeUrlMsgCreateDidDoc, MsgCreateDidDoc],
168
+ [typeUrlMsgCreateDidDocResponse, MsgCreateDidDocResponse],
169
+ [typeUrlMsgUpdateDidDoc, MsgUpdateDidDoc],
170
+ [typeUrlMsgUpdateDidDocResponse, MsgUpdateDidDocResponse],
171
+ [typeUrlMsgDeactivateDidDoc, MsgDeactivateDidDoc],
172
+ [typeUrlMsgDeactivateDidDocResponse, MsgDeactivateDidDocResponse],
173
+ ];
174
+ /** Base denomination for Cheqd network transactions */
175
+ static baseMinimalDenom = 'ncheq';
176
+ /**
177
+ * Standard fee amounts for DID operations.
178
+ * These represent the default costs for different DID document operations.
179
+ */
180
+ static fees = {
181
+ /** Default fee for creating a new DID document */
182
+ DefaultCreateDidDocFee: { amount: '50000000000', denom: DIDModule.baseMinimalDenom },
183
+ /** Default fee for updating an existing DID document */
184
+ DefaultUpdateDidDocFee: { amount: '25000000000', denom: DIDModule.baseMinimalDenom },
185
+ /** Default fee for deactivating a DID document */
186
+ DefaultDeactivateDidDocFee: { amount: '10000000000', denom: DIDModule.baseMinimalDenom },
187
+ };
188
+ /** Querier extension setup function for DID operations */
189
+ static querierExtensionSetup = setupDidExtension;
190
+ /** Querier instance with DID extension capabilities */
191
+ querier;
192
+ /**
193
+ * Constructs a new DID module instance.
194
+ *
195
+ * @param signer - Signing client for blockchain transactions
196
+ * @param querier - Querier client with DID extension for data retrieval
197
+ */
198
+ constructor(signer, querier) {
199
+ super(signer, querier);
200
+ this.querier = querier;
201
+ this.methods = {
202
+ createDidDocTx: this.createDidDocTx.bind(this),
203
+ updateDidDocTx: this.updateDidDocTx.bind(this),
204
+ deactivateDidDocTx: this.deactivateDidDocTx.bind(this),
205
+ queryDidDoc: this.queryDidDoc.bind(this),
206
+ queryDidDocVersion: this.queryDidDocVersion.bind(this),
207
+ queryAllDidDocVersionsMetadata: this.queryAllDidDocVersionsMetadata.bind(this),
208
+ };
209
+ }
210
+ /**
211
+ * Gets the registry types for DID message encoding/decoding.
212
+ *
213
+ * @returns Iterable of [typeUrl, GeneratedType] pairs for the registry
214
+ */
215
+ getRegistryTypes() {
216
+ return DIDModule.registryTypes;
217
+ }
218
+ /**
219
+ * Gets the querier extension setup for DID operations.
220
+ *
221
+ * @returns Query extension setup function for DID functionality
222
+ */
223
+ getQuerierExtensionSetup() {
224
+ return DIDModule.querierExtensionSetup;
225
+ }
226
+ /**
227
+ * Creates a new DID document transaction on the blockchain.
228
+ * Validates the DID payload and authentication before submission.
229
+ *
230
+ * @param signInputs - Signing inputs or pre-computed signatures for the transaction
231
+ * @param didPayload - DID document payload to create
232
+ * @param address - Address of the account submitting the transaction
233
+ * @param fee - Transaction fee configuration or 'auto' for automatic calculation
234
+ * @param memo - Optional transaction memo
235
+ * @param versionId - Optional version identifier for the DID document
236
+ * @param context - Optional SDK context for accessing clients
237
+ * @returns Promise resolving to the transaction response
238
+ * @throws Error if DID payload is not spec compliant or authentication is invalid
239
+ */
240
+ async createDidDocTx(signInputs, didPayload, address, fee, memo, versionId, context) {
241
+ if (!this._signer) {
242
+ this._signer = context.sdk.signer;
243
+ }
244
+ if (!this.querier) {
245
+ this.querier = context.sdk.querier;
246
+ }
247
+ if (!versionId || versionId === '') {
248
+ versionId = v4();
249
+ }
250
+ const { valid, error, protobufVerificationMethod, protobufService } = await DIDModule.validateSpecCompliantPayload(didPayload);
251
+ if (!valid) {
252
+ throw new Error(`DID payload is not spec compliant: ${error}`);
253
+ }
254
+ const { valid: authenticationValid, error: authenticationError } = await DIDModule.validateAuthenticationAgainstSignatures(didPayload, signInputs, this.querier);
255
+ if (!authenticationValid) {
256
+ throw new Error(`DID authentication is not valid: ${authenticationError}`);
257
+ }
258
+ const payload = MsgCreateDidDocPayload.fromPartial({
259
+ context: didPayload?.['@context'],
260
+ id: didPayload.id,
261
+ controller: didPayload.controller,
262
+ verificationMethod: protobufVerificationMethod,
263
+ authentication: didPayload.authentication,
264
+ assertionMethod: didPayload.assertionMethod,
265
+ capabilityInvocation: didPayload.capabilityInvocation,
266
+ capabilityDelegation: didPayload.capabilityDelegation,
267
+ keyAgreement: didPayload.keyAgreement,
268
+ service: protobufService,
269
+ alsoKnownAs: didPayload.alsoKnownAs,
270
+ versionId: versionId,
271
+ });
272
+ let signatures;
273
+ if (ISignInputs.isSignInput(signInputs)) {
274
+ signatures = await this._signer.signCreateDidDocTx(signInputs, payload);
275
+ }
276
+ else {
277
+ signatures = signInputs;
278
+ }
279
+ const value = {
280
+ payload,
281
+ signatures,
282
+ };
283
+ const createDidMsg = {
284
+ typeUrl: typeUrlMsgCreateDidDoc,
285
+ value,
286
+ };
287
+ if (address === '') {
288
+ address = (await context.sdk.options.wallet.getAccounts())[0].address;
289
+ }
290
+ if (!fee) {
291
+ fee = await DIDModule.generateCreateDidDocFees(address);
292
+ }
293
+ return this._signer.signAndBroadcast(address, [createDidMsg], fee, memo);
294
+ }
295
+ /**
296
+ * Updates an existing DID document transaction on the blockchain.
297
+ * Validates the updated DID payload and handles key rotation scenarios.
298
+ *
299
+ * @param signInputs - Signing inputs or pre-computed signatures for the transaction
300
+ * @param didPayload - Updated DID document payload
301
+ * @param address - Address of the account submitting the transaction
302
+ * @param fee - Transaction fee configuration or 'auto' for automatic calculation
303
+ * @param memo - Optional transaction memo
304
+ * @param versionId - Optional version identifier for the updated DID document
305
+ * @param context - Optional SDK context for accessing clients
306
+ * @returns Promise resolving to the transaction response
307
+ * @throws Error if DID payload is not spec compliant or authentication is invalid
308
+ */
309
+ async updateDidDocTx(signInputs, didPayload, address, fee, memo, versionId, context) {
310
+ if (!this._signer) {
311
+ this._signer = context.sdk.signer;
312
+ }
313
+ if (!this.querier) {
314
+ this.querier = context.sdk.querier;
315
+ }
316
+ if (!versionId || versionId === '') {
317
+ versionId = v4();
318
+ }
319
+ const { valid, error, protobufVerificationMethod, protobufService } = await DIDModule.validateSpecCompliantPayload(didPayload);
320
+ if (!valid) {
321
+ throw new Error(`DID payload is not spec compliant: ${error}`);
322
+ }
323
+ const { valid: authenticationValid, error: authenticationError, externalControllersDocuments, previousDidDocument, } = await DIDModule.validateAuthenticationAgainstSignaturesKeyRotation(didPayload, signInputs, this.querier);
324
+ if (!authenticationValid) {
325
+ throw new Error(`DID authentication is not valid: ${authenticationError}`);
326
+ }
327
+ const payload = MsgUpdateDidDocPayload.fromPartial({
328
+ context: didPayload?.['@context'],
329
+ id: didPayload.id,
330
+ controller: didPayload.controller,
331
+ verificationMethod: protobufVerificationMethod,
332
+ authentication: didPayload.authentication,
333
+ assertionMethod: didPayload.assertionMethod,
334
+ capabilityInvocation: didPayload.capabilityInvocation,
335
+ capabilityDelegation: didPayload.capabilityDelegation,
336
+ keyAgreement: didPayload.keyAgreement,
337
+ service: protobufService,
338
+ alsoKnownAs: didPayload.alsoKnownAs,
339
+ versionId: versionId,
340
+ });
341
+ let signatures;
342
+ if (ISignInputs.isSignInput(signInputs)) {
343
+ signatures = await this._signer.signUpdateDidDocTx(signInputs, payload, externalControllersDocuments, previousDidDocument);
344
+ }
345
+ else {
346
+ signatures = signInputs;
347
+ }
348
+ const value = {
349
+ payload,
350
+ signatures,
351
+ };
352
+ const updateDidMsg = {
353
+ typeUrl: typeUrlMsgUpdateDidDoc,
354
+ value,
355
+ };
356
+ if (address === '') {
357
+ address = (await context.sdk.options.wallet.getAccounts())[0].address;
358
+ }
359
+ if (!fee) {
360
+ fee = await DIDModule.generateUpdateDidDocFees(address);
361
+ }
362
+ return this._signer.signAndBroadcast(address, [updateDidMsg], fee, memo);
363
+ }
364
+ /**
365
+ * Deactivates an existing DID document transaction on the blockchain.
366
+ * Validates authentication and creates a deactivation transaction.
367
+ *
368
+ * @param signInputs - Signing inputs or pre-computed signatures for the transaction
369
+ * @param didPayload - DID document payload containing the ID to deactivate
370
+ * @param address - Address of the account submitting the transaction
371
+ * @param fee - Transaction fee configuration or 'auto' for automatic calculation
372
+ * @param memo - Optional transaction memo
373
+ * @param versionId - Optional version identifier for the deactivation
374
+ * @param context - Optional SDK context for accessing clients
375
+ * @returns Promise resolving to the transaction response
376
+ * @throws Error if DID payload is not spec compliant or authentication is invalid
377
+ */
378
+ async deactivateDidDocTx(signInputs, didPayload, address, fee, memo, versionId, context) {
379
+ if (!this._signer) {
380
+ this._signer = context.sdk.signer;
381
+ }
382
+ if (!versionId || versionId === '') {
383
+ versionId = v4();
384
+ }
385
+ const { valid, error, protobufVerificationMethod } = await DIDModule.validateSpecCompliantPayload(didPayload);
386
+ if (!valid) {
387
+ throw new Error(`DID payload is not spec compliant: ${error}`);
388
+ }
389
+ const { valid: authenticationValid, error: authenticationError } = await DIDModule.validateAuthenticationAgainstSignatures(didPayload, signInputs, this.querier);
390
+ if (!authenticationValid) {
391
+ throw new Error(`DID authentication is not valid: ${authenticationError}`);
392
+ }
393
+ const payload = MsgDeactivateDidDocPayload.fromPartial({
394
+ id: didPayload.id,
395
+ versionId: versionId,
396
+ });
397
+ let signatures;
398
+ if (ISignInputs.isSignInput(signInputs)) {
399
+ signatures = await this._signer.signDeactivateDidDocTx(signInputs, payload, protobufVerificationMethod);
400
+ }
401
+ else {
402
+ signatures = signInputs;
403
+ }
404
+ const value = {
405
+ payload,
406
+ signatures,
407
+ };
408
+ const deactivateDidMsg = {
409
+ typeUrl: typeUrlMsgDeactivateDidDoc,
410
+ value,
411
+ };
412
+ if (address === '') {
413
+ address = (await context.sdk.options.wallet.getAccounts())[0].address;
414
+ }
415
+ if (!fee) {
416
+ fee = await DIDModule.generateDeactivateDidDocFees(address);
417
+ }
418
+ return this._signer.signAndBroadcast(address, [deactivateDidMsg], fee, memo);
419
+ }
420
+ /**
421
+ * Queries a DID document by its identifier.
422
+ * Retrieves the latest version of the DID document with metadata.
423
+ *
424
+ * @param id - DID identifier to query
425
+ * @param context - Optional SDK context for accessing clients
426
+ * @returns Promise resolving to the DID document with metadata
427
+ */
428
+ async queryDidDoc(id, context) {
429
+ if (!this.querier) {
430
+ this.querier = context.sdk.querier;
431
+ }
432
+ const { didDoc, metadata } = await this.querier[defaultDidExtensionKey].didDoc(id);
433
+ return {
434
+ didDocument: await DIDModule.toSpecCompliantPayload(didDoc),
435
+ didDocumentMetadata: await DIDModule.toSpecCompliantMetadata(metadata),
436
+ };
437
+ }
438
+ /**
439
+ * Queries a specific version of a DID document by its identifier and version ID.
440
+ *
441
+ * @param id - DID identifier to query
442
+ * @param versionId - Specific version identifier to retrieve
443
+ * @param context - Optional SDK context for accessing clients
444
+ * @returns Promise resolving to the DID document version with metadata
445
+ */
446
+ async queryDidDocVersion(id, versionId, context) {
447
+ if (!this.querier) {
448
+ this.querier = context.sdk.querier;
449
+ }
450
+ const { didDoc, metadata } = await this.querier[defaultDidExtensionKey].didDocVersion(id, versionId);
451
+ return {
452
+ didDocument: await DIDModule.toSpecCompliantPayload(didDoc),
453
+ didDocumentMetadata: await DIDModule.toSpecCompliantMetadata(metadata),
454
+ };
455
+ }
456
+ /**
457
+ * Queries metadata for all versions of a DID document.
458
+ * Retrieves version history information for a specific DID.
459
+ *
460
+ * @param id - DID identifier to query version metadata for
461
+ * @param context - Optional SDK context for accessing clients
462
+ * @returns Promise resolving to array of version metadata and pagination info
463
+ */
464
+ async queryAllDidDocVersionsMetadata(id, context) {
465
+ if (!this.querier) {
466
+ this.querier = context.sdk.querier;
467
+ }
468
+ const { versions, pagination } = await this.querier[defaultDidExtensionKey].allDidDocVersionsMetadata(id);
469
+ return {
470
+ didDocumentVersionsMetadata: await Promise.all(versions.map(async (m) => await DIDModule.toSpecCompliantMetadata(m))),
471
+ pagination,
472
+ };
473
+ }
474
+ /**
475
+ * Validates a DID document against the Cheqd specification requirements.
476
+ * Ensures all required fields are present and verification methods are supported.
477
+ *
478
+ * @param didDocument - DID document to validate
479
+ * @returns Promise resolving to validation result with protobuf conversion or error details
480
+ */
481
+ static async validateSpecCompliantPayload(didDocument) {
482
+ // id is required, validated on both compile and runtime
483
+ if (!didDocument?.id)
484
+ return { valid: false, error: 'id is required' };
485
+ // verificationMethod is required
486
+ if (!didDocument?.verificationMethod)
487
+ return { valid: false, error: 'verificationMethod is required' };
488
+ // verificationMethod must be an array
489
+ if (!Array.isArray(didDocument?.verificationMethod))
490
+ return { valid: false, error: 'verificationMethod must be an array' };
491
+ // verificationMethod types must be supported
492
+ const protoVerificationMethod = didDocument.verificationMethod.map((vm) => {
493
+ switch (vm?.type) {
494
+ case VerificationMethods.Ed255192020:
495
+ if (!vm?.publicKeyMultibase)
496
+ throw new Error('publicKeyMultibase is required');
497
+ return VerificationMethod.fromPartial({
498
+ id: vm.id,
499
+ controller: vm.controller,
500
+ verificationMethodType: VerificationMethods.Ed255192020,
501
+ verificationMaterial: vm.publicKeyMultibase,
502
+ });
503
+ case VerificationMethods.JWK:
504
+ if (!vm?.publicKeyJwk)
505
+ throw new Error('publicKeyJwk is required');
506
+ return VerificationMethod.fromPartial({
507
+ id: vm.id,
508
+ controller: vm.controller,
509
+ verificationMethodType: VerificationMethods.JWK,
510
+ verificationMaterial: JSON.stringify(vm.publicKeyJwk),
511
+ });
512
+ case VerificationMethods.Ed255192018:
513
+ if (!vm?.publicKeyBase58)
514
+ throw new Error('publicKeyBase58 is required');
515
+ return VerificationMethod.fromPartial({
516
+ id: vm.id,
517
+ controller: vm.controller,
518
+ verificationMethodType: VerificationMethods.Ed255192018,
519
+ verificationMaterial: vm.publicKeyBase58,
520
+ });
521
+ default:
522
+ throw new Error('Unsupported verificationMethod type');
523
+ }
524
+ });
525
+ const protoService = normalizeService(didDocument);
526
+ return {
527
+ valid: true,
528
+ protobufVerificationMethod: protoVerificationMethod,
529
+ protobufService: protoService,
530
+ };
531
+ }
532
+ /**
533
+ * Converts a protobuf DID document to a specification-compliant DID document format.
534
+ * Handles context inclusion, verification method formatting, and service denormalization.
535
+ *
536
+ * @param protobufDidDocument - Protobuf DID document to convert
537
+ * @returns Promise resolving to a spec-compliant DID document
538
+ */
539
+ static async toSpecCompliantPayload(protobufDidDocument) {
540
+ const verificationMethod = protobufDidDocument.verificationMethod.map((vm) => {
541
+ switch (vm.verificationMethodType) {
542
+ case VerificationMethods.Ed255192020:
543
+ if (!protobufDidDocument.context.includes(contexts.W3CSuiteEd255192020))
544
+ protobufDidDocument.context = [...protobufDidDocument.context, contexts.W3CSuiteEd255192020];
545
+ return {
546
+ id: vm.id,
547
+ type: vm.verificationMethodType,
548
+ controller: vm.controller,
549
+ publicKeyMultibase: vm.verificationMaterial,
550
+ };
551
+ case VerificationMethods.JWK:
552
+ if (!protobufDidDocument.context.includes(contexts.W3CSuiteJws2020))
553
+ protobufDidDocument.context = [...protobufDidDocument.context, contexts.W3CSuiteJws2020];
554
+ return {
555
+ id: vm.id,
556
+ type: vm.verificationMethodType,
557
+ controller: vm.controller,
558
+ publicKeyJwk: JSON.parse(vm.verificationMaterial),
559
+ };
560
+ case VerificationMethods.Ed255192018:
561
+ if (!protobufDidDocument.context.includes(contexts.W3CSuiteEd255192018))
562
+ protobufDidDocument.context = [...protobufDidDocument.context, contexts.W3CSuiteEd255192018];
563
+ return {
564
+ id: vm.id,
565
+ type: vm.verificationMethodType,
566
+ controller: vm.controller,
567
+ publicKeyBase58: vm.verificationMaterial,
568
+ };
569
+ default:
570
+ throw new Error('Unsupported verificationMethod type'); // should never happen
571
+ }
572
+ });
573
+ const service = denormalizeService(protobufDidDocument);
574
+ const context = (function () {
575
+ if (protobufDidDocument.context.includes(contexts.W3CDIDv1))
576
+ return protobufDidDocument.context;
577
+ return [contexts.W3CDIDv1, ...protobufDidDocument.context];
578
+ })();
579
+ const assertionMethod = protobufDidDocument.assertionMethod.map((am) => {
580
+ try {
581
+ // Check if the assertionMethod is a DID URL
582
+ if (!am.startsWith('did:cheqd:')) {
583
+ // Parse once if it's a stringified JSON
584
+ const parsedAm = JSON.parse(am);
585
+ if (typeof parsedAm === 'string') {
586
+ // Parse again only if necessary
587
+ return JSON.parse(parsedAm);
588
+ }
589
+ return parsedAm;
590
+ }
591
+ return am;
592
+ }
593
+ catch (error) {
594
+ throw new Error(`Unsupported assertionMethod type: ${am}`);
595
+ }
596
+ });
597
+ const specCompliant = {
598
+ '@context': context,
599
+ id: protobufDidDocument.id,
600
+ controller: protobufDidDocument.controller,
601
+ verificationMethod: verificationMethod,
602
+ authentication: protobufDidDocument.authentication,
603
+ assertionMethod: assertionMethod,
604
+ capabilityInvocation: protobufDidDocument.capabilityInvocation,
605
+ capabilityDelegation: protobufDidDocument.capabilityDelegation,
606
+ keyAgreement: protobufDidDocument.keyAgreement,
607
+ service: service,
608
+ alsoKnownAs: protobufDidDocument.alsoKnownAs,
609
+ };
610
+ if (!protobufDidDocument.authentication?.length)
611
+ delete specCompliant.authentication;
612
+ if (!protobufDidDocument.assertionMethod?.length)
613
+ delete specCompliant.assertionMethod;
614
+ if (!protobufDidDocument.capabilityInvocation?.length)
615
+ delete specCompliant.capabilityInvocation;
616
+ if (!protobufDidDocument.capabilityDelegation?.length)
617
+ delete specCompliant.capabilityDelegation;
618
+ if (!protobufDidDocument.keyAgreement?.length)
619
+ delete specCompliant.keyAgreement;
620
+ if (!protobufDidDocument.service?.length)
621
+ delete specCompliant.service;
622
+ if (!protobufDidDocument.alsoKnownAs?.length)
623
+ delete specCompliant.alsoKnownAs;
624
+ return specCompliant;
625
+ }
626
+ /**
627
+ * Converts protobuf metadata to specification-compliant DID document metadata format.
628
+ * Handles date formatting and optional field normalization.
629
+ *
630
+ * @param protobufDidDocument - Protobuf metadata to convert
631
+ * @returns Promise resolving to spec-compliant DID document metadata
632
+ */
633
+ static async toSpecCompliantMetadata(protobufDidDocument) {
634
+ return {
635
+ created: protobufDidDocument.created?.toISOString(),
636
+ updated: protobufDidDocument.updated?.toISOString(),
637
+ deactivated: protobufDidDocument.deactivated,
638
+ versionId: protobufDidDocument.versionId,
639
+ nextVersionId: protobufDidDocument?.nextVersionId,
640
+ previousVersionId: protobufDidDocument?.previousVersionId,
641
+ };
642
+ }
643
+ /**
644
+ * Validates that provided signatures match the authentication requirements in a DID document.
645
+ * Checks signature count, authentication presence, and controller authorization.
646
+ *
647
+ * @param didDocument - DID document containing authentication requirements
648
+ * @param signatures - Array of signatures to validate against authentication
649
+ * @param querier - Optional querier for retrieving external controller documents
650
+ * @param externalControllersDidDocuments - Optional pre-loaded external controller documents
651
+ * @returns Promise resolving to validation result with error details if invalid
652
+ */
653
+ static async validateAuthenticationAgainstSignatures(didDocument, signatures, querier, externalControllersDidDocuments) {
654
+ // validate signatures - case: no signatures
655
+ if (!signatures || !signatures.length)
656
+ return { valid: false, error: 'signatures are required' };
657
+ // validate authentication - case: no authentication when at least one verificationMethod
658
+ if ((!didDocument.authentication || !didDocument.authentication.length) &&
659
+ didDocument.verificationMethod?.length)
660
+ return { valid: false, error: 'authentication is required' };
661
+ const normalizedAuthentication = normalizeAuthentication(didDocument);
662
+ // define unique authentication
663
+ const uniqueAuthentication = new Set(normalizedAuthentication);
664
+ // validate authentication - case: authentication contains duplicates
665
+ if (uniqueAuthentication.size < normalizedAuthentication.length)
666
+ return {
667
+ valid: false,
668
+ error: `authentication contains duplicate key references: duplicate key reference ${Array.from(uniqueAuthentication).find((a) => normalizeAuthentication(didDocument).filter((aa) => aa === a).length > 1)}`,
669
+ };
670
+ // define unique signatures - shallow, only verificationMethodId, no signature
671
+ const uniqueSignatures = new Set(signatures.map((s) => s.verificationMethodId));
672
+ // validate signatures - case: signatures contain duplicates
673
+ if (uniqueSignatures.size < signatures.length)
674
+ return {
675
+ valid: false,
676
+ error: `signatures contain duplicates: duplicate signature for key reference ${Array.from(uniqueSignatures).find((s) => signatures.filter((ss) => ss.verificationMethodId === s).length > 1)}`,
677
+ };
678
+ // validate authentication - case: authentication contains invalid key references
679
+ if (!Array.from(uniqueAuthentication).every((a) => didDocument.verificationMethod?.some((vm) => vm.id === a)))
680
+ return {
681
+ valid: false,
682
+ error: `authentication contains invalid key references: invalid key reference ${Array.from(uniqueAuthentication).find((a) => !didDocument.verificationMethod?.some((vm) => vm.id === a))}`,
683
+ };
684
+ // define whether external controller or not
685
+ const externalController = normalizeController(didDocument).some((c) => c !== didDocument.id);
686
+ // validate authentication - case: authentication matches signatures, unique, if no external controller
687
+ if (!Array.from(uniqueAuthentication).every((a) => uniqueSignatures.has(a)) && !externalController)
688
+ return {
689
+ valid: false,
690
+ error: `authentication does not match signatures: signature from key ${Array.from(uniqueAuthentication).find((a) => !uniqueSignatures.has(a))} is missing`,
691
+ };
692
+ // validate signatures - case: authentication matches signatures, unique, excessive signatures, no external controller
693
+ if (!Array.from(uniqueSignatures).every((s) => uniqueAuthentication.has(s)) && !externalController)
694
+ return {
695
+ valid: false,
696
+ error: `authentication does not match signatures: signature from key ${Array.from(uniqueSignatures).find((s) => !uniqueAuthentication.has(s))} is not required`,
697
+ };
698
+ // return, if no external controller
699
+ if (!externalController)
700
+ return { valid: true };
701
+ // require querier
702
+ if (!querier)
703
+ throw new Error('querier is required for external controller validation');
704
+ // get external controllers
705
+ const externalControllers = normalizeController(didDocument).filter((c) => c !== didDocument.id);
706
+ // get external controllers' documents
707
+ const externalControllersDocuments = await Promise.all(externalControllers?.map(async (c) => {
708
+ // compute index of external controller's document, if provided
709
+ const externalControllerDocumentIndex = externalControllersDidDocuments?.findIndex((d) => d.id === c);
710
+ // get external controller's document, if provided
711
+ if (externalControllerDocumentIndex !== undefined && externalControllerDocumentIndex !== -1)
712
+ return externalControllersDidDocuments?.[externalControllerDocumentIndex];
713
+ // fetch external controller's document
714
+ const protobufDocument = await querier[defaultDidExtensionKey].didDoc(c);
715
+ // throw, if not found
716
+ if (!protobufDocument || !protobufDocument.didDoc)
717
+ throw new Error(`Document for controller ${c} not found`);
718
+ // convert to spec compliant payload
719
+ return await DIDModule.toSpecCompliantPayload(protobufDocument.didDoc);
720
+ }));
721
+ // define unique required signatures
722
+ const uniqueRequiredSignatures = new Set(externalControllersDocuments.concat(didDocument).flatMap((d) => (d ? normalizeAuthentication(d) : [])));
723
+ // validate authentication - case: authentication matches signatures, unique, if external controller
724
+ if (!Array.from(uniqueRequiredSignatures).every((a) => uniqueSignatures.has(a)))
725
+ return {
726
+ valid: false,
727
+ error: `authentication does not match signatures: signature from key ${Array.from(uniqueRequiredSignatures).find((a) => !uniqueSignatures.has(a))} is missing`,
728
+ };
729
+ // validate authentication - case: authentication matches signatures, unique, excessive signatures, if external controller
730
+ if (uniqueRequiredSignatures.size < uniqueSignatures.size)
731
+ return {
732
+ valid: false,
733
+ error: `authentication does not match signatures: signature from key ${Array.from(uniqueSignatures).find((s) => !uniqueRequiredSignatures.has(s))} is not required`,
734
+ };
735
+ // return valid
736
+ return { valid: true };
737
+ }
738
+ /**
739
+ * Validates authentication against signatures for key rotation scenarios.
740
+ * Handles validation during DID document updates where keys may have changed.
741
+ *
742
+ * @param didDocument - Updated DID document to validate
743
+ * @param signatures - Array of signatures to validate
744
+ * @param querier - Querier for retrieving previous DID document and controllers
745
+ * @param previousDidDocument - Optional previous version of the DID document
746
+ * @param externalControllersDidDocuments - Optional pre-loaded external controller documents
747
+ * @returns Promise resolving to validation result with controller documents and previous document
748
+ */
749
+ static async validateAuthenticationAgainstSignaturesKeyRotation(didDocument, signatures, querier, previousDidDocument, externalControllersDidDocuments) {
750
+ // validate signatures - case: no signatures
751
+ if (!signatures || !signatures.length)
752
+ return { valid: false, error: 'signatures are required' };
753
+ // validate authentication - case: no authentication when at least one verificationMethod
754
+ if ((!didDocument.authentication || !didDocument.authentication.length) &&
755
+ didDocument.verificationMethod?.length)
756
+ return { valid: false, error: 'authentication is required' };
757
+ // define unique authentication
758
+ const authentication = normalizeAuthentication(didDocument);
759
+ const uniqueAuthentication = new Set(authentication);
760
+ // validate authentication - case: authentication contains duplicates
761
+ if (uniqueAuthentication.size < authentication.length)
762
+ return {
763
+ valid: false,
764
+ error: `authentication contains duplicate key references: duplicate key reference ${Array.from(uniqueAuthentication).find((a) => normalizeAuthentication(didDocument).filter((aa) => aa === a).length > 1)}`,
765
+ };
766
+ // define unique signatures
767
+ const uniqueSignatures = new Set(signatures.map((s) => s.verificationMethodId));
768
+ // validate authentication - case: authentication contains invalid key references
769
+ if (!Array.from(uniqueAuthentication).every((a) => didDocument.verificationMethod?.some((vm) => vm.id === a)))
770
+ return {
771
+ valid: false,
772
+ error: `authentication contains invalid key references: invalid key reference ${Array.from(uniqueAuthentication).find((a) => !didDocument.verificationMethod?.some((vm) => vm.id === a))}`,
773
+ };
774
+ // lookup previous document
775
+ if (!previousDidDocument) {
776
+ // get previous document
777
+ const previousDocument = await querier[defaultDidExtensionKey].didDoc(didDocument.id);
778
+ // throw, if not found
779
+ if (!previousDocument || !previousDocument.didDoc)
780
+ throw new Error('Previous did document not found');
781
+ previousDidDocument = await DIDModule.toSpecCompliantPayload(previousDocument.didDoc);
782
+ }
783
+ const controllers = normalizeController(didDocument);
784
+ const previousControllers = normalizeController(previousDidDocument);
785
+ // define whether external controller or not
786
+ const externalController = controllers.concat(previousControllers).some((c) => c !== didDocument.id);
787
+ // define whether key rotation or not (same ID, different material)
788
+ const keyRotation = !!didDocument.verificationMethod?.some((vm) => previousDidDocument?.verificationMethod?.some((pvm) => pvm.id === vm.id &&
789
+ (pvm.publicKeyBase58 !== vm.publicKeyBase58 ||
790
+ pvm.publicKeyMultibase !== vm.publicKeyMultibase ||
791
+ pvm.publicKeyJwk?.x !== vm.publicKeyJwk?.x)));
792
+ // define whether key replacement or not (different IDs in authentication)
793
+ const currentAuthenticationIds = new Set(normalizeAuthentication(didDocument));
794
+ const previousAuthenticationIds = new Set(normalizeAuthentication(previousDidDocument));
795
+ const removedKeys = Array.from(previousAuthenticationIds).filter((id) => !currentAuthenticationIds.has(id));
796
+ const addedKeys = Array.from(currentAuthenticationIds).filter((id) => !previousAuthenticationIds.has(id));
797
+ const keyReplacement = removedKeys.length > 0 && addedKeys.length > 0;
798
+ // define controller rotation
799
+ const controllerRotation = !controllers.every((c) => previousControllers.includes(c)) ||
800
+ !previousControllers.every((c) => controllers.includes(c));
801
+ // define rotated controllers
802
+ const rotatedControllers = controllerRotation
803
+ ? previousControllers.filter((c) => !controllers.includes(c))
804
+ : [];
805
+ // define unique union of authentication
806
+ const previousAuthentication = normalizeAuthentication(previousDidDocument);
807
+ const uniqueUnionAuthentication = new Set([...uniqueAuthentication, ...previousAuthentication]);
808
+ // validate authentication - case: authentication matches signatures, unique, if no external controller, no key rotation, no key replacement
809
+ if (!Array.from(uniqueUnionAuthentication).every((a) => uniqueSignatures.has(a)) &&
810
+ !externalController &&
811
+ !keyRotation &&
812
+ !keyReplacement)
813
+ return {
814
+ valid: false,
815
+ error: `authentication does not match signatures: signature from key ${Array.from(uniqueAuthentication).find((a) => !uniqueSignatures.has(a))} is missing`,
816
+ };
817
+ // define rotated keys
818
+ const rotatedKeys = keyRotation
819
+ ? didDocument.verificationMethod?.filter((vm) => previousDidDocument?.verificationMethod?.some((pvm) => pvm.id === vm.id &&
820
+ (pvm.publicKeyBase58 !== vm.publicKeyBase58 ||
821
+ pvm.publicKeyMultibase !== vm.publicKeyMultibase ||
822
+ pvm.publicKeyJwk?.x !== vm.publicKeyJwk?.x)))
823
+ : [];
824
+ // define unique union of signatures required, including key replacement logic
825
+ let uniqueUnionSignaturesRequired = new Set();
826
+ if (keyRotation) {
827
+ // Existing key rotation logic (same ID, different material)
828
+ uniqueUnionSignaturesRequired = new Set([
829
+ ...authentication.filter((a) => rotatedKeys?.find((rk) => a === rk.id)).map((a) => `${a}(document0)`),
830
+ ...previousAuthentication.map((a) => `${a}(document1)`),
831
+ ]);
832
+ }
833
+ else if (keyReplacement) {
834
+ // For key replacement, we need signatures from:
835
+ // 1. The new keys (from current document)
836
+ // 2. The old keys that are being replaced (from previous document)
837
+ const newKeySignatures = addedKeys.map((keyId) => `${keyId}(document0)`);
838
+ const oldKeySignatures = removedKeys
839
+ .filter((keyId) => previousAuthentication.includes(keyId)) // Only if they were in authentication
840
+ .map((keyId) => `${keyId}(document1)`);
841
+ uniqueUnionSignaturesRequired = new Set([...newKeySignatures, ...oldKeySignatures]);
842
+ }
843
+ else {
844
+ // No rotation or replacement
845
+ uniqueUnionSignaturesRequired = new Set([...authentication.map((a) => `${a}(document0)`)]);
846
+ }
847
+ // define frequency of unique union of signatures required
848
+ const uniqueUnionSignaturesRequiredFrequency = new Map([...uniqueUnionSignaturesRequired].map((s) => [s.replace(new RegExp(/\(document\d+\)/), ''), 0]));
849
+ // count frequency of unique union of signatures required
850
+ uniqueUnionSignaturesRequired.forEach((s) => {
851
+ // define key
852
+ const key = s.replace(new RegExp(/\(document\d+\)/), '');
853
+ // increment frequency
854
+ uniqueUnionSignaturesRequiredFrequency.set(key, uniqueUnionSignaturesRequiredFrequency.get(key) + 1);
855
+ });
856
+ // define frequency of signatures provided
857
+ const uniqueSignaturesFrequency = new Map(signatures.map((s) => [s.verificationMethodId, 0]));
858
+ // count frequency of signatures provided
859
+ signatures.forEach((s) => {
860
+ // increment frequency
861
+ uniqueSignaturesFrequency.set(s.verificationMethodId, uniqueSignaturesFrequency.get(s.verificationMethodId) + 1);
862
+ });
863
+ // validate signatures - case: authentication matches signatures, unique, excessive signatures, no external controller
864
+ if (Array.from(uniqueSignaturesFrequency).filter(([k, f]) => uniqueUnionSignaturesRequiredFrequency.get(k) === undefined ||
865
+ (uniqueUnionSignaturesRequiredFrequency.get(k) &&
866
+ uniqueUnionSignaturesRequiredFrequency.get(k) < f)).length &&
867
+ !externalController)
868
+ return {
869
+ valid: false,
870
+ error: `authentication does not match signatures: signature from key ${Array.from(uniqueSignaturesFrequency).find(([k, f]) => uniqueUnionSignaturesRequiredFrequency.get(k) === undefined || uniqueUnionSignaturesRequiredFrequency.get(k) < f)?.[0]} is not required`,
871
+ };
872
+ // validate signatures - case: authentication matches signatures, unique, missing signatures, no external controller
873
+ if (Array.from(uniqueSignaturesFrequency).filter(([k, f]) => uniqueUnionSignaturesRequiredFrequency.get(k) && uniqueUnionSignaturesRequiredFrequency.get(k) > f).length &&
874
+ !externalController)
875
+ return {
876
+ valid: false,
877
+ error: `authentication does not match signatures: signature from key ${Array.from(uniqueSignaturesFrequency).find(([k, f]) => uniqueUnionSignaturesRequiredFrequency.get(k) > f)?.[0]} is missing`,
878
+ };
879
+ // return, if no external controller
880
+ if (!externalController)
881
+ return { valid: true };
882
+ // require querier
883
+ if (!querier)
884
+ throw new Error('querier is required for external controller validation');
885
+ // get external controllers
886
+ // Only include rotated controllers if they are external (not the current DID itself)
887
+ const externalRotatedControllers = rotatedControllers.filter((c) => c !== didDocument.id);
888
+ const externalControllers = controllers?.filter((c) => c !== didDocument.id).concat(externalRotatedControllers);
889
+ // get external controllers' documents
890
+ const externalControllersDocuments = await Promise.all(externalControllers?.map(async (c) => {
891
+ // compute index of external controller's document, if provided
892
+ const externalControllerDocumentIndex = externalControllersDidDocuments?.findIndex((d) => d.id === c);
893
+ // get external controller's document, if provided
894
+ if (externalControllerDocumentIndex !== undefined && externalControllerDocumentIndex !== -1)
895
+ return externalControllersDidDocuments[externalControllerDocumentIndex];
896
+ // fetch external controller's document
897
+ const protobufDocument = await querier[defaultDidExtensionKey].didDoc(c);
898
+ // throw, if not found
899
+ if (!protobufDocument || !protobufDocument.didDoc)
900
+ throw new Error(`Document for controller ${c} not found`);
901
+ // convert to spec compliant payload
902
+ return await DIDModule.toSpecCompliantPayload(protobufDocument.didDoc);
903
+ }));
904
+ // define unique required signatures, delimited, with external controllers
905
+ const uniqueUnionSignaturesRequiredWithExternalControllers = new Set([
906
+ ...uniqueUnionSignaturesRequired,
907
+ ...externalControllersDocuments
908
+ .flatMap((d) => normalizeAuthentication(d))
909
+ .map((a) => `${a}(document${externalControllersDocuments.findIndex((d) => normalizeAuthentication(d).includes(a))})`),
910
+ ]);
911
+ // add rotated controller keys to unique required signatures, if any
912
+ if (controllerRotation) {
913
+ // walk through rotated controllers
914
+ rotatedControllers.forEach((c) => {
915
+ // get rotated controller's document index
916
+ const rotatedControllerDocumentIndex = externalControllersDocuments.findIndex((d) => d?.id === c);
917
+ // early return, if no document
918
+ if (rotatedControllerDocumentIndex === -1)
919
+ return;
920
+ // get rotated controller's document
921
+ const rotatedControllerDocument = externalControllersDocuments[rotatedControllerDocumentIndex];
922
+ // add rotated controller's authentication to unique required signatures
923
+ rotatedControllerDocument.authentication?.forEach((a) => uniqueUnionSignaturesRequiredWithExternalControllers.add(`${a}(document${rotatedControllerDocumentIndex})`));
924
+ });
925
+ }
926
+ // define frequency of unique union of signatures required, with external controllers
927
+ const uniqueUnionSignaturesRequiredWithExternalControllersFrequency = new Map([...uniqueUnionSignaturesRequiredWithExternalControllers].map((s) => [
928
+ s.replace(new RegExp(/\(document\d+\)/), ''),
929
+ 0,
930
+ ]));
931
+ // count frequency of unique union of signatures required, with external controllers
932
+ uniqueUnionSignaturesRequiredWithExternalControllers.forEach((s) => {
933
+ // define key
934
+ const key = s.replace(new RegExp(/\(document\d+\)/), '');
935
+ // increment frequency
936
+ uniqueUnionSignaturesRequiredWithExternalControllersFrequency.set(key, uniqueUnionSignaturesRequiredWithExternalControllersFrequency.get(key) + 1);
937
+ });
938
+ // define frequency of signatures provided, with external controllers
939
+ const uniqueSignaturesFrequencyWithExternalControllers = new Map(signatures.map((s) => [s.verificationMethodId, 0]));
940
+ // count frequency of signatures provided, with external controllers
941
+ signatures.forEach((s) => {
942
+ // increment frequency
943
+ uniqueSignaturesFrequencyWithExternalControllers.set(s.verificationMethodId, uniqueSignaturesFrequencyWithExternalControllers.get(s.verificationMethodId) + 1);
944
+ });
945
+ // validate signatures - case: authentication matches signatures, unique, excessive signatures, with external controllers
946
+ if (Array.from(uniqueSignaturesFrequencyWithExternalControllers).filter(([k, f]) => uniqueUnionSignaturesRequiredWithExternalControllersFrequency.get(k) === undefined ||
947
+ (uniqueUnionSignaturesRequiredWithExternalControllersFrequency.get(k) &&
948
+ uniqueUnionSignaturesRequiredWithExternalControllersFrequency.get(k) < f)).length &&
949
+ externalController)
950
+ return {
951
+ valid: false,
952
+ error: `authentication does not match signatures: signature from key ${Array.from(uniqueSignaturesFrequencyWithExternalControllers).find(([k, f]) => uniqueUnionSignaturesRequiredWithExternalControllersFrequency.get(k) === undefined || uniqueUnionSignaturesRequiredWithExternalControllersFrequency.get(k) < f)?.[0]} is not required`,
953
+ };
954
+ // validate signatures - case: authentication matches signatures, unique, missing signatures, with external controllers
955
+ if (Array.from(uniqueSignaturesFrequencyWithExternalControllers).filter(([k, f]) => uniqueUnionSignaturesRequiredWithExternalControllersFrequency.get(k) &&
956
+ uniqueUnionSignaturesRequiredWithExternalControllersFrequency.get(k) > f).length &&
957
+ externalController)
958
+ return {
959
+ valid: false,
960
+ error: `authentication does not match signatures: signature from key ${Array.from(uniqueSignaturesFrequencyWithExternalControllers).find(([k, f]) => uniqueUnionSignaturesRequiredWithExternalControllersFrequency.get(k) > f)?.[0]} is missing`,
961
+ };
962
+ // return valid
963
+ return { valid: true, previousDidDocument, externalControllersDocuments };
964
+ }
965
+ /**
966
+ * Generates standard fees for creating a DID document.
967
+ *
968
+ * @param feePayer - Address of the account that will pay the transaction fees
969
+ * @param granter - Optional address of the account granting fee payment permissions
970
+ * @returns Promise resolving to the fee configuration for DID document creation
971
+ */
972
+ static async generateCreateDidDocFees(feePayer, granter) {
973
+ return {
974
+ amount: [DIDModule.fees.DefaultCreateDidDocFee],
975
+ gas: '360000',
976
+ payer: feePayer,
977
+ granter: granter,
978
+ };
979
+ }
980
+ /**
981
+ * Generates fee configuration for DID document update transactions.
982
+ * Uses default update fees and gas requirements.
983
+ *
984
+ * @param feePayer - Address of the account that will pay the transaction fees
985
+ * @param granter - Optional address of the account granting fee payment permissions
986
+ * @returns Promise resolving to the fee configuration for DID document updates
987
+ */
988
+ static async generateUpdateDidDocFees(feePayer, granter) {
989
+ return {
990
+ amount: [DIDModule.fees.DefaultUpdateDidDocFee],
991
+ gas: '360000',
992
+ payer: feePayer,
993
+ granter: granter,
994
+ };
995
+ }
996
+ /**
997
+ * Generates fee configuration for DID document deactivation transactions.
998
+ * Uses default deactivation fees and gas requirements.
999
+ *
1000
+ * @param feePayer - Address of the account that will pay the transaction fees
1001
+ * @param granter - Optional address of the account granting fee payment permissions
1002
+ * @returns Promise resolving to the fee configuration for DID document deactivation
1003
+ */
1004
+ static async generateDeactivateDidDocFees(feePayer, granter) {
1005
+ return {
1006
+ amount: [DIDModule.fees.DefaultDeactivateDidDocFee],
1007
+ gas: '360000',
1008
+ payer: feePayer,
1009
+ granter: granter,
1010
+ };
1011
+ }
1012
+ }
1013
+ //# sourceMappingURL=did.js.map