@did-btcr2/method 0.20.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +223 -1
  2. package/dist/browser.js +2566 -3507
  3. package/dist/browser.mjs +2566 -3507
  4. package/dist/cjs/core/beacon/aggregation/cohort/index.js +13 -2
  5. package/dist/cjs/core/beacon/aggregation/cohort/index.js.map +1 -1
  6. package/dist/cjs/core/beacon/aggregation/cohort/messages/base.js +7 -2
  7. package/dist/cjs/core/beacon/aggregation/cohort/messages/base.js.map +1 -1
  8. package/dist/cjs/core/beacon/aggregation/communication/adapter/did-comm.js +5 -10
  9. package/dist/cjs/core/beacon/aggregation/communication/adapter/did-comm.js.map +1 -1
  10. package/dist/cjs/core/beacon/aggregation/communication/adapter/nostr.js +4 -7
  11. package/dist/cjs/core/beacon/aggregation/communication/adapter/nostr.js.map +1 -1
  12. package/dist/cjs/core/beacon/aggregation/session/index.js +15 -3
  13. package/dist/cjs/core/beacon/aggregation/session/index.js.map +1 -1
  14. package/dist/cjs/core/beacon/cas-beacon.js +1 -1
  15. package/dist/cjs/core/beacon/cas-beacon.js.map +1 -1
  16. package/dist/cjs/core/beacon/signal-discovery.js +6 -6
  17. package/dist/cjs/core/beacon/signal-discovery.js.map +1 -1
  18. package/dist/cjs/core/beacon/singleton.js +18 -20
  19. package/dist/cjs/core/beacon/singleton.js.map +1 -1
  20. package/dist/cjs/core/beacon/smt-beacon.js +1 -1
  21. package/dist/cjs/core/beacon/smt-beacon.js.map +1 -1
  22. package/dist/cjs/core/identifier.js +11 -13
  23. package/dist/cjs/core/identifier.js.map +1 -1
  24. package/dist/cjs/core/resolve.js +52 -49
  25. package/dist/cjs/core/resolve.js.map +1 -1
  26. package/dist/cjs/core/update.js +3 -4
  27. package/dist/cjs/core/update.js.map +1 -1
  28. package/dist/cjs/did-btcr2.js +36 -35
  29. package/dist/cjs/did-btcr2.js.map +1 -1
  30. package/dist/cjs/utils/did-document-builder.js +0 -6
  31. package/dist/cjs/utils/did-document-builder.js.map +1 -1
  32. package/dist/cjs/utils/did-document.js +44 -26
  33. package/dist/cjs/utils/did-document.js.map +1 -1
  34. package/dist/esm/core/beacon/aggregation/cohort/index.js +13 -2
  35. package/dist/esm/core/beacon/aggregation/cohort/index.js.map +1 -1
  36. package/dist/esm/core/beacon/aggregation/cohort/messages/base.js +7 -2
  37. package/dist/esm/core/beacon/aggregation/cohort/messages/base.js.map +1 -1
  38. package/dist/esm/core/beacon/aggregation/communication/adapter/did-comm.js +5 -10
  39. package/dist/esm/core/beacon/aggregation/communication/adapter/did-comm.js.map +1 -1
  40. package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js +4 -7
  41. package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js.map +1 -1
  42. package/dist/esm/core/beacon/aggregation/session/index.js +15 -3
  43. package/dist/esm/core/beacon/aggregation/session/index.js.map +1 -1
  44. package/dist/esm/core/beacon/cas-beacon.js +1 -1
  45. package/dist/esm/core/beacon/cas-beacon.js.map +1 -1
  46. package/dist/esm/core/beacon/signal-discovery.js +6 -6
  47. package/dist/esm/core/beacon/signal-discovery.js.map +1 -1
  48. package/dist/esm/core/beacon/singleton.js +18 -20
  49. package/dist/esm/core/beacon/singleton.js.map +1 -1
  50. package/dist/esm/core/beacon/smt-beacon.js +1 -1
  51. package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
  52. package/dist/esm/core/identifier.js +11 -13
  53. package/dist/esm/core/identifier.js.map +1 -1
  54. package/dist/esm/core/resolve.js +52 -49
  55. package/dist/esm/core/resolve.js.map +1 -1
  56. package/dist/esm/core/update.js +3 -4
  57. package/dist/esm/core/update.js.map +1 -1
  58. package/dist/esm/did-btcr2.js +36 -35
  59. package/dist/esm/did-btcr2.js.map +1 -1
  60. package/dist/esm/utils/did-document-builder.js +0 -6
  61. package/dist/esm/utils/did-document-builder.js.map +1 -1
  62. package/dist/esm/utils/did-document.js +44 -26
  63. package/dist/esm/utils/did-document.js.map +1 -1
  64. package/dist/types/core/beacon/aggregation/cohort/index.d.ts +1 -1
  65. package/dist/types/core/beacon/aggregation/cohort/index.d.ts.map +1 -1
  66. package/dist/types/core/beacon/aggregation/cohort/messages/base.d.ts +1 -1
  67. package/dist/types/core/beacon/aggregation/cohort/messages/base.d.ts.map +1 -1
  68. package/dist/types/core/beacon/aggregation/communication/adapter/did-comm.d.ts.map +1 -1
  69. package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts.map +1 -1
  70. package/dist/types/core/beacon/aggregation/session/index.d.ts +1 -1
  71. package/dist/types/core/beacon/aggregation/session/index.d.ts.map +1 -1
  72. package/dist/types/core/beacon/beacon.d.ts +3 -3
  73. package/dist/types/core/beacon/beacon.d.ts.map +1 -1
  74. package/dist/types/core/beacon/cas-beacon.d.ts +3 -3
  75. package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -1
  76. package/dist/types/core/beacon/signal-discovery.d.ts +5 -5
  77. package/dist/types/core/beacon/signal-discovery.d.ts.map +1 -1
  78. package/dist/types/core/beacon/singleton.d.ts +4 -4
  79. package/dist/types/core/beacon/singleton.d.ts.map +1 -1
  80. package/dist/types/core/beacon/smt-beacon.d.ts +3 -3
  81. package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -1
  82. package/dist/types/core/identifier.d.ts +17 -21
  83. package/dist/types/core/identifier.d.ts.map +1 -1
  84. package/dist/types/core/interfaces.d.ts +2 -2
  85. package/dist/types/core/interfaces.d.ts.map +1 -1
  86. package/dist/types/core/resolve.d.ts +10 -7
  87. package/dist/types/core/resolve.d.ts.map +1 -1
  88. package/dist/types/core/update.d.ts +2 -2
  89. package/dist/types/core/update.d.ts.map +1 -1
  90. package/dist/types/did-btcr2.d.ts +12 -8
  91. package/dist/types/did-btcr2.d.ts.map +1 -1
  92. package/dist/types/utils/did-document-builder.d.ts +0 -1
  93. package/dist/types/utils/did-document-builder.d.ts.map +1 -1
  94. package/dist/types/utils/did-document.d.ts +14 -9
  95. package/dist/types/utils/did-document.d.ts.map +1 -1
  96. package/package.json +8 -8
  97. package/src/core/beacon/aggregation/cohort/index.ts +13 -2
  98. package/src/core/beacon/aggregation/cohort/messages/base.ts +7 -2
  99. package/src/core/beacon/aggregation/communication/adapter/did-comm.ts +5 -12
  100. package/src/core/beacon/aggregation/communication/adapter/nostr.ts +5 -8
  101. package/src/core/beacon/aggregation/session/index.ts +15 -3
  102. package/src/core/beacon/beacon.ts +3 -3
  103. package/src/core/beacon/cas-beacon.ts +3 -3
  104. package/src/core/beacon/signal-discovery.ts +9 -9
  105. package/src/core/beacon/singleton.ts +21 -23
  106. package/src/core/beacon/smt-beacon.ts +3 -3
  107. package/src/core/identifier.ts +31 -28
  108. package/src/core/interfaces.ts +2 -2
  109. package/src/core/resolve.ts +73 -62
  110. package/src/core/update.ts +5 -5
  111. package/src/did-btcr2.ts +47 -43
  112. package/src/utils/did-document-builder.ts +0 -7
  113. package/src/utils/did-document.ts +54 -31
