@originals/sdk 1.8.0 → 1.8.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 (145) hide show
  1. package/dist/utils/hash.js +1 -0
  2. package/package.json +6 -5
  3. package/src/adapters/FeeOracleMock.ts +9 -0
  4. package/src/adapters/index.ts +5 -0
  5. package/src/adapters/providers/OrdHttpProvider.ts +126 -0
  6. package/src/adapters/providers/OrdMockProvider.ts +101 -0
  7. package/src/adapters/types.ts +66 -0
  8. package/src/bitcoin/BitcoinManager.ts +329 -0
  9. package/src/bitcoin/BroadcastClient.ts +54 -0
  10. package/src/bitcoin/OrdinalsClient.ts +120 -0
  11. package/src/bitcoin/PSBTBuilder.ts +106 -0
  12. package/src/bitcoin/fee-calculation.ts +38 -0
  13. package/src/bitcoin/providers/OrdNodeProvider.ts +92 -0
  14. package/src/bitcoin/providers/OrdinalsProvider.ts +56 -0
  15. package/src/bitcoin/providers/types.ts +59 -0
  16. package/src/bitcoin/transactions/commit.ts +465 -0
  17. package/src/bitcoin/transactions/index.ts +13 -0
  18. package/src/bitcoin/transfer.ts +43 -0
  19. package/src/bitcoin/utxo-selection.ts +322 -0
  20. package/src/bitcoin/utxo.ts +113 -0
  21. package/src/cel/ExternalReferenceManager.ts +87 -0
  22. package/src/cel/OriginalsCel.ts +460 -0
  23. package/src/cel/algorithms/createEventLog.ts +68 -0
  24. package/src/cel/algorithms/deactivateEventLog.ts +109 -0
  25. package/src/cel/algorithms/index.ts +11 -0
  26. package/src/cel/algorithms/updateEventLog.ts +99 -0
  27. package/src/cel/algorithms/verifyEventLog.ts +306 -0
  28. package/src/cel/algorithms/witnessEvent.ts +87 -0
  29. package/src/cel/cli/create.ts +330 -0
  30. package/src/cel/cli/index.ts +383 -0
  31. package/src/cel/cli/inspect.ts +549 -0
  32. package/src/cel/cli/migrate.ts +473 -0
  33. package/src/cel/cli/verify.ts +249 -0
  34. package/src/cel/hash.ts +71 -0
  35. package/src/cel/index.ts +16 -0
  36. package/src/cel/layers/BtcoCelManager.ts +408 -0
  37. package/src/cel/layers/PeerCelManager.ts +371 -0
  38. package/src/cel/layers/WebVHCelManager.ts +361 -0
  39. package/src/cel/layers/index.ts +27 -0
  40. package/src/cel/serialization/cbor.ts +189 -0
  41. package/src/cel/serialization/index.ts +10 -0
  42. package/src/cel/serialization/json.ts +209 -0
  43. package/src/cel/types.ts +160 -0
  44. package/src/cel/witnesses/BitcoinWitness.ts +184 -0
  45. package/src/cel/witnesses/HttpWitness.ts +241 -0
  46. package/src/cel/witnesses/WitnessService.ts +51 -0
  47. package/src/cel/witnesses/index.ts +11 -0
  48. package/src/contexts/credentials-v1.json +237 -0
  49. package/src/contexts/credentials-v2-examples.json +5 -0
  50. package/src/contexts/credentials-v2.json +340 -0
  51. package/src/contexts/credentials.json +237 -0
  52. package/src/contexts/data-integrity-v2.json +81 -0
  53. package/src/contexts/dids.json +58 -0
  54. package/src/contexts/ed255192020.json +93 -0
  55. package/src/contexts/ordinals-plus.json +23 -0
  56. package/src/contexts/originals.json +22 -0
  57. package/src/core/OriginalsSDK.ts +420 -0
  58. package/src/crypto/Multikey.ts +194 -0
  59. package/src/crypto/Signer.ts +262 -0
  60. package/src/crypto/noble-init.ts +138 -0
  61. package/src/did/BtcoDidResolver.ts +231 -0
  62. package/src/did/DIDManager.ts +705 -0
  63. package/src/did/Ed25519Verifier.ts +68 -0
  64. package/src/did/KeyManager.ts +239 -0
  65. package/src/did/WebVHManager.ts +499 -0
  66. package/src/did/createBtcoDidDocument.ts +60 -0
  67. package/src/did/providers/OrdinalsClientProviderAdapter.ts +68 -0
  68. package/src/events/EventEmitter.ts +222 -0
  69. package/src/events/index.ts +19 -0
  70. package/src/events/types.ts +331 -0
  71. package/src/examples/basic-usage.ts +78 -0
  72. package/src/examples/create-module-original.ts +435 -0
  73. package/src/examples/full-lifecycle-flow.ts +514 -0
  74. package/src/examples/run.ts +60 -0
  75. package/src/index.ts +204 -0
  76. package/src/kinds/KindRegistry.ts +320 -0
  77. package/src/kinds/index.ts +74 -0
  78. package/src/kinds/types.ts +470 -0
  79. package/src/kinds/validators/AgentValidator.ts +257 -0
  80. package/src/kinds/validators/AppValidator.ts +211 -0
  81. package/src/kinds/validators/DatasetValidator.ts +242 -0
  82. package/src/kinds/validators/DocumentValidator.ts +311 -0
  83. package/src/kinds/validators/MediaValidator.ts +269 -0
  84. package/src/kinds/validators/ModuleValidator.ts +225 -0
  85. package/src/kinds/validators/base.ts +276 -0
  86. package/src/kinds/validators/index.ts +12 -0
  87. package/src/lifecycle/BatchOperations.ts +381 -0
  88. package/src/lifecycle/LifecycleManager.ts +2156 -0
  89. package/src/lifecycle/OriginalsAsset.ts +524 -0
  90. package/src/lifecycle/ProvenanceQuery.ts +280 -0
  91. package/src/lifecycle/ResourceVersioning.ts +163 -0
  92. package/src/migration/MigrationManager.ts +587 -0
  93. package/src/migration/audit/AuditLogger.ts +176 -0
  94. package/src/migration/checkpoint/CheckpointManager.ts +112 -0
  95. package/src/migration/checkpoint/CheckpointStorage.ts +101 -0
  96. package/src/migration/index.ts +33 -0
  97. package/src/migration/operations/BaseMigration.ts +126 -0
  98. package/src/migration/operations/PeerToBtcoMigration.ts +105 -0
  99. package/src/migration/operations/PeerToWebvhMigration.ts +62 -0
  100. package/src/migration/operations/WebvhToBtcoMigration.ts +105 -0
  101. package/src/migration/rollback/RollbackManager.ts +170 -0
  102. package/src/migration/state/StateMachine.ts +92 -0
  103. package/src/migration/state/StateTracker.ts +156 -0
  104. package/src/migration/types.ts +356 -0
  105. package/src/migration/validation/BitcoinValidator.ts +107 -0
  106. package/src/migration/validation/CredentialValidator.ts +62 -0
  107. package/src/migration/validation/DIDCompatibilityValidator.ts +151 -0
  108. package/src/migration/validation/LifecycleValidator.ts +64 -0
  109. package/src/migration/validation/StorageValidator.ts +79 -0
  110. package/src/migration/validation/ValidationPipeline.ts +213 -0
  111. package/src/resources/ResourceManager.ts +655 -0
  112. package/src/resources/index.ts +21 -0
  113. package/src/resources/types.ts +202 -0
  114. package/src/storage/LocalStorageAdapter.ts +64 -0
  115. package/src/storage/MemoryStorageAdapter.ts +29 -0
  116. package/src/storage/StorageAdapter.ts +25 -0
  117. package/src/storage/index.ts +3 -0
  118. package/src/types/bitcoin.ts +98 -0
  119. package/src/types/common.ts +92 -0
  120. package/src/types/credentials.ts +89 -0
  121. package/src/types/did.ts +31 -0
  122. package/src/types/external-shims.d.ts +53 -0
  123. package/src/types/index.ts +7 -0
  124. package/src/types/network.ts +178 -0
  125. package/src/utils/EventLogger.ts +298 -0
  126. package/src/utils/Logger.ts +324 -0
  127. package/src/utils/MetricsCollector.ts +358 -0
  128. package/src/utils/bitcoin-address.ts +132 -0
  129. package/src/utils/cbor.ts +31 -0
  130. package/src/utils/encoding.ts +135 -0
  131. package/src/utils/hash.ts +12 -0
  132. package/src/utils/retry.ts +46 -0
  133. package/src/utils/satoshi-validation.ts +196 -0
  134. package/src/utils/serialization.ts +102 -0
  135. package/src/utils/telemetry.ts +44 -0
  136. package/src/utils/validation.ts +123 -0
  137. package/src/vc/CredentialManager.ts +955 -0
  138. package/src/vc/Issuer.ts +105 -0
  139. package/src/vc/Verifier.ts +54 -0
  140. package/src/vc/cryptosuites/bbs.ts +253 -0
  141. package/src/vc/cryptosuites/bbsSimple.ts +21 -0
  142. package/src/vc/cryptosuites/eddsa.ts +99 -0
  143. package/src/vc/documentLoader.ts +81 -0
  144. package/src/vc/proofs/data-integrity.ts +33 -0
  145. package/src/vc/utils/jsonld.ts +18 -0
