@originals/sdk 1.4.2 → 1.4.3

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 (212) hide show
  1. package/package.json +4 -1
  2. package/.eslintrc.json +0 -33
  3. package/src/adapters/FeeOracleMock.ts +0 -9
  4. package/src/adapters/index.ts +0 -5
  5. package/src/adapters/providers/OrdHttpProvider.ts +0 -126
  6. package/src/adapters/providers/OrdMockProvider.ts +0 -101
  7. package/src/adapters/types.ts +0 -66
  8. package/src/bitcoin/BitcoinManager.ts +0 -330
  9. package/src/bitcoin/BroadcastClient.ts +0 -54
  10. package/src/bitcoin/OrdinalsClient.ts +0 -119
  11. package/src/bitcoin/PSBTBuilder.ts +0 -106
  12. package/src/bitcoin/fee-calculation.ts +0 -38
  13. package/src/bitcoin/providers/OrdNodeProvider.ts +0 -92
  14. package/src/bitcoin/providers/OrdinalsProvider.ts +0 -56
  15. package/src/bitcoin/providers/types.ts +0 -59
  16. package/src/bitcoin/transactions/commit.ts +0 -465
  17. package/src/bitcoin/transactions/index.ts +0 -13
  18. package/src/bitcoin/transfer.ts +0 -43
  19. package/src/bitcoin/utxo-selection.ts +0 -322
  20. package/src/bitcoin/utxo.ts +0 -113
  21. package/src/contexts/credentials-v1.json +0 -237
  22. package/src/contexts/credentials-v2-examples.json +0 -5
  23. package/src/contexts/credentials-v2.json +0 -340
  24. package/src/contexts/credentials.json +0 -237
  25. package/src/contexts/data-integrity-v2.json +0 -81
  26. package/src/contexts/dids.json +0 -58
  27. package/src/contexts/ed255192020.json +0 -93
  28. package/src/contexts/ordinals-plus.json +0 -23
  29. package/src/contexts/originals.json +0 -22
  30. package/src/core/OriginalsSDK.ts +0 -416
  31. package/src/crypto/Multikey.ts +0 -194
  32. package/src/crypto/Signer.ts +0 -254
  33. package/src/crypto/noble-init.ts +0 -121
  34. package/src/did/BtcoDidResolver.ts +0 -227
  35. package/src/did/DIDManager.ts +0 -694
  36. package/src/did/Ed25519Verifier.ts +0 -68
  37. package/src/did/KeyManager.ts +0 -236
  38. package/src/did/WebVHManager.ts +0 -498
  39. package/src/did/createBtcoDidDocument.ts +0 -59
  40. package/src/did/providers/OrdinalsClientProviderAdapter.ts +0 -68
  41. package/src/events/EventEmitter.ts +0 -222
  42. package/src/events/index.ts +0 -19
  43. package/src/events/types.ts +0 -331
  44. package/src/examples/basic-usage.ts +0 -78
  45. package/src/examples/create-module-original.ts +0 -435
  46. package/src/examples/full-lifecycle-flow.ts +0 -514
  47. package/src/examples/run.ts +0 -60
  48. package/src/index.ts +0 -150
  49. package/src/kinds/KindRegistry.ts +0 -290
  50. package/src/kinds/index.ts +0 -74
  51. package/src/kinds/types.ts +0 -470
  52. package/src/kinds/validators/AgentValidator.ts +0 -257
  53. package/src/kinds/validators/AppValidator.ts +0 -211
  54. package/src/kinds/validators/DatasetValidator.ts +0 -242
  55. package/src/kinds/validators/DocumentValidator.ts +0 -311
  56. package/src/kinds/validators/MediaValidator.ts +0 -269
  57. package/src/kinds/validators/ModuleValidator.ts +0 -225
  58. package/src/kinds/validators/base.ts +0 -276
  59. package/src/kinds/validators/index.ts +0 -12
  60. package/src/lifecycle/BatchOperations.ts +0 -373
  61. package/src/lifecycle/LifecycleManager.ts +0 -2126
  62. package/src/lifecycle/OriginalsAsset.ts +0 -524
  63. package/src/lifecycle/ProvenanceQuery.ts +0 -280
  64. package/src/lifecycle/ResourceVersioning.ts +0 -163
  65. package/src/migration/MigrationManager.ts +0 -527
  66. package/src/migration/audit/AuditLogger.ts +0 -176
  67. package/src/migration/checkpoint/CheckpointManager.ts +0 -112
  68. package/src/migration/checkpoint/CheckpointStorage.ts +0 -101
  69. package/src/migration/index.ts +0 -33
  70. package/src/migration/operations/BaseMigration.ts +0 -126
  71. package/src/migration/operations/PeerToBtcoMigration.ts +0 -105
  72. package/src/migration/operations/PeerToWebvhMigration.ts +0 -62
  73. package/src/migration/operations/WebvhToBtcoMigration.ts +0 -105
  74. package/src/migration/rollback/RollbackManager.ts +0 -170
  75. package/src/migration/state/StateMachine.ts +0 -92
  76. package/src/migration/state/StateTracker.ts +0 -156
  77. package/src/migration/types.ts +0 -344
  78. package/src/migration/validation/BitcoinValidator.ts +0 -107
  79. package/src/migration/validation/CredentialValidator.ts +0 -62
  80. package/src/migration/validation/DIDCompatibilityValidator.ts +0 -151
  81. package/src/migration/validation/LifecycleValidator.ts +0 -64
  82. package/src/migration/validation/StorageValidator.ts +0 -79
  83. package/src/migration/validation/ValidationPipeline.ts +0 -213
  84. package/src/resources/ResourceManager.ts +0 -655
  85. package/src/resources/index.ts +0 -21
  86. package/src/resources/types.ts +0 -202
  87. package/src/storage/LocalStorageAdapter.ts +0 -61
  88. package/src/storage/MemoryStorageAdapter.ts +0 -29
  89. package/src/storage/StorageAdapter.ts +0 -25
  90. package/src/storage/index.ts +0 -3
  91. package/src/types/bitcoin.ts +0 -98
  92. package/src/types/common.ts +0 -92
  93. package/src/types/credentials.ts +0 -88
  94. package/src/types/did.ts +0 -31
  95. package/src/types/external-shims.d.ts +0 -53
  96. package/src/types/index.ts +0 -7
  97. package/src/types/network.ts +0 -175
  98. package/src/utils/EventLogger.ts +0 -298
  99. package/src/utils/Logger.ts +0 -322
  100. package/src/utils/MetricsCollector.ts +0 -358
  101. package/src/utils/bitcoin-address.ts +0 -130
  102. package/src/utils/cbor.ts +0 -12
  103. package/src/utils/encoding.ts +0 -127
  104. package/src/utils/hash.ts +0 -6
  105. package/src/utils/retry.ts +0 -46
  106. package/src/utils/satoshi-validation.ts +0 -196
  107. package/src/utils/serialization.ts +0 -96
  108. package/src/utils/telemetry.ts +0 -40
  109. package/src/utils/validation.ts +0 -119
  110. package/src/vc/CredentialManager.ts +0 -918
  111. package/src/vc/Issuer.ts +0 -100
  112. package/src/vc/Verifier.ts +0 -47
  113. package/src/vc/cryptosuites/bbs.ts +0 -253
  114. package/src/vc/cryptosuites/bbsSimple.ts +0 -21
  115. package/src/vc/cryptosuites/eddsa.ts +0 -99
  116. package/src/vc/documentLoader.ts +0 -67
  117. package/src/vc/proofs/data-integrity.ts +0 -33
  118. package/src/vc/utils/jsonld.ts +0 -18
  119. package/tests/__mocks__/bbs-signatures.js +0 -17
  120. package/tests/__mocks__/mf-base58.js +0 -24
  121. package/tests/fixtures/did-documents.ts +0 -247
  122. package/tests/index.test.ts +0 -21
  123. package/tests/integration/BatchOperations.test.ts +0 -531
  124. package/tests/integration/CompleteLifecycle.e2e.test.ts +0 -735
  125. package/tests/integration/CredentialManager.test.ts +0 -42
  126. package/tests/integration/DIDManager.test.ts +0 -41
  127. package/tests/integration/DidPeerToWebVhFlow.test.ts +0 -351
  128. package/tests/integration/Events.test.ts +0 -435
  129. package/tests/integration/Lifecycle.transfer.btco.integration.test.ts +0 -25
  130. package/tests/integration/LifecycleManager.test.ts +0 -21
  131. package/tests/integration/MultikeyFlow.test.ts +0 -52
  132. package/tests/integration/TelemetryIntegration.test.ts +0 -395
  133. package/tests/integration/WebVhPublish.test.ts +0 -48
  134. package/tests/integration/createTypedOriginal.test.ts +0 -379
  135. package/tests/integration/migration/peer-to-webvh.test.ts +0 -172
  136. package/tests/manual/test-commit-creation.ts +0 -323
  137. package/tests/mocks/MockKeyStore.ts +0 -38
  138. package/tests/mocks/adapters/MemoryStorageAdapter.ts +0 -24
  139. package/tests/mocks/adapters/MockFeeOracle.ts +0 -11
  140. package/tests/mocks/adapters/MockOrdinalsProvider.ts +0 -76
  141. package/tests/mocks/adapters/OrdMockProvider.test.ts +0 -176
  142. package/tests/mocks/adapters/index.ts +0 -6
  143. package/tests/performance/BatchOperations.perf.test.ts +0 -403
  144. package/tests/performance/logging.perf.test.ts +0 -336
  145. package/tests/sdk.test.ts +0 -43
  146. package/tests/security/bitcoin-penetration-tests.test.ts +0 -622
  147. package/tests/setup.bun.ts +0 -69
  148. package/tests/setup.jest.ts +0 -23
  149. package/tests/stress/batch-operations-stress.test.ts +0 -571
  150. package/tests/unit/adapters/FeeOracleMock.test.ts +0 -40
  151. package/tests/unit/bitcoin/BitcoinManager.test.ts +0 -293
  152. package/tests/unit/bitcoin/BroadcastClient.test.ts +0 -52
  153. package/tests/unit/bitcoin/OrdNodeProvider.test.ts +0 -53
  154. package/tests/unit/bitcoin/OrdinalsClient.test.ts +0 -381
  155. package/tests/unit/bitcoin/OrdinalsClientProvider.test.ts +0 -102
  156. package/tests/unit/bitcoin/PSBTBuilder.test.ts +0 -84
  157. package/tests/unit/bitcoin/fee-calculation.test.ts +0 -261
  158. package/tests/unit/bitcoin/transactions/commit.test.ts +0 -649
  159. package/tests/unit/bitcoin/transfer.test.ts +0 -31
  160. package/tests/unit/bitcoin/utxo-selection-new.test.ts +0 -502
  161. package/tests/unit/bitcoin/utxo.more.test.ts +0 -39
  162. package/tests/unit/bitcoin/utxo.selection.test.ts +0 -38
  163. package/tests/unit/core/OriginalsSDK.test.ts +0 -152
  164. package/tests/unit/crypto/Multikey.test.ts +0 -206
  165. package/tests/unit/crypto/Signer.test.ts +0 -408
  166. package/tests/unit/did/BtcoDidResolver.test.ts +0 -611
  167. package/tests/unit/did/DIDManager.more.test.ts +0 -43
  168. package/tests/unit/did/DIDManager.test.ts +0 -185
  169. package/tests/unit/did/Ed25519Verifier.test.ts +0 -160
  170. package/tests/unit/did/KeyManager.test.ts +0 -452
  171. package/tests/unit/did/OrdinalsClientProviderAdapter.test.ts +0 -45
  172. package/tests/unit/did/WebVHManager.test.ts +0 -435
  173. package/tests/unit/did/createBtcoDidDocument.test.ts +0 -67
  174. package/tests/unit/did/providers/OrdinalsClientProviderAdapter.test.ts +0 -159
  175. package/tests/unit/events/EventEmitter.test.ts +0 -407
  176. package/tests/unit/kinds/KindRegistry.test.ts +0 -329
  177. package/tests/unit/kinds/types.test.ts +0 -409
  178. package/tests/unit/kinds/validators.test.ts +0 -651
  179. package/tests/unit/lifecycle/BatchOperations.test.ts +0 -527
  180. package/tests/unit/lifecycle/LifecycleManager.cleanapi.test.ts +0 -441
  181. package/tests/unit/lifecycle/LifecycleManager.keymanagement.test.ts +0 -312
  182. package/tests/unit/lifecycle/LifecycleManager.prov.test.ts +0 -18
  183. package/tests/unit/lifecycle/LifecycleManager.test.ts +0 -213
  184. package/tests/unit/lifecycle/LifecycleManager.transfer.unit.test.ts +0 -30
  185. package/tests/unit/lifecycle/OriginalsAsset.test.ts +0 -176
  186. package/tests/unit/lifecycle/ProvenanceQuery.test.ts +0 -577
  187. package/tests/unit/lifecycle/ResourceVersioning.test.ts +0 -651
  188. package/tests/unit/resources/ResourceManager.test.ts +0 -740
  189. package/tests/unit/storage/MemoryStorageAdapter.test.ts +0 -93
  190. package/tests/unit/types/network.test.ts +0 -255
  191. package/tests/unit/utils/EventIntegration.test.ts +0 -384
  192. package/tests/unit/utils/Logger.test.ts +0 -473
  193. package/tests/unit/utils/MetricsCollector.test.ts +0 -358
  194. package/tests/unit/utils/bitcoin-address.test.ts +0 -250
  195. package/tests/unit/utils/cbor.test.ts +0 -35
  196. package/tests/unit/utils/encoding.test.ts +0 -318
  197. package/tests/unit/utils/hash.test.ts +0 -12
  198. package/tests/unit/utils/retry.test.ts +0 -100
  199. package/tests/unit/utils/satoshi-validation.test.ts +0 -354
  200. package/tests/unit/utils/serialization.test.ts +0 -124
  201. package/tests/unit/utils/telemetry.test.ts +0 -52
  202. package/tests/unit/utils/validation.test.ts +0 -141
  203. package/tests/unit/vc/CredentialManager.helpers.test.ts +0 -527
  204. package/tests/unit/vc/CredentialManager.test.ts +0 -487
  205. package/tests/unit/vc/Issuer.test.ts +0 -107
  206. package/tests/unit/vc/Verifier.test.ts +0 -525
  207. package/tests/unit/vc/bbs.test.ts +0 -282
  208. package/tests/unit/vc/cryptosuites/eddsa.test.ts +0 -398
  209. package/tests/unit/vc/documentLoader.test.ts +0 -121
  210. package/tests/unit/vc/proofs/data-integrity.test.ts +0 -24
  211. package/tsconfig.json +0 -31
  212. package/tsconfig.test.json +0 -15