@@ -1,8 +1,9 @@
1
1
  import {
2
- BitcoinNetworkConnection,
2
+ BitcoinConnection,
3
3
  getNetwork
4
4
  } from '@did-btcr2/bitcoin';
5
5
  import {
6
+ Canonicalization,
6
7
  DateUtils,
7
8
  IdentifierHrp,
8
9
  INVALID_DID,
@@ -23,7 +24,7 @@ import {
23
24
  } from '@did-btcr2/cryptosuite';
24
25
  import { CompressedSecp256k1PublicKey } from '@did-btcr2/keypair';
25
26
  import { bytesToHex } from '@noble/hashes/utils';
26
- import { canonicalization, DidBtcr2 } from '../did-btcr2.js';
27
+ import { DidBtcr2 } from '../did-btcr2.js';
27
28
  import { Appendix } from '../utils/appendix.js';
28
29
  import { DidDocument, ID_PLACEHOLDER_VALUE } from '../utils/did-document.js';
29
30
  import { BeaconFactory } from './beacon/factory.js';
@@ -38,10 +39,13 @@ import { CASAnnouncement, Sidecar, SidecarData } from './types.js';
38
39
  * The response object for DID Resolution.
39
40
  */
40
41
  export interface DidResolutionResponse {
41
- currentDocument: DidDocument;
42
- confirmations: number;
43
- versionId: string;
44
- updated: string;
42
+ didDocument: DidDocument;
43
+ metadata: {
44
+ confirmations?: number;
45
+ versionId: string;
46
+ updated?: string;
47
+ deactivated?: boolean;
48
+ }
45
49
  }
46
50
 
47
51
  /**
@@ -60,12 +64,12 @@ export class Resolve {
60
64
  * @returns {DidDocument} The resolved DID Document object.
61
65
  */
62
66
  static deterministic(didComponents: DidComponents): DidDocument {
63
- // Encode the did from the didComponents
64
- const did = Identifier.encode(didComponents);
65
-
66
67
  // Deconstruct the bytes from the given components
67
68
  const { genesisBytes } = didComponents;
68
69
 
70
+ // Encode the did from the didComponents
71
+ const did = Identifier.encode(genesisBytes, didComponents);
72
+
69
73
  // Construct a new CompressedSecp256k1PublicKey and deconstruct the publicKey and publicKeyMultibase
70
74
  const { multibase: publicKeyMultibase } = new CompressedSecp256k1PublicKey(genesisBytes);
71
75
 
@@ -79,7 +83,6 @@ export class Resolve {
79
83
 
80
84
  return new DidDocument({
81
85
  id : did,
82
- controller : [did],
83
86
  verificationMethod : [{
84
87
  id : `${did}#initialKey`,
85
88
  type : 'Multikey',
@@ -102,21 +105,20 @@ export class Resolve {
102
105
  genesisDocument: object,
103
106
  ): Promise<DidDocument> {
104
107
  // Canonicalize and sha256 hash the currentDocument
105
- const hashBytes = canonicalization.process(genesisDocument, { encoding: 'hex' });
108
+ const hashBytes = Canonicalization.process(genesisDocument, { encoding: 'hex' });
106
109
 
107
- // Compare the genesisBytes to the hashBytes
108
- const genesisBytes = bytesToHex(didComponents.genesisBytes);
110
+ const { genesisBytes } = didComponents;
109
111
 
110
112
  // If the genesisBytes do not match the hashBytes, throw an error
111
- if (genesisBytes !== hashBytes) {
113
+ if (bytesToHex(genesisBytes) !== hashBytes) {
112
114
  throw new ResolveError(
113
- `Initial document mismatch: genesisBytes ${genesisBytes} !== hashBytes ${hashBytes}`,
115
+ `Initial document mismatch: genesisBytes ${bytesToHex(genesisBytes)} !== hashBytes ${hashBytes}`,
114
116
  INVALID_DID_DOCUMENT, { genesisBytes, hashBytes }
115
117
  );
116
118
  }
117
119
 
118
120
  // Encode the did from the didComponents
119
- const did = Identifier.encode(didComponents);
121
+ const did = Identifier.encode(genesisBytes, didComponents);
120
122
 
121
123
  // Replace the placeholder did with the did throughout the currentDocument.
122
124
  const currentDocument = JSON.parse(
@@ -137,14 +139,14 @@ export class Resolve {
137
139
  const updateMap = new Map<string, SignedBTCR2Update>();
138
140
  if(sidecar.updates?.length)
139
141
  for(const update of sidecar.updates) {
140
- updateMap.set(canonicalization.process(update, { encoding: 'hex' }), update);
142
+ updateMap.set(Canonicalization.process(update, { encoding: 'hex' }), update);
141
143
  }
142
144
 
143
145
  // CAS Announcements map
144
146
  const casMap = new Map<string, CASAnnouncement>();
145
147
  if(sidecar.casUpdates?.length)
146
148
  for(const update of sidecar.casUpdates) {
147
- casMap.set(canonicalization.process(update, { encoding: 'hex' }), update);
149
+ casMap.set(Canonicalization.process(update, { encoding: 'hex' }), update);
148
150
  }
149
151
 
150
152
  // SMT Proofs map
@@ -206,30 +208,32 @@ export class Resolve {
206
208
  * Signal Bytes (last output in OP_RETURN transaction).
207
209
  * @param {Array<BeaconService>} beaconServices The array of BeaconService objects to search for signals.
208
210
  * @param {SidecarData} sidecarData The sidecar data containing maps of updates, CAS announcements, and SMT proofs.
209
- * @param {BitcoinNetworkConnection} bitcoin The bitcoin network connection used to fetch beacon signals
211
+ * @param {BitcoinConnection} bitcoin The bitcoin network connection used to fetch beacon signals
210
212
  * @returns {Promise<Array<[SignedBTCR2Update, BlockMetadata]>>} The array of BTCR2 Signed Updates announced by the Beacon Signals.
211
213
  */
212
214
  static async beaconSignals(
213
215
  beaconServices: Array<BeaconService>,
214
216
  sidecarData: SidecarData,
215
- bitcoin: BitcoinNetworkConnection
217
+ bitcoin: BitcoinConnection
216
218
  ): Promise<Array<[SignedBTCR2Update, BlockMetadata]>> {
217
219
  // Discover Beacon Signals via indexer server (esplora/electrs) or full node
218
- const beaconServicesSignals = bitcoin.network.rest
220
+ const beaconServicesSignals = bitcoin.rest
219
221
  ? await BeaconSignalDiscovery.indexer(beaconServices, bitcoin)
220
222
  : await BeaconSignalDiscovery.fullnode(beaconServices, bitcoin);
221
223
 
222
224
  // Process each beacon's signals in parallel
223
- const promises = Array.from(beaconServicesSignals.entries()).map(
224
- async ([service, signals]) => {
225
- // Skip beacons with no signals
226
- if (!signals.length) return [];
227
- // Establish a typed beacon and process its signals
228
- return BeaconFactory.establish(service).processSignals(signals, sidecarData);
229
- }
225
+ const promises = await Promise.all(
226
+ Array.from(beaconServicesSignals.entries()).map(
227
+ async ([service, signals]) => {
228
+ // Skip beacons with no signals
229
+ if (!signals.length) return [];
230
+ // Establish a typed beacon and process its signals
231
+ return BeaconFactory.establish(service).processSignals(signals, sidecarData);
232
+ }
233
+ )
230
234
  );
231
235
 
232
- return (await Promise.all(promises)).flat();
236
+ return promises.flat();
233
237
  }
234
238
 
235
239
  /**
@@ -258,31 +262,36 @@ export class Resolve {
258
262
  );
259
263
 
260
264
  // Create a default response object
261
- const response = {
262
- currentDocument,
263
- versionId : `${currentVersionId}`,
264
- confirmations : 0,
265
- updated : ''
265
+ const response: DidResolutionResponse = {
266
+ didDocument : currentDocument,
267
+ metadata : {
268
+ versionId : `${currentVersionId}`,
269
+ confirmations : 0,
270
+ updated : '',
271
+ deactivated : currentDocument.deactivated || false
272
+ }
266
273
  };
267
274
 
268
275
  // Iterate over each (update block) pair
269
276
  for(const [update, block] of updates) {
270
277
  // Get the hash of the current document
271
- const currentDocumentHash = canonicalization.process(response.currentDocument, { encoding: 'base58' });
278
+ const currentDocumentHash = Canonicalization.process(response.didDocument, { encoding: 'base58btc' });
272
279
 
273
- // Set confirmations to the block confirmations
274
- response.confirmations = block.confirmations;
280
+ // Safely convert block.time to timestamp
281
+ const blocktime = DateUtils.blocktimeToTimestamp(block.time);
275
282
 
276
- // Safely convert versionTime to timestamp
277
- const vTime = DateUtils.dateStringToTimestamp(versionTime || '');
278
- // Safely convert block.blocktime to timestamp
279
- const bTime = DateUtils.blocktimeToTimestamp(block.time);
280
283
  // Set the updated field to the blocktime of the current update
281
- response.updated = DateUtils.toISOStringNonFractional(bTime);
284
+ response.metadata.updated = DateUtils.toISOStringNonFractional(blocktime);
285
+
286
+ // Set confirmations to the block confirmations
287
+ response.metadata.confirmations = block.confirmations;
282
288
 
283
289
  // if resolutionOptions.versionTime is defined and the blocktime is more recent, return currentDocument
284
- if(vTime < bTime) {
285
- return response;
290
+ if(versionTime) {
291
+ // Safely convert versionTime to timestamp
292
+ if(blocktime > DateUtils.dateStringToTimestamp(versionTime)) {
293
+ return response;
294
+ }
286
295
  }
287
296
 
288
297
  // Check update.targetVersionId against currentVersionId
@@ -294,23 +303,21 @@ export class Resolve {
294
303
 
295
304
  // If update.targetVersionId == currentVersionId + 1, apply the update
296
305
  else if (update.targetVersionId === currentVersionId + 1) {
297
- // Prepend `z` to the sourceHash if it does not start with it
298
- const sourceHash = update.sourceHash.startsWith('z') ? update.sourceHash : `z${update.sourceHash}`;
299
-
300
306
  // Check if update.sourceHash !== currentDocumentHash
301
- if (sourceHash !== currentDocumentHash) {
307
+ if (update.sourceHash !== currentDocumentHash) {
302
308
  // Raise an INVALID_DID_UPDATE error if they do not match
303
309
  throw new ResolveError(
304
310
  `Hash mismatch: update.sourceHash !== currentDocumentHash`,
305
- INVALID_DID_UPDATE, { sourceHash, currentDocumentHash }
311
+ INVALID_DID_UPDATE, { sourceHash: update.sourceHash, currentDocumentHash }
306
312
  );
307
313
  }
308
314
  // Apply the update to the currentDocument and set it in the response
309
- response.currentDocument = await this.applyUpdate(response.currentDocument, update);
315
+ response.didDocument = await this.applyUpdate(response.didDocument, update);
316
+
310
317
  // Create unsigned_update by removing the proof property from update.
311
318
  const unsignedUpdate = JSONUtils.deleteKeys(update, ['proof']) as UnsignedBTCR2Update;
312
319
  // Push the canonicalized unsigned update hash to the updateHashHistory
313
- updateHashHistory.push(canonicalization.process(unsignedUpdate, { encoding: 'base58' }));
320
+ updateHashHistory.push(Canonicalization.process(unsignedUpdate, { encoding: 'base58btc' }));
314
321
  }
315
322
 
316
323
  // If update.targetVersionId > currentVersionId + 1, throw LATE_PUBLISHING error
@@ -319,15 +326,16 @@ export class Resolve {
319
326
  `Version Id Mismatch: targetVersionId cannot be > currentVersionId + 1`,
320
327
  'LATE_PUBLISHING_ERROR', {
321
328
  targetVersionId : update.targetVersionId,
322
- currentVersionId : String(currentVersionId + 1)
329
+ currentVersionId : currentVersionId + 1
323
330
  }
324
331
  );
325
332
  }
326
333
 
327
334
  // Increment currentVersionId
328
335
  currentVersionId++;
329
- // Set currentVersionId in response
330
- response.versionId = `${currentVersionId}`;
336
+
337
+ // Set response.versionId to be the new currentVersionId
338
+ response.metadata.versionId = `${currentVersionId}`;
331
339
 
332
340
  // If resolutionOptions.versionId is defined and <= currentVersionId, return currentDocument
333
341
  if(currentVersionId >= Number(versionId)) {
@@ -336,6 +344,9 @@ export class Resolve {
336
344
 
337
345
  // Check if the current document is deactivated before further processing
338
346
  if(currentDocument.deactivated) {
347
+ // Set the response deactivated flag to true
348
+ response.metadata.deactivated = currentDocument.deactivated;
349
+ // If deactivated, stop processing further updates and return the response
339
350
  return response;
340
351
  }
341
352
  }
@@ -352,12 +363,12 @@ export class Resolve {
352
363
  */
353
364
  static confirmDuplicate(update: SignedBTCR2Update, updateHashHistory: string[]): void {
354
365
  // Create unsigned_update by removing the proof property from update.
355
- const unsignedUpdate = JSONUtils.deleteKeys(update, ['proof']) as UnsignedBTCR2Update;
366
+ const { proof: _, ...unsignedUpdate } = update;
356
367
 
357
368
  // Hash unsignedUpdate with JSON Document Hashing algorithm
358
- const unsignedUpdateHash = canonicalization.process(unsignedUpdate);
369
+ const unsignedUpdateHash = Canonicalization.process(unsignedUpdate);
359
370
 
360
- // 5. Let historicalUpdateHash equal updateHashHistory[updateHashIndex].
371
+ // Let historicalUpdateHash equal updateHashHistory[updateHashIndex].
361
372
  const historicalUpdateHash = updateHashHistory[update.targetVersionId - 2];
362
373
 
363
374
  // Check if the updateHash matches the historical hash
@@ -420,7 +431,7 @@ export class Resolve {
420
431
  const cryptosuite = new BIP340Cryptosuite(multikey);
421
432
 
422
433
  // Canonicalize the update
423
- const canonicalUpdate = canonicalization.canonicalize(update);
434
+ const canonicalUpdate = Canonicalization.canonicalize(update);
424
435
 
425
436
  // Construct a DataIntegrityProof with the cryptosuite
426
437
  const diProof = new BIP340DataIntegrityProof(cryptosuite);
@@ -443,16 +454,16 @@ export class Resolve {
443
454
  DidDocument.validate(updatedDocument);
444
455
 
445
456
  // Canonicalize and hash the updatedDocument to get the currentDocumentHash.
446
- const currentDocumentHash = canonicalization.process(currentDocument, { encoding: 'base58' });
457
+ const currentDocumentHash = Canonicalization.process(updatedDocument, { encoding: 'base58btc' });
447
458
 
448
459
  // Prepare the update targetHash for comparison with currentDocumentHash.
449
- const updateTargetHash = update.targetHash.startsWith('z') ? update.targetHash : `z${update.targetHash}`;
460
+ const updateTargetHash = update.targetHash;
450
461
 
451
462
  // Make sure the update.targetHash equals currentDocumentHash.
452
- if (updateTargetHash !== currentDocumentHash) {
463
+ if (update.targetHash !== currentDocumentHash) {
453
464
  // If they do not match, throw INVALID_DID_UPDATE error.
454
465
  throw new ResolveError(
455
- `Invalid update: updateTargetHash !== currentDocumentHash`,
466
+ `Invalid update: update.targetHash !== currentDocumentHash`,
456
467
  INVALID_DID_UPDATE, { updateTargetHash, currentDocumentHash }
457
468
  );
458
469
  }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ Canonicalization,
2
3
  INVALID_DID_UPDATE,
3
4
  JSONPatch,
4
5
  KeyBytes,
@@ -11,11 +12,10 @@ import {
11
12
  SignedBTCR2Update,
12
13
  UnsignedBTCR2Update
13
14
  } from '@did-btcr2/cryptosuite';
14
- import { canonicalization } from '../did-btcr2.js';
15
15
  import { Btcr2DidDocument, DidDocument, DidVerificationMethod } from '../utils/did-document.js';
16
16
  import { BeaconFactory } from './beacon/factory.js';
17
17
  import { BeaconService } from './beacon/interfaces.js';
18
- import { BitcoinNetworkConnection } from '@did-btcr2/bitcoin';
18
+ import { BitcoinConnection } from '@did-btcr2/bitcoin';
19
19
 
20
20
  /**
21
21
  * Implements {@link https://dcdpr.github.io/did-btcr2/operations/update.html | 7.3 Update}.
@@ -56,7 +56,7 @@ export class Update {
56
56
  patch : patches,
57
57
  targetHash : '',
58
58
  targetVersionId : sourceVersionId + 1,
59
- sourceHash : canonicalization.process(sourceDocument, { encoding: 'base58' }),
59
+ sourceHash : Canonicalization.process(sourceDocument, { encoding: 'base58btc' }),
60
60
  };
61
61
 
62
62
  // Apply all JSON patches to sourceDocument.
@@ -74,7 +74,7 @@ export class Update {
74
74
  }
75
75
 
76
76
  // Set the targetHash by canonicalizing the targetDocument and encoding it in base58.
77
- unsignedUpdate.targetHash = canonicalization.process(targetDocument, { encoding: 'base58' });
77
+ unsignedUpdate.targetHash = Canonicalization.process(targetDocument, { encoding: 'base58btc' });
78
78
 
79
79
  // Return unsignedUpdate.
80
80
  return unsignedUpdate;
@@ -140,7 +140,7 @@ export class Update {
140
140
  beaconService: BeaconService,
141
141
  update: SignedBTCR2Update,
142
142
  secretKey: KeyBytes,
143
- bitcoin: BitcoinNetworkConnection
143
+ bitcoin: BitcoinConnection
144
144
  ): Promise<SignedBTCR2Update> {
145
145
  // Establish a beacon object
146
146
  const beacon = BeaconFactory.establish(beaconService);
package/src/did-btcr2.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { BitcoinNetworkConnection } from '@did-btcr2/bitcoin';
1
+ import { BitcoinConnection } from '@did-btcr2/bitcoin';
2
2
  import {
3
- Canonicalization,
4
3
  DocumentBytes,
5
4
  HexString,
6
5
  IdentifierHrp,
@@ -9,6 +8,7 @@ import {
9
8
  KeyBytes,
10
9
  METHOD_NOT_SUPPORTED,
11
10
  MethodError,
11
+ MISSING_RESOLUTION_OPTIONS,
12
12
  MISSING_UPDATE_DATA,
13
13
  PatchOperation,
14
14
  ResolveError,
@@ -34,14 +34,11 @@ import { Update } from './core/update.js';
34
34
  import { Appendix } from './utils/appendix.js';
35
35
  import { Btcr2DidDocument, DidVerificationMethod } from './utils/did-document.js';
36
36
 
37
- // TODO: convert to API driver?
38
- export const canonicalization = new Canonicalization();
39
-
40
37
  export type Btcr2Identifier = string;
41
38
 
42
39
  export interface DidCreateOptions {
43
40
  /** Type of identifier to create (key or external) */
44
- idType: 'KEY' | 'EXTERNAL';
41
+ idType: string;
45
42
  /** DID BTCR2 Version Number */
46
43
  version?: number;
47
44
  /** Bitcoin Network */
@@ -81,11 +78,13 @@ export class DidBtcr2 implements DidMethod {
81
78
  * @param {string} options.network The Bitcoin network to use for the identifier, e.g. 'bitcoin', 'testnet', etc. Defaults to 'bitcoin'.
82
79
  * @returns {Promise<Btcr2Identifier>} Promise resolving to a Btcr2Identifier string.
83
80
  * @throws {MethodError} if any of the checks fail
81
+ * @example
82
+ * ```ts
83
+ * const genesisBytes = SchnorrKeyPair.generate().publicKey.compressed;
84
+ * const did = DidBtcr2.create(genesisBytes, { idType: 'KEY', network: 'regtest' });
85
+ * ```
84
86
  */
85
- static async create(
86
- genesisBytes: KeyBytes | DocumentBytes,
87
- options?: DidCreateOptions
88
- ): Promise<Btcr2Identifier> {
87
+ static create(genesisBytes: KeyBytes | DocumentBytes, options?: DidCreateOptions): Btcr2Identifier {
89
88
  // Deconstruct the idType, version and network from the options, setting defaults if not given
90
89
  const { idType, version = 1, network = 'bitcoin' } = options || {};
91
90
 
@@ -97,7 +96,7 @@ export class DidBtcr2 implements DidMethod {
97
96
  }
98
97
 
99
98
  // Call identifier encoding algorithm
100
- return Identifier.encode({ idType, genesisBytes, version, network });
99
+ return Identifier.encode(genesisBytes, { idType, version, network });
101
100
  }
102
101
 
103
102
  /**
@@ -117,24 +116,26 @@ export class DidBtcr2 implements DidMethod {
117
116
  * @example
118
117
  * ```ts
119
118
  * const resolution = await DidBtcr2.resolve(
120
- * 'did:btcr2:k1q0dygyp3gz969tp46dychzy4q78c2k3js68kvyr0shanzg67jnuez2cfplh'
119
+ * 'did:btcr2:k1qgpr45cheptyjekl3cex80xfnkwhxnlclecwwf92gvdjrszm2uwhzlcxu5xte'
121
120
  * )
122
121
  * ```
123
122
  */
124
123
  static async resolve(
125
124
  did: string,
126
- resolutionOptions: ResolutionOptions = { drivers: {} }
125
+ resolutionOptions: ResolutionOptions = {}
127
126
  ): Promise<DidResolutionResult> {
128
127
  try {
128
+ // Set versionId from resolutionOptions
129
+ const versionId = resolutionOptions.versionId;
129
130
 
130
131
  // Initialize an empty DID Resolution Result
131
132
  const didResolutionResult: DidResolutionResult = {
132
133
  '@context' : 'https://w3id.org/did-resolution/v1',
133
134
  didResolutionMetadata : { contentType: 'application/ld+json' },
134
135
  didDocumentMetadata : {
136
+ versionId,
135
137
  deactivated : false,
136
138
  updated : undefined,
137
- versionId : resolutionOptions.versionId,
138
139
  confirmations : undefined,
139
140
  },
140
141
  didDocument : null,
@@ -146,25 +147,16 @@ export class DidBtcr2 implements DidMethod {
146
147
  // Process sidecar if provided
147
148
  const sidecarData = Resolve.sidecarData(resolutionOptions.sidecar);
148
149
 
149
- // Check if bitcoin driver provided
150
- if(!resolutionOptions?.drivers?.bitcoin) {
151
- // If not, initialize default drivers
152
- resolutionOptions.drivers = resolutionOptions.drivers || {};
153
- // Set bitcoin driver to default BitcoinNetworkConnection
154
- resolutionOptions.drivers.bitcoin = new BitcoinNetworkConnection();
155
- // Set the network based on the decoded identifier
156
- resolutionOptions.drivers.bitcoin.setActiveNetwork(didComponents.network);
157
- }
158
-
159
150
  // Parse the genesis document from the resolution options if provided
160
151
  const genesisDocument = resolutionOptions.sidecar?.genesisDocument;
152
+
161
153
  // Since genesisDocument is optional, check if it exists
162
154
  if(!genesisDocument) {
163
155
  // If no genesisDocument and x HRP, throw MISSING_UPDATE_DATA error
164
156
  if(didComponents.hrp === IdentifierHrp.x)
165
157
  throw new ResolveError(
166
158
  'External resolution requires genesisDocument',
167
- MISSING_UPDATE_DATA, { resolutionOptions }
159
+ MISSING_UPDATE_DATA, resolutionOptions
168
160
  );
169
161
  }
170
162
 
@@ -176,23 +168,32 @@ export class DidBtcr2 implements DidMethod {
176
168
  .filter(BeaconUtils.isBeaconService)
177
169
  .map(BeaconUtils.parseBeaconServiceEndpoint);
178
170
 
179
- console.log('beaconServices', beaconServices);
171
+ // Check if bitcoin driver provided
172
+ if(!resolutionOptions?.drivers?.bitcoin) {
173
+ throw new ResolveError(
174
+ 'Bitcoin connection required for resolve. Pass a configured driver via '
175
+ + 'resolutionOptions.drivers.bitcoin or use DidBtcr2Api which injects it automatically.',
176
+ MISSING_RESOLUTION_OPTIONS, resolutionOptions
177
+ );
178
+ }
179
+
180
+ // Get the bitcoin driver from the resolution options
181
+ const bitcoin = resolutionOptions.drivers.bitcoin;
180
182
 
181
183
  // Process the Beacon Signals to get the required updates
182
184
  const unsortedUpdates = await Resolve.beaconSignals(
183
185
  beaconServices,
184
186
  sidecarData,
185
- resolutionOptions.drivers.bitcoin
187
+ bitcoin
186
188
  );
187
- console.log('unsortedUpdates', unsortedUpdates);
188
189
 
189
190
  // If no updates found, return the current document
190
191
  if(!unsortedUpdates.length) {
191
- // Set the current document in the didResolutionResult
192
+ // Set the didDocument in didResolutionResult based on currentDocument
192
193
  didResolutionResult.didDocument = currentDocument;
193
-
194
- // Set the deactivated status in the didDocumentMetadata
194
+ // Set other required fields in the didResolutionResult
195
195
  didResolutionResult.didDocumentMetadata.deactivated = !!currentDocument.deactivated;
196
+ didResolutionResult.didDocumentMetadata.versionId = versionId ?? '1';
196
197
 
197
198
  // Return the didResolutionResult early
198
199
  return didResolutionResult;
@@ -203,21 +204,18 @@ export class DidBtcr2 implements DidMethod {
203
204
  currentDocument,
204
205
  unsortedUpdates,
205
206
  resolutionOptions.versionTime,
206
- resolutionOptions.versionId
207
+ versionId
207
208
  );
208
209
 
209
210
  // Set all of the required fields in the didResolutionResult
210
- didResolutionResult.didDocument = result.currentDocument;
211
- didResolutionResult.didDocumentMetadata.confirmations = result.confirmations;
212
- didResolutionResult.didDocumentMetadata.versionId = result.versionId;
213
- didResolutionResult.didDocumentMetadata.deactivated = !!result.currentDocument.deactivated;
211
+ didResolutionResult.didDocument = result.didDocument;
212
+ didResolutionResult.didDocumentMetadata = result.metadata;
214
213
 
215
214
  // Return didResolutionResult;
216
215
  return didResolutionResult;
217
216
  } catch (error: any) {
218
- console.error(error);
219
217
  // Rethrow any unexpected errors that are not a `ResolveError`.
220
- if (!(error instanceof ResolveError)) throw new Error(error);
218
+ if (!(error instanceof ResolveError)) throw new Error(error.message ?? error, { cause: error });
221
219
 
222
220
  // Return a DID Resolution Result with the appropriate error code.
223
221
  return {
@@ -245,7 +243,7 @@ export class DidBtcr2 implements DidMethod {
245
243
  * @param {string} params.verificationMethodId The verificationMethod ID to sign the update with.
246
244
  * @param {string} params.beaconId The beacon ID associated with the update.
247
245
  * @param {KeyBytes | HexString} [params.signingMaterial] Optional signing material (key bytes or hex string).
248
- * @param {BitcoinNetworkConnection} [params.bitcoin] Optional Bitcoin network connection for announcing the update. If not provided, a default connection will be initialized.
246
+ * @param {BitcoinConnection} [params.bitcoin] Optional Bitcoin network connection for announcing the update. If not provided, a default connection will be initialized.
249
247
  * @return {Promise<SignedBTCR2Update>} Promise resolving to the signed BTCR2 update.
250
248
  * @throws {UpdateError} if no verificationMethod, verificationMethod type is not `Multikey` or the publicKeyMultibase
251
249
  * header is not `zQ3s`
@@ -265,7 +263,7 @@ export class DidBtcr2 implements DidMethod {
265
263
  verificationMethodId: string;
266
264
  beaconId: string;
267
265
  signingMaterial?: KeyBytes | HexString;
268
- bitcoin?: BitcoinNetworkConnection;
266
+ bitcoin?: BitcoinConnection;
269
267
  }): Promise<SignedBTCR2Update> {
270
268
  // TODO: provide KMS as alternative
271
269
  // If no signingMaterial provided, throw an UpdateError with INVALID_DID_UPDATE.
@@ -335,11 +333,17 @@ export class DidBtcr2 implements DidMethod {
335
333
  INVALID_DID_UPDATE, {sourceDocument, beaconId}
336
334
  );
337
335
  }
338
- // If no bitcoin network connection provided, initialize default
339
- bitcoin ??= new BitcoinNetworkConnection();
336
+ // Require an explicit bitcoin connection no silent env-var fallback
337
+ if (!bitcoin) {
338
+ throw new UpdateError(
339
+ 'Bitcoin connection required for update. Pass a configured `bitcoin` parameter '
340
+ + 'or use DidBtcr2Api which injects it automatically.',
341
+ INVALID_DID_UPDATE, { beaconId }
342
+ );
343
+ }
340
344
 
341
345
  // Announce the signed update to the blockchain using the specified beacon(s)
342
- // await Update.announce(beaconService, signed, secretKey, bitcoin);
346
+ await Update.announce(beaconService, signed, secretKey, bitcoin);
343
347
 
344
348
  // Return signed update if announced successfully
345
349
  return signed;
@@ -22,13 +22,6 @@ export class DidDocumentBuilder {
22
22
  }
23
23
  }
24
24
 
25
- withController(controller?: Array<string>): this {
26
- if (controller) {
27
- this.document.controller = controller ?? [this.document.id!];
28
- }
29
- return this;
30
- }
31
-
32
25
  withAuthentication(authentication: Array<string | DidVerificationMethod>): this {
33
26
  if (authentication) {
34
27
  this.document.authentication = authentication;