@smartledger/bsv 3.1.1 → 3.2.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 (67) hide show
  1. package/CHANGELOG.md +123 -1
  2. package/README.md +233 -277
  3. package/bsv.bundle.js +39 -0
  4. package/bsv.min.js +8 -8
  5. package/docs/ADVANCED_COVENANT_DEVELOPMENT.md +533 -0
  6. package/docs/COVENANT_DEVELOPMENT_RESOLVED.md +169 -0
  7. package/docs/CUSTOM_SCRIPT_DEVELOPMENT.md +320 -0
  8. package/docs/README.md +201 -0
  9. package/docs/block.md +46 -0
  10. package/docs/ecies.md +102 -0
  11. package/docs/index.md +104 -0
  12. package/docs/nchain.md +958 -0
  13. package/docs/networks.md +55 -0
  14. package/docs/preimage.md +126 -0
  15. package/docs/script.md +139 -0
  16. package/docs/transaction.md +174 -0
  17. package/docs/unspentoutput.md +32 -0
  18. package/examples/README.md +200 -0
  19. package/examples/basic/transaction-creation.js +534 -0
  20. package/examples/basic/transaction_signature_api_gap.js +178 -0
  21. package/examples/covenants/advanced_covenant_demo.js +219 -0
  22. package/examples/covenants/covenant_interface_demo.js +270 -0
  23. package/examples/covenants/covenant_manual_signature_resolved.js +212 -0
  24. package/examples/covenants/covenant_signature_template.js +117 -0
  25. package/examples/covenants2/covenant_bidirectional_example.js +262 -0
  26. package/examples/covenants2/covenant_utils_demo.js +120 -0
  27. package/examples/covenants2/preimage_covenant_utils.js +287 -0
  28. package/examples/covenants2/production_integration.js +256 -0
  29. package/examples/data/covenant_utxos.json +28 -0
  30. package/examples/data/utxos.json +26 -0
  31. package/examples/preimage/README.md +178 -0
  32. package/examples/preimage/extract_preimage_bidirectional.js +421 -0
  33. package/examples/preimage/generate_sample_preimage.js +208 -0
  34. package/examples/preimage/generate_sighash_examples.js +152 -0
  35. package/examples/preimage/parse_preimage.js +117 -0
  36. package/examples/preimage/test_preimage_extractor.js +53 -0
  37. package/examples/preimage/test_varint_extraction.js +95 -0
  38. package/examples/scripts/custom_script_helper_example.js +273 -0
  39. package/examples/scripts/custom_script_signature_test.js +344 -0
  40. package/examples/scripts/script_interpreter.js +193 -0
  41. package/examples/smart_contract/complete_workflow_demo.js +343 -0
  42. package/examples/smart_contract/covenant_builder_demo.js +176 -0
  43. package/examples/smart_contract/script_testing_integration.js +198 -0
  44. package/index.js +3 -0
  45. package/lib/covenant-interface.js +713 -0
  46. package/lib/opcode.js +14 -7
  47. package/lib/smart_contract/API_REFERENCE.md +754 -0
  48. package/lib/smart_contract/DOCUMENTATION_SUMMARY.md +201 -0
  49. package/lib/smart_contract/EXAMPLES.md +751 -0
  50. package/lib/smart_contract/QUICK_START.md +549 -0
  51. package/lib/smart_contract/README.md +395 -0
  52. package/lib/smart_contract/builder.js +452 -0
  53. package/lib/smart_contract/covenant.js +336 -0
  54. package/lib/smart_contract/covenant_builder.js +512 -0
  55. package/lib/smart_contract/index.js +311 -0
  56. package/lib/smart_contract/opcode_list.js +30 -0
  57. package/lib/smart_contract/opcode_map.js +1174 -0
  58. package/lib/smart_contract/opcodes.md +1173 -0
  59. package/lib/smart_contract/preimage.js +903 -0
  60. package/lib/smart_contract/script_tester.js +487 -0
  61. package/lib/smart_contract/script_utils.js +609 -0
  62. package/lib/smart_contract/sighash.js +310 -0
  63. package/lib/smart_contract/smartledger-opcode_review.md +70 -0
  64. package/lib/smart_contract/test_integration.js +269 -0
  65. package/lib/smart_contract/utxo_generator.js +367 -0
  66. package/package.json +43 -10
  67. package/utilities/blockchain-state.json +20478 -3