@@ -1,649 +0,0 @@
1
- /**
2
- * Tests for commit transaction creation
3
- */
4
- import { describe, test, expect, beforeEach } from 'bun:test';
5
- import {
6
- createCommitTransaction,
7
- type CommitTransactionParams,
8
- type CommitTransactionResult
9
- } from '../../../../src/bitcoin/transactions/commit.js';
10
- import type { Utxo } from '../../../../src/types/bitcoin.js';
11
-
12
- // Helper to create test UTXOs
13
- const createUtxo = (value: number, index: number = 0, network: 'mainnet' | 'testnet' | 'signet' | 'regtest' = 'mainnet'): Utxo => {
14
- const addressMap = {
15
- mainnet: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
16
- testnet: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
17
- signet: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
18
- regtest: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx' // Use testnet format for regtest compatibility with @scure/btc-signer
19
- };
20
-
21
- return {
22
- txid: `${'a'.repeat(62)}${index.toString().padStart(2, '0')}`,
23
- vout: index,
24
- value,
25
- scriptPubKey: '0014' + 'b'.repeat(40), // Mock P2WPKH scriptPubKey
26
- address: addressMap[network]
27
- };
28
- };
29
-
30
- // Helper to create basic commit params
31
- const createCommitParams = (overrides: Partial<CommitTransactionParams> = {}): CommitTransactionParams => {
32
- const network = overrides.network || 'mainnet';
33
- const addressMap = {
34
- mainnet: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
35
- testnet: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
36
- signet: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
37
- regtest: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx' // Use testnet format for regtest compatibility with @scure/btc-signer
38
- };
39
-
40
- return {
41
- content: Buffer.from('Hello Ordinals'),
42
- contentType: 'text/plain',
43
- utxos: overrides.utxos || [createUtxo(10000, 0, network)],
44
- changeAddress: addressMap[network],
45
- feeRate: 10,
46
- network,
47
- ...overrides
48
- };
49
- };
50
-
51
- describe('createCommitTransaction', () => {
52
- describe('Basic Functionality', () => {
53
- test('creates commit transaction with valid inputs', async () => {
54
- const params = createCommitParams();
55
- const result = await createCommitTransaction(params);
56
-
57
- expect(result).toBeDefined();
58
- expect(result.commitAddress).toBeDefined();
59
- expect(result.commitPsbtBase64).toBeDefined();
60
- expect(result.commitPsbt).toBeDefined();
61
- expect(result.selectedUtxos).toHaveLength(1);
62
- expect(result.fees.commit).toBeGreaterThan(0);
63
- });
64
-
65
- test('generates valid P2TR commit address', async () => {
66
- const params = createCommitParams();
67
- const result = await createCommitTransaction(params);
68
-
69
- // P2TR addresses start with bc1p for mainnet
70
- expect(result.commitAddress).toMatch(/^bc1p[a-z0-9]{58}$/);
71
- });
72
-
73
- test('generates reveal keypair', async () => {
74
- const params = createCommitParams();
75
- const result = await createCommitTransaction(params);
76
-
77
- expect(result.revealPrivateKey).toBeDefined();
78
- expect(result.revealPublicKey).toBeDefined();
79
- expect(result.revealPrivateKey).toHaveLength(64); // 32 bytes in hex
80
- expect(result.revealPublicKey).toHaveLength(64); // 32 bytes x-only pubkey in hex
81
- });
82
-
83
- test('includes inscription script data', async () => {
84
- const params = createCommitParams();
85
- const result = await createCommitTransaction(params);
86
-
87
- expect(result.inscriptionScript).toBeDefined();
88
- expect(result.inscriptionScript.script).toBeInstanceOf(Uint8Array);
89
- expect(result.inscriptionScript.controlBlock).toBeInstanceOf(Uint8Array);
90
- expect(result.inscriptionScript.leafVersion).toBe(0xc0);
91
- });
92
-
93
- test('returns correct commit amount', async () => {
94
- const params = createCommitParams({ minimumCommitAmount: 1000 });
95
- const result = await createCommitTransaction(params);
96
-
97
- expect(result.commitAmount).toBeGreaterThanOrEqual(1000);
98
- expect(result.commitAmount).toBeGreaterThanOrEqual(546); // Dust limit
99
- });
100
- });
101
-
102
- describe('UTXO Selection', () => {
103
- test('selects single UTXO when sufficient', async () => {
104
- const params = createCommitParams({
105
- utxos: [createUtxo(10000, 0)]
106
- });
107
- const result = await createCommitTransaction(params);
108
-
109
- expect(result.selectedUtxos).toHaveLength(1);
110
- expect(result.selectedUtxos[0].value).toBe(10000);
111
- });
112
-
113
- test('selects multiple UTXOs when needed', async () => {
114
- const params = createCommitParams({
115
- utxos: [
116
- createUtxo(2000, 0),
117
- createUtxo(2000, 1),
118
- createUtxo(2000, 2)
119
- ],
120
- minimumCommitAmount: 2000
121
- });
122
- const result = await createCommitTransaction(params);
123
-
124
- expect(result.selectedUtxos.length).toBeGreaterThan(1);
125
- const totalValue = result.selectedUtxos.reduce((sum, utxo) => sum + utxo.value, 0);
126
- expect(totalValue).toBeGreaterThanOrEqual(2000 + result.fees.commit);
127
- });
128
-
129
- test('throws when insufficient funds', async () => {
130
- const params = createCommitParams({
131
- utxos: [createUtxo(100, 0)], // Not enough for commit + fees
132
- minimumCommitAmount: 546
133
- });
134
-
135
- await expect(createCommitTransaction(params)).rejects.toThrow(/Insufficient funds/);
136
- });
137
- });
138
-
139
- describe('Fee Calculation', () => {
140
- test('calculates correct fee for 1 input', async () => {
141
- const feeRate = 10; // 10 sats/vB
142
- const params = createCommitParams({
143
- feeRate,
144
- utxos: [createUtxo(10000, 0)]
145
- });
146
- const result = await createCommitTransaction(params);
147
-
148
- // Fee should be reasonable for 1 input, 2 outputs (commit + change)
149
- // Estimate: ~10.5 overhead + 68 input + 43 P2TR + 31 change = ~152 vB
150
- // At 10 sats/vB = ~1520 sats
151
- expect(result.fees.commit).toBeGreaterThan(1000);
152
- expect(result.fees.commit).toBeLessThan(3000);
153
- });
154
-
155
- test('fee scales with fee rate', async () => {
156
- const params1 = createCommitParams({ feeRate: 5 });
157
- const params2 = createCommitParams({ feeRate: 50 });
158
-
159
- const result1 = await createCommitTransaction(params1);
160
- const result2 = await createCommitTransaction(params2);
161
-
162
- // Fee should be ~10x higher for 10x fee rate
163
- expect(result2.fees.commit).toBeGreaterThan(result1.fees.commit * 8);
164
- expect(result2.fees.commit).toBeLessThan(result1.fees.commit * 12);
165
- });
166
-
167
- test('fee increases with multiple inputs', async () => {
168
- const params1 = createCommitParams({
169
- utxos: [createUtxo(10000, 0)]
170
- });
171
- const params2 = createCommitParams({
172
- utxos: [
173
- createUtxo(1500, 0),
174
- createUtxo(1500, 1),
175
- createUtxo(1500, 2),
176
- createUtxo(1500, 3)
177
- ],
178
- minimumCommitAmount: 2000 // Force use of multiple UTXOs
179
- });
180
-
181
- const result1 = await createCommitTransaction(params1);
182
- const result2 = await createCommitTransaction(params2);
183
-
184
- // More inputs = higher fee
185
- expect(result2.fees.commit).toBeGreaterThan(result1.fees.commit);
186
- });
187
- });
188
-
189
- describe('PSBT Construction', () => {
190
- test('PSBT has correct number of inputs', async () => {
191
- const params = createCommitParams({
192
- utxos: [createUtxo(10000, 0)]
193
- });
194
- const result = await createCommitTransaction(params);
195
-
196
- expect(result.commitPsbt.inputsLength).toBe(1);
197
- });
198
-
199
- test('PSBT includes commit output', async () => {
200
- const params = createCommitParams();
201
- const result = await createCommitTransaction(params);
202
-
203
- expect(result.commitPsbt.outputsLength).toBeGreaterThanOrEqual(1);
204
- });
205
-
206
- test('PSBT creates change output when needed', async () => {
207
- const params = createCommitParams({
208
- utxos: [createUtxo(100000, 0)], // Large UTXO
209
- minimumCommitAmount: 546
210
- });
211
- const result = await createCommitTransaction(params);
212
-
213
- // Should have commit output + change output
214
- expect(result.commitPsbt.outputsLength).toBe(2);
215
- });
216
-
217
- test('PSBT omits change when below dust limit', async () => {
218
- const params = createCommitParams({
219
- utxos: [createUtxo(2500, 0)], // Enough for commit + fees with minimal change below dust
220
- minimumCommitAmount: 546,
221
- feeRate: 10
222
- });
223
- const result = await createCommitTransaction(params);
224
-
225
- // Should have only commit output (change below dust limit)
226
- expect(result.commitPsbt.outputsLength).toBe(1);
227
- });
228
-
229
- test('PSBT is valid base64', async () => {
230
- const params = createCommitParams();
231
- const result = await createCommitTransaction(params);
232
-
233
- expect(result.commitPsbtBase64).toBeDefined();
234
- expect(typeof result.commitPsbtBase64).toBe('string');
235
-
236
- // Should be valid base64
237
- const decoded = Buffer.from(result.commitPsbtBase64, 'base64');
238
- expect(decoded.length).toBeGreaterThan(0);
239
- });
240
- });
241
-
242
- describe('Inscription Content', () => {
243
- test('handles text content', async () => {
244
- const params = createCommitParams({
245
- content: Buffer.from('Hello World'),
246
- contentType: 'text/plain'
247
- });
248
- const result = await createCommitTransaction(params);
249
-
250
- expect(result).toBeDefined();
251
- expect(result.commitAddress).toBeDefined();
252
- });
253
-
254
- test('handles JSON content', async () => {
255
- const params = createCommitParams({
256
- content: Buffer.from(JSON.stringify({ test: 'data' })),
257
- contentType: 'application/json'
258
- });
259
- const result = await createCommitTransaction(params);
260
-
261
- expect(result).toBeDefined();
262
- expect(result.commitAddress).toBeDefined();
263
- });
264
-
265
- test('handles binary content', async () => {
266
- const params = createCommitParams({
267
- content: Buffer.from([0x89, 0x50, 0x4E, 0x47]), // PNG header
268
- contentType: 'image/png'
269
- });
270
- const result = await createCommitTransaction(params);
271
-
272
- expect(result).toBeDefined();
273
- expect(result.commitAddress).toBeDefined();
274
- });
275
-
276
- test('handles large content (1KB)', async () => {
277
- const largeContent = Buffer.alloc(1024, 'a');
278
- const params = createCommitParams({
279
- content: largeContent,
280
- contentType: 'text/plain',
281
- utxos: [createUtxo(100000, 0)]
282
- });
283
- const result = await createCommitTransaction(params);
284
-
285
- expect(result).toBeDefined();
286
- expect(result.commitAddress).toBeDefined();
287
- });
288
-
289
- test('includes metadata when provided', async () => {
290
- const params = createCommitParams({
291
- metadata: { title: 'Test Inscription', author: 'Tester' }
292
- });
293
- const result = await createCommitTransaction(params);
294
-
295
- expect(result).toBeDefined();
296
- expect(result.commitAddress).toBeDefined();
297
- });
298
-
299
- test('handles missing pointer gracefully', async () => {
300
- // Pointer is optional, test that it works without it
301
- const params = createCommitParams();
302
- const result = await createCommitTransaction(params);
303
-
304
- expect(result).toBeDefined();
305
- expect(result.commitAddress).toBeDefined();
306
- });
307
- });
308
-
309
- describe('Network Support', () => {
310
- test('creates mainnet commit address', async () => {
311
- const params = createCommitParams({ network: 'mainnet' });
312
- const result = await createCommitTransaction(params);
313
-
314
- expect(result.commitAddress).toMatch(/^bc1p/);
315
- });
316
-
317
- test('creates testnet commit address', async () => {
318
- const params = createCommitParams({ network: 'testnet' });
319
- const result = await createCommitTransaction(params);
320
-
321
- expect(result.commitAddress).toMatch(/^tb1p/);
322
- });
323
-
324
- test('creates signet commit address', async () => {
325
- const params = createCommitParams({ network: 'signet' });
326
- const result = await createCommitTransaction(params);
327
-
328
- expect(result.commitAddress).toMatch(/^tb1p/);
329
- });
330
-
331
- test('creates regtest commit address', async () => {
332
- const params = createCommitParams({ network: 'regtest' });
333
- const result = await createCommitTransaction(params);
334
-
335
- // Regtest uses TEST_NETWORK which generates tb1p addresses
336
- expect(result.commitAddress).toMatch(/^tb1p/);
337
- });
338
- });
339
-
340
- describe('Error Handling', () => {
341
- test('throws when no UTXOs provided', async () => {
342
- const params = createCommitParams({ utxos: [] });
343
- await expect(createCommitTransaction(params)).rejects.toThrow(/No UTXOs provided/);
344
- });
345
-
346
- test('throws when content is empty', async () => {
347
- const params = createCommitParams({ content: Buffer.from([]) });
348
- await expect(createCommitTransaction(params)).rejects.toThrow(/missing content/);
349
- });
350
-
351
- test('throws when contentType is missing', async () => {
352
- const params = createCommitParams({ contentType: '' });
353
- await expect(createCommitTransaction(params)).rejects.toThrow(/missing content type/);
354
- });
355
-
356
- test('throws when changeAddress is missing', async () => {
357
- const params = createCommitParams({ changeAddress: '' });
358
- await expect(createCommitTransaction(params)).rejects.toThrow(/Change address is required/);
359
- });
360
-
361
- test('throws when feeRate is invalid', async () => {
362
- const params = createCommitParams({ feeRate: 0 });
363
- await expect(createCommitTransaction(params)).rejects.toThrow(/Invalid fee rate/);
364
- });
365
-
366
- test('throws when all UTXOs are missing scriptPubKey', async () => {
367
- const invalidUtxo1: Utxo = {
368
- txid: 'a'.repeat(64),
369
- vout: 0,
370
- value: 10000
371
- // Missing scriptPubKey
372
- };
373
-
374
- const invalidUtxo2: Utxo = {
375
- txid: 'b'.repeat(64),
376
- vout: 1,
377
- value: 10000
378
- // Missing scriptPubKey
379
- };
380
-
381
- const params = createCommitParams({
382
- utxos: [invalidUtxo1, invalidUtxo2]
383
- });
384
-
385
- // Should throw error because no valid UTXOs remain after filtering
386
- await expect(createCommitTransaction(params)).rejects.toThrow(/No valid spendable UTXOs available/);
387
- await expect(createCommitTransaction(params)).rejects.toThrow(/missing scriptPubKey/);
388
- });
389
-
390
- test('filters out invalid UTXOs and uses only valid ones', async () => {
391
- const invalidUtxo: Utxo = {
392
- txid: 'a'.repeat(64),
393
- vout: 0,
394
- value: 10000
395
- // Missing scriptPubKey
396
- };
397
-
398
- const params = createCommitParams({
399
- utxos: [invalidUtxo, createUtxo(50000, 1), createUtxo(50000, 2)]
400
- });
401
-
402
- // Should filter out the invalid UTXO and use only the valid ones
403
- const result = await createCommitTransaction(params);
404
- expect(result).toBeDefined();
405
- // Should only use valid UTXOs
406
- expect(result.selectedUtxos.every(u => u.scriptPubKey)).toBe(true);
407
- });
408
- });
409
-
410
- describe('Dust Handling', () => {
411
- test('respects minimum dust limit (546 sats)', async () => {
412
- const params = createCommitParams({ minimumCommitAmount: 100 });
413
- const result = await createCommitTransaction(params);
414
-
415
- // Should use dust limit instead of 100
416
- expect(result.commitAmount).toBeGreaterThanOrEqual(546);
417
- });
418
-
419
- test('uses custom minimum when above dust limit', async () => {
420
- const params = createCommitParams({
421
- minimumCommitAmount: 10000,
422
- utxos: [createUtxo(15000, 0)] // Enough to cover 10000 + fees
423
- });
424
- const result = await createCommitTransaction(params);
425
-
426
- expect(result.commitAmount).toBe(10000);
427
- });
428
-
429
- test('adds dust change to fee', async () => {
430
- // Create scenario where change would be < 546 sats
431
- const params = createCommitParams({
432
- utxos: [createUtxo(1500, 0)],
433
- minimumCommitAmount: 546,
434
- feeRate: 5
435
- });
436
- const result = await createCommitTransaction(params);
437
-
438
- // Should have only commit output (no change)
439
- expect(result.commitPsbt.outputsLength).toBe(1);
440
- });
441
- });
442
-
443
- describe('Consistency', () => {
444
- test('generates different addresses for different content', async () => {
445
- const params1 = createCommitParams({ content: Buffer.from('Content 1') });
446
- const params2 = createCommitParams({ content: Buffer.from('Content 2') });
447
-
448
- const result1 = await createCommitTransaction(params1);
449
- const result2 = await createCommitTransaction(params2);
450
-
451
- // Different content should generate different addresses
452
- expect(result1.commitAddress).not.toBe(result2.commitAddress);
453
- });
454
-
455
- test('generates different addresses on each call (random keypair)', async () => {
456
- const params = createCommitParams();
457
-
458
- const result1 = await createCommitTransaction(params);
459
- const result2 = await createCommitTransaction(params);
460
-
461
- // Different reveal keypairs should generate different addresses
462
- expect(result1.commitAddress).not.toBe(result2.commitAddress);
463
- expect(result1.revealPrivateKey).not.toBe(result2.revealPrivateKey);
464
- });
465
-
466
- test('total value equals commit + change + fees', async () => {
467
- const params = createCommitParams({
468
- utxos: [createUtxo(100000, 0)]
469
- });
470
- const result = await createCommitTransaction(params);
471
-
472
- const totalInput = result.selectedUtxos.reduce((sum, utxo) => sum + utxo.value, 0);
473
- const totalOutput = result.commitAmount;
474
- const fee = result.fees.commit;
475
-
476
- // Get change amount from PSBT if it exists
477
- let changeAmount = 0;
478
- if (result.commitPsbt.outputsLength === 2) {
479
- changeAmount = totalInput - totalOutput - fee;
480
- }
481
-
482
- expect(totalInput).toBe(totalOutput + changeAmount + fee);
483
- });
484
-
485
- test('inputs always cover outputs (no negative change)', async () => {
486
- // Test with various fee rates to ensure iterative selection works
487
- const feeRates = [1, 5, 10, 20, 50];
488
-
489
- for (const feeRate of feeRates) {
490
- const params = createCommitParams({
491
- utxos: [createUtxo(10000, 0), createUtxo(20000, 1), createUtxo(30000, 2)],
492
- feeRate
493
- });
494
-
495
- const result = await createCommitTransaction(params);
496
-
497
- const totalInput = result.selectedUtxos.reduce((sum, utxo) => sum + utxo.value, 0);
498
- const totalOutput = result.commitAmount + result.fees.commit;
499
-
500
- // Critical check: inputs must always be >= outputs
501
- expect(totalInput).toBeGreaterThanOrEqual(totalOutput);
502
-
503
- // Calculate actual change
504
- const actualChange = totalInput - totalOutput;
505
- expect(actualChange).toBeGreaterThanOrEqual(0);
506
- }
507
- });
508
- });
509
-
510
- describe('Iterative UTXO Selection', () => {
511
- test('reselects UTXOs when fee increases after accurate calculation', async () => {
512
- // Create scenario where 1 UTXO isn't enough after fee recalculation
513
- const params = createCommitParams({
514
- utxos: [
515
- createUtxo(1500, 0), // Not enough alone
516
- createUtxo(2000, 1), // Will need this one too
517
- createUtxo(5000, 2) // May need this as well
518
- ],
519
- minimumCommitAmount: 546,
520
- feeRate: 10
521
- });
522
-
523
- const result = await createCommitTransaction(params);
524
-
525
- // Should have selected enough UTXOs to cover commit + fees
526
- const totalInput = result.selectedUtxos.reduce((sum, utxo) => sum + utxo.value, 0);
527
- expect(totalInput).toBeGreaterThanOrEqual(result.commitAmount + result.fees.commit);
528
- });
529
-
530
- test('stops iteration when sufficient funds are found', async () => {
531
- // Create scenario with plenty of UTXOs
532
- const params = createCommitParams({
533
- utxos: [
534
- createUtxo(100000, 0), // This should be enough
535
- createUtxo(100000, 1),
536
- createUtxo(100000, 2)
537
- ],
538
- feeRate: 10
539
- });
540
-
541
- const result = await createCommitTransaction(params);
542
-
543
- // Should not need all UTXOs since first one is sufficient
544
- expect(result.selectedUtxos.length).toBeLessThan(3);
545
- });
546
-
547
- test('throws error if max iterations reached without sufficient funds', async () => {
548
- // Create scenario where UTXOs are just barely insufficient
549
- // This would require many iterations if the algorithm isn't working
550
- const params = createCommitParams({
551
- utxos: [
552
- createUtxo(500, 0),
553
- createUtxo(500, 1)
554
- ],
555
- minimumCommitAmount: 546,
556
- feeRate: 50 // High fee rate makes it impossible
557
- });
558
-
559
- // Should throw after max iterations
560
- await expect(createCommitTransaction(params)).rejects.toThrow(/Insufficient funds/);
561
- });
562
- });
563
-
564
- describe('UTXO Validation', () => {
565
- test('validates UTXO has txid', async () => {
566
- const invalidUtxo: Utxo = {
567
- txid: '', // Empty txid
568
- vout: 0,
569
- value: 10000,
570
- scriptPubKey: '0014' + 'a'.repeat(40)
571
- };
572
-
573
- const params = createCommitParams({
574
- utxos: [invalidUtxo]
575
- });
576
-
577
- await expect(createCommitTransaction(params)).rejects.toThrow(/No valid spendable UTXOs/);
578
- });
579
-
580
- test('validates UTXO has valid vout', async () => {
581
- const invalidUtxo: any = {
582
- txid: 'a'.repeat(64),
583
- vout: 'invalid', // Invalid vout type
584
- value: 10000,
585
- scriptPubKey: '0014' + 'a'.repeat(40)
586
- };
587
-
588
- const params = createCommitParams({
589
- utxos: [invalidUtxo]
590
- });
591
-
592
- await expect(createCommitTransaction(params)).rejects.toThrow(/No valid spendable UTXOs/);
593
- });
594
-
595
- test('validates UTXO has positive value', async () => {
596
- const invalidUtxo: Utxo = {
597
- txid: 'a'.repeat(64),
598
- vout: 0,
599
- value: 0, // Zero value
600
- scriptPubKey: '0014' + 'a'.repeat(40)
601
- };
602
-
603
- const params = createCommitParams({
604
- utxos: [invalidUtxo]
605
- });
606
-
607
- await expect(createCommitTransaction(params)).rejects.toThrow(/No valid spendable UTXOs/);
608
- });
609
-
610
- test('provides detailed error message for invalid UTXOs', async () => {
611
- const invalidUtxos: Utxo[] = [
612
- {
613
- txid: 'a'.repeat(64),
614
- vout: 0,
615
- value: 10000
616
- // Missing scriptPubKey
617
- },
618
- {
619
- txid: '', // Missing txid
620
- vout: 1,
621
- value: 10000,
622
- scriptPubKey: '0014' + 'a'.repeat(40)
623
- },
624
- {
625
- txid: 'c'.repeat(64),
626
- vout: 2,
627
- value: 0, // Invalid value
628
- scriptPubKey: '0014' + 'a'.repeat(40)
629
- }
630
- ];
631
-
632
- const params = createCommitParams({
633
- utxos: invalidUtxos
634
- });
635
-
636
- try {
637
- await createCommitTransaction(params);
638
- throw new Error('Should have thrown');
639
- } catch (error) {
640
- expect(error).toBeInstanceOf(Error);
641
- if (error instanceof Error) {
642
- // Should contain detailed information about what's wrong
643
- expect(error.message).toMatch(/No valid spendable UTXOs available/);
644
- expect(error.message).toMatch(/3 UTXO.*provided but all are invalid/);
645
- }
646
- }
647
- });
648
- });
649
- });
@@ -1,31 +0,0 @@
1
- import { describe, test, expect } from 'bun:test';
2
- import { buildTransferTransaction } from '../../../src/bitcoin/transfer';
3
- import { DUST_LIMIT_SATS, Utxo } from '../../../src/types';
4
-
5
- describe('buildTransferTransaction', () => {
6
- const utxo = (value: number, i: number = 0): Utxo => ({ txid: 't', vout: i, value });
7
-
8
- test('creates tx with recipient output and change when above dust', () => {
9
- const { tx, selection } = buildTransferTransaction([utxo(100_000)], 'bc1qto', 50_000, 1);
10
- expect(tx.vout[0].address).toBe('bc1qto');
11
- expect(tx.vout[0].value).toBe(50_000);
12
- expect(selection.changeSats).toBeGreaterThanOrEqual(DUST_LIMIT_SATS);
13
- // change output present when change >= dust
14
- expect(tx.vout.length).toBe(2);
15
- });
16
-
17
- test('suppresses change output when below dust threshold', () => {
18
- const { tx, selection } = buildTransferTransaction([utxo(800)], 'addr', DUST_LIMIT_SATS, 1);
19
- expect(selection.changeSats).toBe(0);
20
- // only recipient output
21
- expect(tx.vout.length).toBe(1);
22
- });
23
-
24
- test('uses input address as default change address when provided', () => {
25
- const inputWithAddr: Utxo = { txid: 't', vout: 0, value: 100000, address: 'bc1qchange' };
26
- const { tx, selection } = buildTransferTransaction([inputWithAddr], 'bc1qto', 50000, 1);
27
- expect(selection.changeSats).toBeGreaterThanOrEqual(DUST_LIMIT_SATS);
28
- // change output address should be input address when not passed explicitly
29
- expect(tx.vout[1].address).toBe('bc1qchange');
30
- });
31
- });