@@ -0,0 +1,209 @@
1
+ /**
2
+ * JSON Serialization for CEL Event Logs
3
+ *
4
+ * Provides serialization and parsing of EventLog objects to/from JSON format.
5
+ * Uses deterministic key ordering for consistent hashes.
6
+ */
7
+
8
+ import type { EventLog, LogEntry, DataIntegrityProof, WitnessProof } from '../types';
9
+
10
+ /**
11
+ * Sort object keys recursively for deterministic JSON output.
12
+ * This ensures consistent serialization for hash computations.
13
+ */
14
+ function sortKeys(obj: unknown): unknown {
15
+ if (obj === null || obj === undefined) {
16
+ return obj;
17
+ }
18
+
19
+ if (Array.isArray(obj)) {
20
+ return obj.map(sortKeys);
21
+ }
22
+
23
+ if (typeof obj === 'object') {
24
+ const sorted: Record<string, unknown> = {};
25
+ const keys = Object.keys(obj as Record<string, unknown>).sort();
26
+ for (const key of keys) {
27
+ sorted[key] = sortKeys((obj as Record<string, unknown>)[key]);
28
+ }
29
+ return sorted;
30
+ }
31
+
32
+ return obj;
33
+ }
34
+
35
+ /**
36
+ * Serialize an EventLog to JSON string.
37
+ *
38
+ * Uses deterministic key ordering for consistent output.
39
+ *
40
+ * @param log - The EventLog to serialize
41
+ * @returns JSON string representation of the EventLog
42
+ * @throws Error if log is null or undefined
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const log = await createEventLog(data, options);
47
+ * const json = serializeEventLogJson(log);
48
+ * console.log(json); // '{"events":[...]}'
49
+ * ```
50
+ */
51
+ export function serializeEventLogJson(log: EventLog): string {
52
+ if (!log) {
53
+ throw new Error('Cannot serialize null or undefined EventLog');
54
+ }
55
+
56
+ const sorted = sortKeys(log);
57
+ return JSON.stringify(sorted, null, 2);
58
+ }
59
+
60
+ /**
61
+ * Check if a proof object is a WitnessProof (has witnessedAt field)
62
+ */
63
+ function isWitnessProof(proof: DataIntegrityProof | WitnessProof): proof is WitnessProof {
64
+ return 'witnessedAt' in proof && typeof (proof as WitnessProof).witnessedAt === 'string';
65
+ }
66
+
67
+ /**
68
+ * Validate and reconstruct a DataIntegrityProof or WitnessProof
69
+ */
70
+ function parseProof(proof: unknown): DataIntegrityProof | WitnessProof {
71
+ if (!proof || typeof proof !== 'object') {
72
+ throw new Error('Invalid proof: must be an object');
73
+ }
74
+
75
+ const p = proof as Record<string, unknown>;
76
+
77
+ // Validate required DataIntegrityProof fields
78
+ if (typeof p.type !== 'string') {
79
+ throw new Error('Invalid proof: missing or invalid type');
80
+ }
81
+ if (typeof p.cryptosuite !== 'string') {
82
+ throw new Error('Invalid proof: missing or invalid cryptosuite');
83
+ }
84
+ if (typeof p.created !== 'string') {
85
+ throw new Error('Invalid proof: missing or invalid created');
86
+ }
87
+ if (typeof p.verificationMethod !== 'string') {
88
+ throw new Error('Invalid proof: missing or invalid verificationMethod');
89
+ }
90
+ if (typeof p.proofPurpose !== 'string') {
91
+ throw new Error('Invalid proof: missing or invalid proofPurpose');
92
+ }
93
+ if (typeof p.proofValue !== 'string') {
94
+ throw new Error('Invalid proof: missing or invalid proofValue');
95
+ }
96
+
97
+ const baseProof: DataIntegrityProof = {
98
+ type: p.type,
99
+ cryptosuite: p.cryptosuite,
100
+ created: p.created,
101
+ verificationMethod: p.verificationMethod,
102
+ proofPurpose: p.proofPurpose,
103
+ proofValue: p.proofValue,
104
+ };
105
+
106
+ // Check for WitnessProof
107
+ if ('witnessedAt' in p) {
108
+ if (typeof p.witnessedAt !== 'string') {
109
+ throw new Error('Invalid witness proof: witnessedAt must be a string');
110
+ }
111
+ return {
112
+ ...baseProof,
113
+ witnessedAt: p.witnessedAt,
114
+ } as WitnessProof;
115
+ }
116
+
117
+ return baseProof;
118
+ }
119
+
120
+ /**
121
+ * Validate and reconstruct a LogEntry
122
+ */
123
+ function parseEntry(entry: unknown): LogEntry {
124
+ if (!entry || typeof entry !== 'object') {
125
+ throw new Error('Invalid entry: must be an object');
126
+ }
127
+
128
+ const e = entry as Record<string, unknown>;
129
+
130
+ // Validate type
131
+ if (e.type !== 'create' && e.type !== 'update' && e.type !== 'deactivate') {
132
+ throw new Error(`Invalid entry type: ${e.type}`);
133
+ }
134
+
135
+ // Validate proof array
136
+ if (!Array.isArray(e.proof)) {
137
+ throw new Error('Invalid entry: proof must be an array');
138
+ }
139
+
140
+ const parsedEntry: LogEntry = {
141
+ type: e.type,
142
+ data: e.data,
143
+ proof: e.proof.map(parseProof),
144
+ };
145
+
146
+ // Optional previousEvent
147
+ if (e.previousEvent !== undefined) {
148
+ if (typeof e.previousEvent !== 'string') {
149
+ throw new Error('Invalid entry: previousEvent must be a string');
150
+ }
151
+ parsedEntry.previousEvent = e.previousEvent;
152
+ }
153
+
154
+ return parsedEntry;
155
+ }
156
+
157
+ /**
158
+ * Parse a JSON string into an EventLog.
159
+ *
160
+ * Validates the structure and types of the parsed object.
161
+ *
162
+ * @param json - JSON string to parse
163
+ * @returns Parsed and validated EventLog
164
+ * @throws Error if JSON is invalid or doesn't match EventLog structure
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * const json = '{"events":[...]}';
169
+ * const log = parseEventLogJson(json);
170
+ * console.log(log.events.length);
171
+ * ```
172
+ */
173
+ export function parseEventLogJson(json: string): EventLog {
174
+ if (!json || typeof json !== 'string') {
175
+ throw new Error('Cannot parse null, undefined, or non-string value');
176
+ }
177
+
178
+ let parsed: unknown;
179
+ try {
180
+ parsed = JSON.parse(json);
181
+ } catch (e) {
182
+ throw new Error(`Invalid JSON: ${(e as Error).message}`);
183
+ }
184
+
185
+ if (!parsed || typeof parsed !== 'object') {
186
+ throw new Error('Invalid EventLog: must be an object');
187
+ }
188
+
189
+ const obj = parsed as Record<string, unknown>;
190
+
191
+ // Validate events array
192
+ if (!Array.isArray(obj.events)) {
193
+ throw new Error('Invalid EventLog: events must be an array');
194
+ }
195
+
196
+ const eventLog: EventLog = {
197
+ events: obj.events.map(parseEntry),
198
+ };
199
+
200
+ // Optional previousLog
201
+ if (obj.previousLog !== undefined) {
202
+ if (typeof obj.previousLog !== 'string') {
203
+ throw new Error('Invalid EventLog: previousLog must be a string');
204
+ }
205
+ eventLog.previousLog = obj.previousLog;
206
+ }
207
+
208
+ return eventLog;
209
+ }
@@ -0,0 +1,160 @@
1
+ /**
2
+ * CEL (Cryptographic Event Log) Types
3
+ *
4
+ * Based on W3C CCG CEL Specification v0.1
5
+ * @see https://w3c-ccg.github.io/cel-spec/
6
+ */
7
+
8
+ /**
9
+ * Data Integrity Proof as defined in W3C Data Integrity spec
10
+ * Used for signing events and witness attestations
11
+ */
12
+ export interface DataIntegrityProof {
13
+ /** The type of proof (e.g., "DataIntegrityProof") */
14
+ type: string;
15
+ /** The cryptosuite used (e.g., "eddsa-jcs-2022") */
16
+ cryptosuite: string;
17
+ /** ISO 8601 timestamp when the proof was created */
18
+ created: string;
19
+ /** DID URL of the verification method used to create the proof */
20
+ verificationMethod: string;
21
+ /** The purpose of the proof (e.g., "assertionMethod") */
22
+ proofPurpose: string;
23
+ /** The multibase-encoded proof value */
24
+ proofValue: string;
25
+ }
26
+
27
+ /**
28
+ * Witness Proof - extends DataIntegrityProof with witness-specific fields
29
+ * Used when a third party attests to the existence of an event at a point in time
30
+ */
31
+ export interface WitnessProof extends DataIntegrityProof {
32
+ /** ISO 8601 timestamp when the witness attested to the event */
33
+ witnessedAt: string;
34
+ }
35
+
36
+ /**
37
+ * External Reference - points to data outside the event log
38
+ * Used for large resources that shouldn't be embedded in the log
39
+ */
40
+ export interface ExternalReference {
41
+ /** Optional URLs where the data can be retrieved */
42
+ url?: string[];
43
+ /** Optional MIME type of the data */
44
+ mediaType?: string;
45
+ /** Required Multibase-encoded (base64url-nopad) Multihash (sha2-256) of the data */
46
+ digestMultibase: string;
47
+ }
48
+
49
+ /**
50
+ * Event type for log entries
51
+ */
52
+ export type EventType = 'create' | 'update' | 'deactivate';
53
+
54
+ /**
55
+ * Log Entry - a single event in the cryptographic event log
56
+ * Contains the event data, proof(s), and chain reference
57
+ */
58
+ export interface LogEntry {
59
+ /** The type of event */
60
+ type: EventType;
61
+ /** The event data (schema varies by event type) */
62
+ data: unknown;
63
+ /** Multibase-encoded hash of the previous event (omitted for first event) */
64
+ previousEvent?: string;
65
+ /** One or more proofs attesting to this event (controller proof + optional witness proofs) */
66
+ proof: (DataIntegrityProof | WitnessProof)[];
67
+ }
68
+
69
+ /**
70
+ * Event Log - the complete cryptographic event log
71
+ * Contains a list of hash-chained events with optional chunking support
72
+ */
73
+ export interface EventLog {
74
+ /** The list of events in chronological order */
75
+ events: LogEntry[];
76
+ /** Optional reference to a previous log file (for chunking long histories) */
77
+ previousLog?: string;
78
+ }
79
+
80
+ /**
81
+ * Verification result for a single event
82
+ */
83
+ export interface EventVerification {
84
+ /** Index of the event in the log */
85
+ index: number;
86
+ /** The event type */
87
+ type: EventType;
88
+ /** Whether the event's proofs are valid */
89
+ proofValid: boolean;
90
+ /** Whether the hash chain link is valid (previousEvent matches) */
91
+ chainValid: boolean;
92
+ /** Any errors encountered during verification */
93
+ errors: string[];
94
+ }
95
+
96
+ /**
97
+ * Result of verifying an entire event log
98
+ */
99
+ export interface VerificationResult {
100
+ /** Whether the entire log is valid */
101
+ verified: boolean;
102
+ /** List of errors encountered */
103
+ errors: string[];
104
+ /** Per-event verification details */
105
+ events: EventVerification[];
106
+ }
107
+
108
+ /**
109
+ * Options for creating a new event log
110
+ */
111
+ export interface CreateOptions {
112
+ /** Signer function that produces a proof */
113
+ signer: (data: unknown) => Promise<DataIntegrityProof>;
114
+ /** The verification method DID URL */
115
+ verificationMethod: string;
116
+ /** The proof purpose (defaults to "assertionMethod") */
117
+ proofPurpose?: string;
118
+ }
119
+
120
+ /**
121
+ * Options for updating an event log
122
+ */
123
+ export interface UpdateOptions extends CreateOptions {}
124
+
125
+ /**
126
+ * Options for deactivating an event log
127
+ */
128
+ export interface DeactivateOptions extends CreateOptions {}
129
+
130
+ /**
131
+ * Options for verifying an event log
132
+ */
133
+ export interface VerifyOptions {
134
+ /** Optional custom proof verifier */
135
+ verifier?: (proof: DataIntegrityProof, data: unknown) => Promise<boolean>;
136
+ }
137
+
138
+ /**
139
+ * Asset state derived from replaying event log
140
+ */
141
+ export interface AssetState {
142
+ /** Current DID of the asset */
143
+ did: string;
144
+ /** Asset name */
145
+ name?: string;
146
+ /** Current layer (peer, webvh, btco) */
147
+ layer: 'peer' | 'webvh' | 'btco';
148
+ /** External resources associated with the asset */
149
+ resources: ExternalReference[];
150
+ /** Creator DID */
151
+ creator?: string;
152
+ /** Creation timestamp */
153
+ createdAt?: string;
154
+ /** Last update timestamp */
155
+ updatedAt?: string;
156
+ /** Whether the asset has been deactivated */
157
+ deactivated: boolean;
158
+ /** Custom metadata */
159
+ metadata?: Record<string, unknown>;
160
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * BitcoinWitness - Bitcoin-based witness service for CEL event logs
3
+ *
4
+ * Implements the WitnessService interface using Bitcoin ordinals inscriptions.
5
+ * Used for the did:btco layer to anchor events on the Bitcoin blockchain,
6
+ * providing the highest level of immutability and timestamping.
7
+ *
8
+ * @see https://w3c-ccg.github.io/cel-spec/
9
+ */
10
+
11
+ import type { WitnessProof } from '../types';
12
+ import type { WitnessService } from './WitnessService';
13
+ import type { BitcoinManager } from '../../bitcoin/BitcoinManager';
14
+
15
+ /**
16
+ * Configuration options for BitcoinWitness
17
+ */
18
+ export interface BitcoinWitnessOptions {
19
+ /** Fee rate in sat/vB for inscription transactions (optional - BitcoinManager will estimate if not provided) */
20
+ feeRate?: number;
21
+ /** Verification method DID URL for the witness proof */
22
+ verificationMethod?: string;
23
+ }
24
+
25
+ /**
26
+ * Error thrown when the Bitcoin witness service fails
27
+ */
28
+ export class BitcoinWitnessError extends Error {
29
+ /** The digest that failed to be witnessed */
30
+ readonly digest?: string;
31
+ /** The underlying error message if available */
32
+ readonly cause?: Error;
33
+
34
+ constructor(message: string, digest?: string, cause?: Error) {
35
+ super(message);
36
+ this.name = 'BitcoinWitnessError';
37
+ this.digest = digest;
38
+ this.cause = cause;
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Bitcoin inscription witness proof with additional Bitcoin-specific fields
44
+ */
45
+ export interface BitcoinWitnessProof extends WitnessProof {
46
+ /** The Bitcoin transaction ID containing the witness inscription */
47
+ txid: string;
48
+ /** The block height where the inscription was confirmed (if available) */
49
+ blockHeight?: number;
50
+ /** The satoshi ordinal number anchoring the inscription */
51
+ satoshi: string;
52
+ /** The inscription ID in the format {txid}i{index} */
53
+ inscriptionId: string;
54
+ }
55
+
56
+ /**
57
+ * Bitcoin-based witness service implementation
58
+ *
59
+ * Inscribes digestMultibase on Bitcoin via ordinals and returns a WitnessProof
60
+ * containing the transaction details and satoshi ordinal as anchor.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const bitcoinManager = new BitcoinManager(config);
65
+ * const witness = new BitcoinWitness(bitcoinManager);
66
+ * const proof = await witness.witness('uEiD...');
67
+ * console.log(proof.txid); // Bitcoin transaction ID
68
+ * console.log(proof.satoshi); // Satoshi ordinal anchor
69
+ * ```
70
+ */
71
+ export class BitcoinWitness implements WitnessService {
72
+ private readonly bitcoinManager: BitcoinManager;
73
+ private readonly feeRate?: number;
74
+ private readonly verificationMethod: string;
75
+
76
+ /**
77
+ * Creates a new BitcoinWitness instance
78
+ *
79
+ * @param bitcoinManager - BitcoinManager instance configured with an ordinals provider
80
+ * @param options - Optional configuration options
81
+ */
82
+ constructor(bitcoinManager: BitcoinManager, options: BitcoinWitnessOptions = {}) {
83
+ if (!bitcoinManager) {
84
+ throw new Error('BitcoinManager instance is required');
85
+ }
86
+
87
+ this.bitcoinManager = bitcoinManager;
88
+ this.feeRate = options.feeRate;
89
+ this.verificationMethod = options.verificationMethod ?? 'did:btco:witness';
90
+ }
91
+
92
+ /**
93
+ * Witnesses a digest by inscribing it on the Bitcoin blockchain
94
+ *
95
+ * @param digestMultibase - The Multibase-encoded digest to witness
96
+ * @returns A BitcoinWitnessProof containing the inscription details and witnessedAt timestamp
97
+ * @throws BitcoinWitnessError if the inscription fails
98
+ */
99
+ async witness(digestMultibase: string): Promise<BitcoinWitnessProof> {
100
+ if (!digestMultibase || typeof digestMultibase !== 'string') {
101
+ throw new BitcoinWitnessError('digestMultibase must be a non-empty string', digestMultibase);
102
+ }
103
+
104
+ // Validate multibase prefix (should start with 'u' for base64url-nopad or 'z' for base58btc)
105
+ const validPrefixes = ['u', 'z'];
106
+ if (!validPrefixes.includes(digestMultibase[0])) {
107
+ throw new BitcoinWitnessError(
108
+ `Invalid digestMultibase encoding: expected prefix 'u' or 'z', got '${digestMultibase[0]}'`,
109
+ digestMultibase
110
+ );
111
+ }
112
+
113
+ try {
114
+ // Create witness attestation data
115
+ const witnessData = {
116
+ '@context': 'https://w3id.org/cel/v1',
117
+ type: 'BitcoinWitnessAttestation',
118
+ digestMultibase,
119
+ witnessedAt: new Date().toISOString(),
120
+ };
121
+
122
+ // Inscribe the witness data on Bitcoin
123
+ const inscription = await this.bitcoinManager.inscribeData(
124
+ witnessData,
125
+ 'application/json',
126
+ this.feeRate
127
+ );
128
+
129
+ // Validate inscription result
130
+ if (!inscription.inscriptionId) {
131
+ throw new BitcoinWitnessError(
132
+ 'Bitcoin inscription did not return a valid inscription ID',
133
+ digestMultibase
134
+ );
135
+ }
136
+
137
+ if (!inscription.txid) {
138
+ throw new BitcoinWitnessError(
139
+ 'Bitcoin inscription did not return a transaction ID',
140
+ digestMultibase
141
+ );
142
+ }
143
+
144
+ const now = new Date().toISOString();
145
+
146
+ // Build the WitnessProof with Bitcoin-specific extensions
147
+ const proof: BitcoinWitnessProof = {
148
+ type: 'DataIntegrityProof',
149
+ cryptosuite: 'bitcoin-ordinals-2024',
150
+ created: now,
151
+ verificationMethod: this.verificationMethod,
152
+ proofPurpose: 'assertionMethod',
153
+ proofValue: `z${inscription.inscriptionId}`, // Use inscription ID as proof value with multibase prefix
154
+ witnessedAt: now,
155
+ txid: inscription.txid,
156
+ blockHeight: inscription.blockHeight,
157
+ satoshi: inscription.satoshi,
158
+ inscriptionId: inscription.inscriptionId,
159
+ };
160
+
161
+ return proof;
162
+
163
+ } catch (error) {
164
+ // Re-throw BitcoinWitnessError as-is
165
+ if (error instanceof BitcoinWitnessError) {
166
+ throw error;
167
+ }
168
+
169
+ // Wrap other errors
170
+ throw new BitcoinWitnessError(
171
+ `Failed to inscribe witness on Bitcoin: ${error instanceof Error ? error.message : String(error)}`,
172
+ digestMultibase,
173
+ error instanceof Error ? error : undefined
174
+ );
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Gets the fee rate configured for this witness (if any)
180
+ */
181
+ get configuredFeeRate(): number | undefined {
182
+ return this.feeRate;
183
+ }
184
+ }