@@ -0,0 +1,713 @@
1
+ /**
2
+ * SmartLedger Covenant Interface - Advanced BSV Covenant Development
3
+ *
4
+ * Provides high-level abstractions for covenant development while preserving
5
+ * full access to low-level BSV operations. Works alongside existing BSV API.
6
+ *
7
+ * Features:
8
+ * - Simplified covenant creation and validation
9
+ * - Automatic preimage generation and parsing
10
+ * - Template-based covenant patterns
11
+ * - Full compatibility with existing bsv library
12
+ * - Granular control when needed
13
+ */
14
+
15
+ const bsv = require('../index.js');
16
+
17
+ class CovenantInterface {
18
+ constructor() {
19
+ this.bsv = bsv; // Full access to underlying BSV library
20
+ }
21
+
22
+ /**
23
+ * Create a covenant-ready transaction with preimage access
24
+ * @param {Object} config - Transaction configuration
25
+ * @returns {CovenantTransaction} Enhanced transaction object
26
+ */
27
+ createCovenantTransaction(config) {
28
+ const tx = new bsv.Transaction();
29
+
30
+ // Add inputs
31
+ if (config.inputs) {
32
+ config.inputs.forEach(input => tx.from(input));
33
+ }
34
+
35
+ // Add outputs
36
+ if (config.outputs) {
37
+ config.outputs.forEach(output => {
38
+ if (output.script) {
39
+ tx.addOutput(new bsv.Transaction.Output({
40
+ script: output.script,
41
+ satoshis: output.satoshis
42
+ }));
43
+ } else {
44
+ tx.to(output.address, output.satoshis);
45
+ }
46
+ });
47
+ }
48
+
49
+ // Set fee configuration
50
+ if (config.feePerKb) {
51
+ tx.feePerKb(config.feePerKb);
52
+ }
53
+
54
+ return new CovenantTransaction(tx, this);
55
+ }
56
+
57
+ /**
58
+ * Create manual signature using correct BSV API
59
+ * @param {Transaction} transaction - BSV transaction
60
+ * @param {PrivateKey} privateKey - Private key to sign with
61
+ * @param {number} inputIndex - Input index
62
+ * @param {Script} lockingScript - Locking script being spent
63
+ * @param {number} satoshis - Amount in satoshis
64
+ * @param {number} sighashType - Signature hash type
65
+ * @returns {Buffer} Complete signature with sighash type
66
+ */
67
+ createSignature(transaction, privateKey, inputIndex, lockingScript, satoshis, sighashType = null) {
68
+ sighashType = sighashType || (bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID);
69
+
70
+ const signature = bsv.Transaction.sighash.sign(
71
+ transaction,
72
+ privateKey,
73
+ sighashType,
74
+ inputIndex,
75
+ lockingScript,
76
+ new bsv.crypto.BN(satoshis)
77
+ );
78
+
79
+ return Buffer.concat([signature.toDER(), Buffer.from([sighashType])]);
80
+ }
81
+
82
+ /**
83
+ * Get transaction preimage for covenant validation
84
+ * @param {Transaction} transaction - BSV transaction
85
+ * @param {number} inputIndex - Input index
86
+ * @param {Script} lockingScript - Locking script
87
+ * @param {number} satoshis - Amount in satoshis
88
+ * @param {number} sighashType - Signature hash type
89
+ * @returns {CovenantPreimage} Parsed preimage object
90
+ */
91
+ getPreimage(transaction, inputIndex, lockingScript, satoshis, sighashType = null) {
92
+ sighashType = sighashType || (bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID);
93
+
94
+ const preimage = bsv.Transaction.sighash.sighash(
95
+ transaction,
96
+ sighashType,
97
+ inputIndex,
98
+ lockingScript,
99
+ new bsv.crypto.BN(satoshis)
100
+ );
101
+
102
+ return new CovenantPreimage(preimage);
103
+ }
104
+
105
+ /**
106
+ * Covenant Template: State Machine
107
+ * @param {Array} states - Array of state definitions
108
+ * @param {number} currentState - Current state index
109
+ * @param {PublicKey} authorizedKey - Key authorized for state transitions
110
+ * @returns {Script} State machine covenant script
111
+ */
112
+ createStateMachine(states, currentState, authorizedKey) {
113
+ const script = new bsv.Script();
114
+
115
+ // Check current state
116
+ script.add(Buffer.from([currentState]));
117
+ script.add(bsv.Opcode.OP_EQUAL);
118
+ script.add(bsv.Opcode.OP_VERIFY);
119
+
120
+ // Validate state transition logic
121
+ for (let i = 0; i < states.length - 1; i++) {
122
+ if (i === currentState) {
123
+ // Valid next states
124
+ states[i].nextStates.forEach(nextState => {
125
+ script.add(Buffer.from([nextState]));
126
+ script.add(bsv.Opcode.OP_EQUAL);
127
+ script.add(bsv.Opcode.OP_IF);
128
+ // Add transition logic here
129
+ script.add(bsv.Opcode.OP_ENDIF);
130
+ });
131
+ }
132
+ }
133
+
134
+ // Require authorized signature
135
+ script.add(bsv.Opcode.OP_DUP);
136
+ script.add(bsv.Opcode.OP_HASH160);
137
+ script.add(authorizedKey.toAddress().hashBuffer);
138
+ script.add(bsv.Opcode.OP_EQUALVERIFY);
139
+ script.add(bsv.Opcode.OP_CHECKSIG);
140
+
141
+ return script;
142
+ }
143
+
144
+ /**
145
+ * Covenant Template: Escrow with Arbitration
146
+ * @param {PublicKey} buyer - Buyer public key
147
+ * @param {PublicKey} seller - Seller public key
148
+ * @param {PublicKey} arbitrator - Arbitrator public key
149
+ * @param {number} timelock - Optional timelock for refund
150
+ * @returns {Script} Escrow covenant script
151
+ */
152
+ createEscrow(buyer, seller, arbitrator, timelock = null) {
153
+ const script = new bsv.Script();
154
+
155
+ if (timelock) {
156
+ // Time-locked refund path
157
+ script.add(bsv.Opcode.OP_IF);
158
+ script.add(Buffer.from(timelock.toString(16).padStart(8, '0'), 'hex').reverse());
159
+ script.add(bsv.Opcode.OP_CHECKLOCKTIMEVERIFY);
160
+ script.add(bsv.Opcode.OP_DROP);
161
+ script.add(buyer.toBuffer());
162
+ script.add(bsv.Opcode.OP_CHECKSIG);
163
+ script.add(bsv.Opcode.OP_ELSE);
164
+ }
165
+
166
+ // 2-of-3 multisig: buyer + seller, buyer + arbitrator, or seller + arbitrator
167
+ script.add(bsv.Opcode.OP_2);
168
+ script.add(buyer.toBuffer());
169
+ script.add(seller.toBuffer());
170
+ script.add(arbitrator.toBuffer());
171
+ script.add(bsv.Opcode.OP_3);
172
+ script.add(bsv.Opcode.OP_CHECKMULTISIG);
173
+
174
+ if (timelock) {
175
+ script.add(bsv.Opcode.OP_ENDIF);
176
+ }
177
+
178
+ return script;
179
+ }
180
+
181
+ /**
182
+ * Covenant Template: Token Transfer with Rules
183
+ * @param {PublicKey} newOwner - New owner public key
184
+ * @param {number} minAmount - Minimum transfer amount
185
+ * @param {Script} additionalRules - Optional additional validation rules
186
+ * @returns {Script} Token covenant script
187
+ */
188
+ createTokenTransfer(newOwner, minAmount, additionalRules = null) {
189
+ const script = new bsv.Script();
190
+
191
+ // Check minimum amount
192
+ if (minAmount > 0) {
193
+ script.add(bsv.Opcode.OP_DUP);
194
+ script.add(Buffer.from(minAmount.toString(16), 'hex'));
195
+ script.add(bsv.Opcode.OP_GREATERTHANOREQUAL);
196
+ script.add(bsv.Opcode.OP_VERIFY);
197
+ }
198
+
199
+ // Add custom rules
200
+ if (additionalRules) {
201
+ script.add(additionalRules.toBuffer());
202
+ }
203
+
204
+ // Transfer to new owner
205
+ script.add(bsv.Opcode.OP_DUP);
206
+ script.add(bsv.Opcode.OP_HASH160);
207
+ script.add(newOwner.toAddress().hashBuffer);
208
+ script.add(bsv.Opcode.OP_EQUALVERIFY);
209
+ script.add(bsv.Opcode.OP_CHECKSIG);
210
+
211
+ return script;
212
+ }
213
+
214
+ /**
215
+ * Validate covenant execution
216
+ * @param {Transaction} transaction - Transaction to validate
217
+ * @param {number} inputIndex - Input index
218
+ * @param {Script} unlockingScript - Unlocking script
219
+ * @param {Script} lockingScript - Locking script
220
+ * @returns {CovenantValidation} Validation result
221
+ */
222
+ validateCovenant(transaction, inputIndex, unlockingScript, lockingScript) {
223
+ try {
224
+ const interpreter = new bsv.Script.Interpreter();
225
+ const flags = bsv.Script.Interpreter.SCRIPT_VERIFY_P2SH |
226
+ bsv.Script.Interpreter.SCRIPT_VERIFY_STRICTENC |
227
+ bsv.Script.Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID |
228
+ bsv.Script.Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES |
229
+ bsv.Script.Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES;
230
+
231
+ const isValid = interpreter.verify(unlockingScript, lockingScript, transaction, inputIndex, flags);
232
+
233
+ return new CovenantValidation(isValid, interpreter.errstr || 'Success');
234
+ } catch (error) {
235
+ return new CovenantValidation(false, error.message);
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Advanced covenant construction based on nChain PUSHTX techniques
241
+ * @param {string} type - Covenant type ('pushtx', 'perpetual', 'pels')
242
+ * @param {Object} params - Covenant parameters
243
+ * @returns {Script} Advanced covenant script
244
+ */
245
+ createAdvancedCovenant(type, params = {}) {
246
+ const templates = {
247
+ 'pushtx': this.createPushtxCovenant,
248
+ 'perpetual': this.createPerpetualCovenant,
249
+ 'pels': this.createPerpetualCovenant, // PELS is a type of perpetual covenant
250
+ 'introspection': this.createIntrospectionCovenant
251
+ };
252
+
253
+ const templateFn = templates[type];
254
+ if (!templateFn) {
255
+ throw new Error(`Unknown advanced covenant type: ${type}. Available types: ${Object.keys(templates).join(', ')}`);
256
+ }
257
+
258
+ return templateFn.call(this, params);
259
+ }
260
+
261
+ /**
262
+ * PUSHTX implementation based on nChain white paper WP1605
263
+ * Generates signature in-script to push current transaction to stack
264
+ * @param {Object} params - PUSHTX parameters
265
+ * @returns {Script} PUSHTX covenant script
266
+ */
267
+ createPushtxCovenant(params = {}) {
268
+ const {
269
+ publicKey = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
270
+ enforceOutputs = true,
271
+ sighashType = 0x41 // SIGHASH_ALL | SIGHASH_FORKID
272
+ } = params;
273
+
274
+ const script = new bsv.Script();
275
+
276
+ // Message construction for covenant validation (items 1-7 from preimage)
277
+ script.add(bsv.Opcode.OP_2DUP)
278
+ .add(bsv.Opcode.OP_HASH256) // Hash outputs (item 9)
279
+ .add(bsv.Opcode.OP_SWAP);
280
+
281
+ // Add sequence number (item 8)
282
+ script.add(Buffer.from('ffffffff', 'hex'))
283
+ .add(bsv.Opcode.OP_CAT)
284
+ .add(bsv.Opcode.OP_SWAP)
285
+ .add(bsv.Opcode.OP_CAT);
286
+
287
+ // Add locktime (item 10) and sighash flag (item 11)
288
+ script.add(Buffer.from('00000000', 'hex')) // nLockTime
289
+ .add(Buffer.from('41000000', 'hex')) // sighashType in little-endian
290
+ .add(bsv.Opcode.OP_CAT)
291
+ .add(bsv.Opcode.OP_CAT);
292
+
293
+ // PUSHTX signature generation (k=a=1 optimization)
294
+ script.add(bsv.Opcode.OP_HASH256);
295
+
296
+ // Add generator point x-coordinate
297
+ const generatorX = '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798';
298
+ script.add(Buffer.from(generatorX, 'hex'))
299
+ .add(bsv.Opcode.OP_ADD);
300
+
301
+ // Modular arithmetic with secp256k1 order
302
+ const secp256k1Order = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
303
+ script.add(Buffer.from(secp256k1Order, 'hex'))
304
+ .add(bsv.Opcode.OP_MOD);
305
+
306
+ // Convert to canonical DER format
307
+ this._addDERConversion(script);
308
+
309
+ // Add sighash flag and public key
310
+ script.add(Buffer.from([sighashType]))
311
+ .add(bsv.Opcode.OP_CAT)
312
+ .add(Buffer.from(publicKey, 'hex'));
313
+
314
+ // Verify signature with OP_CHECKSIGVERIFY
315
+ script.add(bsv.Opcode.OP_CHECKSIGVERIFY);
316
+
317
+ if (enforceOutputs) {
318
+ // Message is now on stack - add output enforcement
319
+ this._addOutputValidation(script, params);
320
+ }
321
+
322
+ return script;
323
+ }
324
+
325
+ /**
326
+ * Perpetually Enforcing Locking Script (PELS) from nChain paper
327
+ * Forces all future transactions to maintain same locking script and value
328
+ * @param {Object} params - PELS parameters
329
+ * @returns {Script} PELS covenant script
330
+ */
331
+ createPerpetualCovenant(params = {}) {
332
+ const {
333
+ publicKeyHash,
334
+ feeDeduction = 512,
335
+ enforceScript = true,
336
+ enforceValue = true
337
+ } = params;
338
+
339
+ if (!publicKeyHash) {
340
+ throw new Error('publicKeyHash required for perpetual covenant');
341
+ }
342
+
343
+ const script = new bsv.Script();
344
+
345
+ // Construct message with fee-adjusted output validation
346
+ script.add(bsv.Opcode.OP_2DUP)
347
+ .add(bsv.Opcode.OP_BIN2NUM);
348
+
349
+ // Deduct transaction fee if specified
350
+ if (feeDeduction > 0) {
351
+ script.add(Buffer.from(feeDeduction.toString(16).padStart(4, '0'), 'hex'))
352
+ .add(bsv.Opcode.OP_SUB);
353
+ }
354
+
355
+ // Convert back to 8-byte little-endian
356
+ script.add(Buffer.from([0x08]))
357
+ .add(bsv.Opcode.OP_NUM2BIN)
358
+ .add(bsv.Opcode.OP_SWAP)
359
+ .add(bsv.Opcode.OP_CAT);
360
+
361
+ // Hash the new output for message construction
362
+ script.add(bsv.Opcode.OP_HASH256);
363
+
364
+ // Build complete sighash preimage
365
+ this._addPreimageConstruction(script, params);
366
+
367
+ // Generate and verify PUSHTX signature
368
+ this._addPushtxSignature(script, params);
369
+
370
+ // Extract and validate output structure against previous output
371
+ // Skip to value field (104 bytes into preimage)
372
+ script.add(bsv.Opcode.OP_SWAP)
373
+ .add(Buffer.from([0x68])) // 104 decimal = 0x68 hex
374
+ .add(bsv.Opcode.OP_SPLIT)
375
+ .add(bsv.Opcode.OP_NIP)
376
+ .add(bsv.Opcode.OP_SWAP)
377
+ .add(Buffer.from([0x08])) // 8 bytes for value
378
+ .add(bsv.Opcode.OP_SPLIT)
379
+ .add(bsv.Opcode.OP_SWAP)
380
+ .add(bsv.Opcode.OP_CAT);
381
+
382
+ // Verify current output matches previous output format
383
+ if (enforceValue || enforceScript) {
384
+ script.add(bsv.Opcode.OP_EQUALVERIFY);
385
+ }
386
+
387
+ // Final P2PKH check for authenticity
388
+ script.add(bsv.Opcode.OP_DUP)
389
+ .add(bsv.Opcode.OP_HASH160)
390
+ .add(Buffer.from(publicKeyHash, 'hex'))
391
+ .add(bsv.Opcode.OP_EQUALVERIFY)
392
+ .add(bsv.Opcode.OP_CHECKSIG);
393
+
394
+ return script;
395
+ }
396
+
397
+ /**
398
+ * Transaction introspection covenant using preimage analysis
399
+ * @param {Object} params - Introspection parameters
400
+ * @returns {Script} Introspection covenant script
401
+ */
402
+ createIntrospectionCovenant(params = {}) {
403
+ const {
404
+ validateInputs = false,
405
+ validateOutputs = true,
406
+ validateSequence = false,
407
+ validateLocktime = false
408
+ } = params;
409
+
410
+ const script = new bsv.Script();
411
+
412
+ // Get preimage for analysis
413
+ this._addPushtxSignature(script, params);
414
+
415
+ // Parse preimage fields for validation
416
+ if (validateInputs) {
417
+ script.add(bsv.Opcode.OP_DUP)
418
+ .add(Buffer.from([0x04, 0x24])) // Skip to hashPrevouts
419
+ .add(bsv.Opcode.OP_SPLIT)
420
+ .add(bsv.Opcode.OP_DROP);
421
+ // Add input validation logic here
422
+ }
423
+
424
+ if (validateOutputs) {
425
+ // Extract hashOutputs for validation
426
+ script.add(bsv.Opcode.OP_DUP)
427
+ .add(Buffer.from([0x64])) // Skip to hashOutputs position
428
+ .add(bsv.Opcode.OP_SPLIT)
429
+ .add(bsv.Opcode.OP_NIP)
430
+ .add(Buffer.from([0x20])) // 32 bytes
431
+ .add(bsv.Opcode.OP_SPLIT)
432
+ .add(bsv.Opcode.OP_DROP);
433
+ // Add output validation logic here
434
+ }
435
+
436
+ return script;
437
+ }
438
+
439
+ // Helper methods for advanced covenant construction
440
+
441
+ _addDERConversion(script) {
442
+ // Convert s value to canonical form (s <= n/2)
443
+ const secp256k1HalfOrder = '7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0';
444
+
445
+ script.add(bsv.Opcode.OP_DUP)
446
+ .add(Buffer.from(secp256k1HalfOrder, 'hex'))
447
+ .add(bsv.Opcode.OP_GREATERTHAN)
448
+ .add(bsv.Opcode.OP_IF);
449
+
450
+ // If s > n/2, compute n - s to prevent malleability
451
+ const secp256k1Order = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
452
+ script.add(Buffer.from(secp256k1Order, 'hex'))
453
+ .add(bsv.Opcode.OP_SWAP)
454
+ .add(bsv.Opcode.OP_SUB);
455
+
456
+ script.add(bsv.Opcode.OP_ENDIF);
457
+
458
+ // Add DER sequence formatting
459
+ script.add(bsv.Opcode.OP_SIZE)
460
+ .add(bsv.Opcode.OP_DUP)
461
+ .add(Buffer.from([0x24])) // 36 bytes total length
462
+ .add(bsv.Opcode.OP_ADD)
463
+ .add(Buffer.from([0x30])) // DER sequence tag
464
+ .add(bsv.Opcode.OP_SWAP)
465
+ .add(bsv.Opcode.OP_CAT);
466
+
467
+ // Add r component (using generator x-coordinate as r)
468
+ script.add(Buffer.from('022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179802', 'hex'))
469
+ .add(bsv.Opcode.OP_CAT)
470
+ .add(bsv.Opcode.OP_SWAP)
471
+ .add(bsv.Opcode.OP_CAT)
472
+ .add(bsv.Opcode.OP_SWAP)
473
+ .add(bsv.Opcode.OP_CAT);
474
+ }
475
+
476
+ _addOutputValidation(script, params) {
477
+ const { enforceValue, enforceScript, enforceCount } = params;
478
+
479
+ // Output validation after CHECKSIGVERIFY leaves preimage on stack
480
+ if (enforceValue) {
481
+ script.add(bsv.Opcode.OP_DUP)
482
+ .add(Buffer.from([0x08])) // 8 bytes for value
483
+ .add(bsv.Opcode.OP_SPLIT);
484
+ // Add value enforcement logic
485
+ }
486
+
487
+ if (enforceScript) {
488
+ // Extract and validate locking script
489
+ script.add(bsv.Opcode.OP_DUP)
490
+ .add(bsv.Opcode.OP_SIZE)
491
+ .add(Buffer.from([0x09])) // Skip value + length byte
492
+ .add(bsv.Opcode.OP_SUB)
493
+ .add(bsv.Opcode.OP_SPLIT)
494
+ .add(bsv.Opcode.OP_NIP);
495
+ }
496
+
497
+ if (enforceCount) {
498
+ // Validate number of outputs in hashOutputs
499
+ // This requires parsing the actual outputs, not just hash
500
+ }
501
+ }
502
+
503
+ _addPreimageConstruction(script, params) {
504
+ const {
505
+ version = 1,
506
+ locktime = 0,
507
+ sighashType = 0x41,
508
+ sequence = 0xffffffff
509
+ } = params;
510
+
511
+ // Construct fields for complete BIP143 preimage
512
+ // Items 8-11: sequence, hashOutputs, locktime, sighashType
513
+ script.add(Buffer.from(sequence.toString(16).padStart(8, '0'), 'hex'))
514
+ .add(bsv.Opcode.OP_CAT)
515
+ .add(bsv.Opcode.OP_SWAP) // hashOutputs already computed
516
+ .add(bsv.Opcode.OP_CAT)
517
+ .add(Buffer.from(locktime.toString(16).padStart(8, '0'), 'hex'))
518
+ .add(bsv.Opcode.OP_CAT)
519
+ .add(Buffer.from(sighashType.toString(16).padStart(8, '0'), 'hex'))
520
+ .add(bsv.Opcode.OP_CAT);
521
+ }
522
+
523
+ _addPushtxSignature(script, params) {
524
+ const {
525
+ publicKey = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
526
+ sighashType = 0x41
527
+ } = params;
528
+
529
+ // Generate signature using PUSHTX technique (k=a=1)
530
+ script.add(bsv.Opcode.OP_HASH256);
531
+
532
+ // s = z + Gx mod n (where z = hash256(message), Gx = generator x-coord)
533
+ const generatorX = '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798';
534
+ script.add(Buffer.from(generatorX, 'hex'))
535
+ .add(bsv.Opcode.OP_ADD);
536
+
537
+ // Modular reduction with secp256k1 order
538
+ const secp256k1Order = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
539
+ script.add(Buffer.from(secp256k1Order, 'hex'))
540
+ .add(bsv.Opcode.OP_MOD);
541
+
542
+ // Convert to DER format and verify
543
+ this._addDERConversion(script);
544
+ script.add(Buffer.from([sighashType]))
545
+ .add(bsv.Opcode.OP_CAT)
546
+ .add(Buffer.from(publicKey, 'hex'))
547
+ .add(bsv.Opcode.OP_CHECKSIGVERIFY);
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Enhanced transaction with covenant-specific methods
553
+ */
554
+ class CovenantTransaction {
555
+ constructor(transaction, covenantInterface) {
556
+ this.tx = transaction;
557
+ this.covenant = covenantInterface;
558
+ this.preimages = new Map();
559
+ }
560
+
561
+ /**
562
+ * Get preimage for specific input with caching
563
+ */
564
+ getPreimage(inputIndex, lockingScript, satoshis) {
565
+ const key = `${inputIndex}-${lockingScript.toHex()}-${satoshis}`;
566
+
567
+ if (!this.preimages.has(key)) {
568
+ const preimage = this.covenant.getPreimage(this.tx, inputIndex, lockingScript, satoshis);
569
+ this.preimages.set(key, preimage);
570
+ }
571
+
572
+ return this.preimages.get(key);
573
+ }
574
+
575
+ /**
576
+ * Sign input with covenant-compatible signature
577
+ */
578
+ signInput(inputIndex, privateKey, lockingScript, satoshis) {
579
+ const signature = this.covenant.createSignature(this.tx, privateKey, inputIndex, lockingScript, satoshis);
580
+
581
+ const unlockingScript = new bsv.Script()
582
+ .add(signature)
583
+ .add(privateKey.publicKey.toBuffer());
584
+
585
+ this.tx.inputs[inputIndex].setScript(unlockingScript);
586
+ return this;
587
+ }
588
+
589
+ /**
590
+ * Access underlying BSV transaction
591
+ */
592
+ getTransaction() {
593
+ return this.tx;
594
+ }
595
+
596
+ /**
597
+ * Verify transaction with enhanced error reporting
598
+ */
599
+ verify() {
600
+ try {
601
+ return this.tx.verify();
602
+ } catch (error) {
603
+ console.error('Transaction validation error:', error.message);
604
+ return false;
605
+ }
606
+ }
607
+ }
608
+
609
+ /**
610
+ * Parsed preimage with convenient access methods
611
+ */
612
+ class CovenantPreimage {
613
+ constructor(preimageHex) {
614
+ this.hex = preimageHex;
615
+ this.buffer = Buffer.from(preimageHex, 'hex');
616
+ this.parseFields();
617
+ }
618
+
619
+ parseFields() {
620
+ let offset = 0;
621
+
622
+ // BIP143 sighash preimage structure (detailed field-by-field parsing)
623
+ // Field 1: nVersion (4 bytes, little-endian)
624
+ this.nVersion = this.buffer.subarray(offset, offset + 4);
625
+ this.nVersionValue = this.buffer.readUInt32LE(offset);
626
+ offset += 4;
627
+
628
+ // Field 2: hashPrevouts (32 bytes) - double SHA256 of all input outpoints
629
+ this.hashPrevouts = this.buffer.subarray(offset, offset + 32);
630
+ offset += 32;
631
+
632
+ // Field 3: hashSequence (32 bytes) - double SHA256 of all input sequences
633
+ this.hashSequence = this.buffer.subarray(offset, offset + 32);
634
+ offset += 32;
635
+
636
+ // Field 4: outpoint (36 bytes) - prevTxId (32) + outputIndex (4, little-endian)
637
+ this.outpoint = this.buffer.subarray(offset, offset + 36);
638
+ this.prevTxId = this.buffer.subarray(offset, offset + 32);
639
+ offset += 32;
640
+ this.outputIndex = this.buffer.subarray(offset, offset + 4);
641
+ this.outputIndexValue = this.buffer.readUInt32LE(offset);
642
+ offset += 4;
643
+
644
+ // Field 5: scriptCode - variable length with proper parsing
645
+ const scriptLen = this.readVarInt(offset);
646
+ offset += this.getVarIntLength(scriptLen);
647
+ this.scriptCode = this.buffer.subarray(offset, offset + scriptLen);
648
+ offset += scriptLen;
649
+
650
+ // Field 6: amount (8 bytes, little-endian) - value of UTXO being spent
651
+ this.amount = this.buffer.subarray(offset, offset + 8);
652
+ this.amountValue = this.buffer.readBigUInt64LE(offset);
653
+ offset += 8;
654
+
655
+ // Field 7: nSequence (4 bytes, little-endian)
656
+ this.nSequence = this.buffer.subarray(offset, offset + 4);
657
+ this.nSequenceValue = this.buffer.readUInt32LE(offset);
658
+ offset += 4;
659
+
660
+ // Field 8: hashOutputs (32 bytes) - double SHA256 of all outputs
661
+ this.hashOutputs = this.buffer.subarray(offset, offset + 32);
662
+ offset += 32;
663
+
664
+ // Field 9: nLockTime (4 bytes, little-endian)
665
+ this.nLockTime = this.buffer.subarray(offset, offset + 4);
666
+ this.nLockTimeValue = this.buffer.readUInt32LE(offset);
667
+ offset += 4;
668
+
669
+ // Field 10: sighashType (4 bytes, little-endian)
670
+ this.sighashType = this.buffer.subarray(offset, offset + 4);
671
+ this.sighashTypeValue = this.buffer.readUInt32LE(offset);
672
+ offset += 4;
673
+
674
+ // Validate preimage structure (typical 108+ bytes)
675
+ this.isValid = offset === this.buffer.length && this.buffer.length >= 108;
676
+ }
677
+
678
+ readVarInt(offset) {
679
+ const first = this.buffer.readUInt8(offset);
680
+ if (first < 0xfd) return first;
681
+ if (first === 0xfd) return this.buffer.readUInt16LE(offset + 1);
682
+ if (first === 0xfe) return this.buffer.readUInt32LE(offset + 1);
683
+ if (first === 0xff) return this.buffer.readBigUInt64LE(offset + 1);
684
+ }
685
+
686
+ getVarIntLength(value) {
687
+ if (value < 0xfd) return 1;
688
+ if (value <= 0xffff) return 3;
689
+ if (value <= 0xffffffff) return 5;
690
+ return 9;
691
+ }
692
+ }
693
+
694
+ /**
695
+ * Covenant validation result
696
+ */
697
+ class CovenantValidation {
698
+ constructor(isValid, message) {
699
+ this.isValid = isValid;
700
+ this.message = message;
701
+ }
702
+
703
+ toString() {
704
+ return `${this.isValid ? 'VALID' : 'INVALID'}: ${this.message}`;
705
+ }
706
+ }
707
+
708
+ module.exports = {
709
+ CovenantInterface,
710
+ CovenantTransaction,
711
+ CovenantPreimage,
712
+ CovenantValidation
713
+ };