smartledger-bsv 3.1.0 → 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,512 @@
1
+ /**
2
+ * covenant_builder.js
3
+ * ===================
4
+ *
5
+ * High-level JavaScript API for building Bitcoin SV covenant scripts.
6
+ * This module allows you to write covenant logic in JavaScript and automatically
7
+ * generates the corresponding Bitcoin Script ASM and hex.
8
+ *
9
+ * Features:
10
+ * - JavaScript-to-Bitcoin Script translation
11
+ * - Preimage field extraction utilities
12
+ * - Conditional logic builders
13
+ * - Arithmetic and comparison operations
14
+ * - Data manipulation functions
15
+ * - Template-based covenant patterns
16
+ */
17
+
18
+ 'use strict'
19
+
20
+ const { opcodeMap, scriptNum, utils } = require('./opcode_map')
21
+
22
+ /**
23
+ * CovenantBuilder Class - High-level covenant construction
24
+ */
25
+ class CovenantBuilder {
26
+ constructor() {
27
+ this.operations = []
28
+ this.comments = []
29
+ }
30
+
31
+ /**
32
+ * Add a comment for documentation
33
+ */
34
+ comment(text) {
35
+ this.comments.push(`// ${text}`)
36
+ return this
37
+ }
38
+
39
+ /**
40
+ * Push a value onto the stack
41
+ */
42
+ push(value) {
43
+ if (typeof value === 'number') {
44
+ if (value >= -1 && value <= 16) {
45
+ if (value === -1) {
46
+ this.operations.push('OP_1NEGATE')
47
+ } else if (value === 0) {
48
+ this.operations.push('OP_0')
49
+ } else {
50
+ this.operations.push(`OP_${value}`)
51
+ }
52
+ } else {
53
+ // For larger numbers, push encoded bytes
54
+ const encoded = scriptNum.encode(value)
55
+ this.operations.push(encoded.toString('hex'))
56
+ }
57
+ } else if (typeof value === 'string') {
58
+ // Assume hex string
59
+ this.operations.push(value)
60
+ } else if (Buffer.isBuffer(value)) {
61
+ this.operations.push(value.toString('hex'))
62
+ } else {
63
+ throw new Error(`Invalid value type: ${typeof value}`)
64
+ }
65
+ return this
66
+ }
67
+
68
+ /**
69
+ * Stack manipulation operations
70
+ */
71
+ dup() { this.operations.push('OP_DUP'); return this }
72
+ drop() { this.operations.push('OP_DROP'); return this }
73
+ swap() { this.operations.push('OP_SWAP'); return this }
74
+ over() { this.operations.push('OP_OVER'); return this }
75
+ rot() { this.operations.push('OP_ROT'); return this }
76
+ pick(n) { this.push(n); this.operations.push('OP_PICK'); return this }
77
+ roll(n) { this.push(n); this.operations.push('OP_ROLL'); return this }
78
+ depth() { this.operations.push('OP_DEPTH'); return this }
79
+
80
+ /**
81
+ * Arithmetic operations
82
+ */
83
+ add() { this.operations.push('OP_ADD'); return this }
84
+ sub() { this.operations.push('OP_SUB'); return this }
85
+ mul() { this.operations.push('OP_MUL'); return this }
86
+ div() { this.operations.push('OP_DIV'); return this }
87
+ mod() { this.operations.push('OP_MOD'); return this }
88
+ negate() { this.operations.push('OP_NEGATE'); return this }
89
+ abs() { this.operations.push('OP_ABS'); return this }
90
+ min() { this.operations.push('OP_MIN'); return this }
91
+ max() { this.operations.push('OP_MAX'); return this }
92
+
93
+ /**
94
+ * Comparison operations
95
+ */
96
+ equal() { this.operations.push('OP_EQUAL'); return this }
97
+ equalVerify() { this.operations.push('OP_EQUALVERIFY'); return this }
98
+ numEqual() { this.operations.push('OP_NUMEQUAL'); return this }
99
+ numNotEqual() { this.operations.push('OP_NUMNOTEQUAL'); return this }
100
+ lessThan() { this.operations.push('OP_LESSTHAN'); return this }
101
+ greaterThan() { this.operations.push('OP_GREATERTHAN'); return this }
102
+ lessThanOrEqual() { this.operations.push('OP_LESSTHANOREQUAL'); return this }
103
+ greaterThanOrEqual() { this.operations.push('OP_GREATERTHANOREQUAL'); return this }
104
+ within() { this.operations.push('OP_WITHIN'); return this }
105
+
106
+ /**
107
+ * Logical operations
108
+ */
109
+ not() { this.operations.push('OP_NOT'); return this }
110
+ boolAnd() { this.operations.push('OP_BOOLAND'); return this }
111
+ boolOr() { this.operations.push('OP_BOOLOR'); return this }
112
+
113
+ /**
114
+ * Bitwise operations
115
+ */
116
+ and() { this.operations.push('OP_AND'); return this }
117
+ or() { this.operations.push('OP_OR'); return this }
118
+ xor() { this.operations.push('OP_XOR'); return this }
119
+ invert() { this.operations.push('OP_INVERT'); return this }
120
+
121
+ /**
122
+ * Data manipulation operations
123
+ */
124
+ cat() { this.operations.push('OP_CAT'); return this }
125
+ split() { this.operations.push('OP_SPLIT'); return this }
126
+ size() { this.operations.push('OP_SIZE'); return this }
127
+ left(n) { this.push(n); this.operations.push('OP_LEFT'); return this }
128
+ right(n) { this.push(n); this.operations.push('OP_RIGHT'); return this }
129
+ substr(start, length) {
130
+ this.push(length).push(start)
131
+ this.operations.push('OP_SUBSTR')
132
+ return this
133
+ }
134
+
135
+ /**
136
+ * Cryptographic operations
137
+ */
138
+ sha256() { this.operations.push('OP_SHA256'); return this }
139
+ hash256() { this.operations.push('OP_HASH256'); return this }
140
+ hash160() { this.operations.push('OP_HASH160'); return this }
141
+ ripemd160() { this.operations.push('OP_RIPEMD160'); return this }
142
+
143
+ /**
144
+ * Control flow operations
145
+ */
146
+ verify() { this.operations.push('OP_VERIFY'); return this }
147
+ return() { this.operations.push('OP_RETURN'); return this }
148
+
149
+ /**
150
+ * Preimage field extraction utilities
151
+ */
152
+ extractField(fieldName) {
153
+ this.comment(`Extract ${fieldName} field from preimage`)
154
+
155
+ const fieldMappings = {
156
+ 'nVersion': { strategy: 'LEFT', offset: 0, length: 4 },
157
+ 'hashPrevouts': { strategy: 'LEFT', offset: 4, length: 32 },
158
+ 'hashSequence': { strategy: 'LEFT', offset: 36, length: 32 },
159
+ 'outpoint': { strategy: 'LEFT', offset: 68, length: 36 },
160
+ 'scriptLen': { strategy: 'DYNAMIC', position: 'after_outpoint' },
161
+ 'scriptCode': { strategy: 'DYNAMIC', variable_length: true },
162
+ 'value': { strategy: 'RIGHT', offsetFromEnd: 52, length: 8 },
163
+ 'nSequence': { strategy: 'RIGHT', offsetFromEnd: 44, length: 4 },
164
+ 'hashOutputs': { strategy: 'RIGHT', offsetFromEnd: 40, length: 32 },
165
+ 'nLocktime': { strategy: 'RIGHT', offsetFromEnd: 8, length: 4 },
166
+ 'sighashType': { strategy: 'RIGHT', offsetFromEnd: 4, length: 4 }
167
+ }
168
+
169
+ const field = fieldMappings[fieldName]
170
+ if (!field) {
171
+ throw new Error(`Unknown field: ${fieldName}`)
172
+ }
173
+
174
+ if (field.strategy === 'LEFT') {
175
+ // LEFT extraction: split at offset, take left part, then extract field
176
+ this.push(field.offset + field.length)
177
+ .split()
178
+ .drop() // Drop right part
179
+ .push(field.offset)
180
+ .split()
181
+ .swap()
182
+ .drop() // Drop left padding, keep field
183
+ } else if (field.strategy === 'RIGHT') {
184
+ // RIGHT extraction: calculate split position from end
185
+ this.size()
186
+ .push(field.offsetFromEnd)
187
+ .sub()
188
+ .split()
189
+ .drop() // Drop left part
190
+ .push(field.length)
191
+ .split()
192
+ .drop() // Drop remaining, keep field
193
+ } else if (field.strategy === 'DYNAMIC') {
194
+ if (fieldName === 'scriptLen') {
195
+ // Extract scriptLen (varint after outpoint)
196
+ this.push(104) // Fixed left part (4+32+32+36)
197
+ .split()
198
+ .drop() // Drop left part
199
+ // For now, assume 1-byte varint
200
+ .push(1)
201
+ .split()
202
+ .swap()
203
+ .drop() // Keep just the length byte
204
+ } else {
205
+ throw new Error(`Dynamic extraction for ${fieldName} not implemented`)
206
+ }
207
+ }
208
+
209
+ return this
210
+ }
211
+
212
+ /**
213
+ * Preimage validation patterns
214
+ */
215
+ validateField(fieldName, expectedValue) {
216
+ this.comment(`Validate ${fieldName} equals expected value`)
217
+ this.extractField(fieldName)
218
+ this.push(expectedValue)
219
+ this.equalVerify()
220
+ return this
221
+ }
222
+
223
+ /**
224
+ * Range validation
225
+ */
226
+ validateRange(fieldName, min, max) {
227
+ this.comment(`Validate ${fieldName} is within range [${min}, ${max})`)
228
+ this.extractField(fieldName)
229
+ // Convert to number for comparison
230
+ // Stack: [field_value]
231
+ this.dup()
232
+ this.push(min)
233
+ this.greaterThanOrEqual()
234
+ this.verify() // Ensure >= min
235
+
236
+ this.push(max)
237
+ this.lessThan()
238
+ this.verify() // Ensure < max
239
+
240
+ return this
241
+ }
242
+
243
+ /**
244
+ * Multi-field validation
245
+ */
246
+ validateFields(fieldRules) {
247
+ this.comment('Multi-field validation')
248
+ Object.entries(fieldRules).forEach(([fieldName, rule]) => {
249
+ if (rule.equals) {
250
+ this.validateField(fieldName, rule.equals)
251
+ } else if (rule.min !== undefined || rule.max !== undefined) {
252
+ this.validateRange(fieldName, rule.min || 0, rule.max || Number.MAX_SAFE_INTEGER)
253
+ }
254
+ })
255
+ return this
256
+ }
257
+
258
+ /**
259
+ * Conditional execution helpers
260
+ */
261
+ if(condition) {
262
+ // This is a simplified IF - real implementation would need parser state
263
+ this.comment('Begin IF block')
264
+ if (typeof condition === 'function') {
265
+ condition(this)
266
+ }
267
+ this.operations.push('OP_IF')
268
+ return this
269
+ }
270
+
271
+ else() {
272
+ this.comment('ELSE block')
273
+ this.operations.push('OP_ELSE')
274
+ return this
275
+ }
276
+
277
+ endif() {
278
+ this.comment('End IF block')
279
+ this.operations.push('OP_ENDIF')
280
+ return this
281
+ }
282
+
283
+ /**
284
+ * Build the final script
285
+ */
286
+ build() {
287
+ const asm = this.operations.join(' ')
288
+ const cleanedASM = this._cleanASM(asm)
289
+
290
+ return {
291
+ operations: [...this.operations],
292
+ comments: [...this.comments],
293
+ asm: asm,
294
+ cleanedASM: cleanedASM,
295
+ hex: this._asmToHex(cleanedASM),
296
+ size: cleanedASM.split(' ').length
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Clean ASM for Bitcoin Script execution
302
+ */
303
+ _cleanASM(asm) {
304
+ return asm.split(' ').map(token => {
305
+ // Convert decimal numbers to hex representation
306
+ if (/^\d+$/.test(token)) {
307
+ const num = parseInt(token)
308
+ if (num >= 1 && num <= 75) {
309
+ // Direct push of 1-75 bytes
310
+ return num.toString(16).padStart(2, '0')
311
+ } else {
312
+ // Encode as script number
313
+ return scriptNum.encode(num).toString('hex')
314
+ }
315
+ }
316
+ return token
317
+ }).join(' ')
318
+ }
319
+
320
+ /**
321
+ * Convert ASM to hex (simplified)
322
+ */
323
+ _asmToHex(asm) {
324
+ // This is a simplified implementation
325
+ // Real implementation would use BSV library
326
+ return asm.split(' ').map(token => {
327
+ if (opcodeMap[token]) {
328
+ return opcodeMap[token].code.toString(16).padStart(2, '0')
329
+ } else if (/^[0-9a-fA-F]+$/.test(token)) {
330
+ return token
331
+ } else {
332
+ return '00' // Unknown
333
+ }
334
+ }).join('')
335
+ }
336
+
337
+ /**
338
+ * Simulate execution
339
+ */
340
+ simulate(initialStack = []) {
341
+ return utils.simulate(this.operations, initialStack)
342
+ }
343
+
344
+ /**
345
+ * Generate documentation
346
+ */
347
+ document() {
348
+ const built = this.build()
349
+ return {
350
+ title: 'Covenant Script Documentation',
351
+ operations: built.operations.length,
352
+ size: built.size,
353
+ asm: built.cleanedASM,
354
+ comments: this.comments,
355
+ structure: this._analyzeStructure()
356
+ }
357
+ }
358
+
359
+ _analyzeStructure() {
360
+ const structure = {
361
+ stack_operations: 0,
362
+ arithmetic: 0,
363
+ comparisons: 0,
364
+ crypto: 0,
365
+ data_manipulation: 0,
366
+ flow_control: 0
367
+ }
368
+
369
+ this.operations.forEach(op => {
370
+ const opInfo = opcodeMap[op]
371
+ if (opInfo) {
372
+ switch (opInfo.category) {
373
+ case 'stack': structure.stack_operations++; break
374
+ case 'arithmetic': structure.arithmetic++; break
375
+ case 'bitwise': structure.comparisons++; break
376
+ case 'crypto': structure.crypto++; break
377
+ case 'data': structure.data_manipulation++; break
378
+ case 'flow_control': structure.flow_control++; break
379
+ }
380
+ }
381
+ })
382
+
383
+ return structure
384
+ }
385
+ }
386
+
387
+ /**
388
+ * Factory functions for common covenant patterns
389
+ */
390
+ const CovenantTemplates = {
391
+ /**
392
+ * Value lock covenant - ensures output value matches expected amount
393
+ */
394
+ valueLock: (expectedValue) => {
395
+ return new CovenantBuilder()
396
+ .comment('Value Lock Covenant')
397
+ .comment(`Expected value: ${expectedValue}`)
398
+ .validateField('value', expectedValue)
399
+ .push(1) // Success
400
+ },
401
+
402
+ /**
403
+ * Hash lock covenant - requires preimage that hashes to expected value
404
+ */
405
+ hashLock: (expectedHash) => {
406
+ return new CovenantBuilder()
407
+ .comment('Hash Lock Covenant')
408
+ .comment(`Expected hash: ${expectedHash}`)
409
+ .sha256()
410
+ .push(expectedHash)
411
+ .equalVerify()
412
+ .push(1) // Success
413
+ },
414
+
415
+ /**
416
+ * Multi-signature covenant with field validation
417
+ */
418
+ multiSigWithValidation: (requiredSigs, pubkeys, fieldRules) => {
419
+ const builder = new CovenantBuilder()
420
+ .comment('Multi-Signature Covenant with Field Validation')
421
+ .comment(`Required signatures: ${requiredSigs}`)
422
+
423
+ // Validate fields first
424
+ builder.validateFields(fieldRules)
425
+
426
+ // Then require signatures (simplified)
427
+ builder.comment('Signature validation (placeholder)')
428
+ .push(1) // Success placeholder
429
+
430
+ return builder
431
+ },
432
+
433
+ /**
434
+ * Time-locked covenant
435
+ */
436
+ timeLock: (locktime) => {
437
+ return new CovenantBuilder()
438
+ .comment('Time Lock Covenant')
439
+ .comment(`Locktime: ${locktime}`)
440
+ .validateField('nLocktime', locktime)
441
+ .push(1) // Success
442
+ },
443
+
444
+ /**
445
+ * Complex validation covenant
446
+ */
447
+ complexValidation: (rules) => {
448
+ const builder = new CovenantBuilder()
449
+ .comment('Complex Validation Covenant')
450
+
451
+ // Value range validation
452
+ if (rules.valueRange) {
453
+ builder.validateRange('value', rules.valueRange.min, rules.valueRange.max)
454
+ }
455
+
456
+ // Specific field validations
457
+ if (rules.fields) {
458
+ builder.validateFields(rules.fields)
459
+ }
460
+
461
+ // Hash validation
462
+ if (rules.hashValidation) {
463
+ builder.sha256()
464
+ .push(rules.hashValidation.expectedHash)
465
+ .equalVerify()
466
+ }
467
+
468
+ builder.push(1) // Success
469
+ return builder
470
+ }
471
+ }
472
+
473
+ module.exports = {
474
+ CovenantBuilder,
475
+ CovenantTemplates
476
+ }
477
+
478
+ // CLI demonstration
479
+ if (require.main === module) {
480
+ console.log("šŸ—ļø Covenant Builder Demonstration")
481
+ console.log("==================================")
482
+
483
+ // Example 1: Simple value lock
484
+ console.log("\nšŸ“Š Example 1: Value Lock Covenant")
485
+ const valueLock = CovenantTemplates.valueLock('50c3000000000000')
486
+ const built = valueLock.build()
487
+ console.log("ASM:", built.cleanedASM)
488
+ console.log("Size:", built.size, "operations")
489
+
490
+ // Example 2: Custom covenant
491
+ console.log("\nšŸ“Š Example 2: Custom Arithmetic Covenant")
492
+ const custom = new CovenantBuilder()
493
+ .comment('Validate that value field equals 5 + 3')
494
+ .extractField('value')
495
+ .push(5)
496
+ .push(3)
497
+ .add()
498
+ .numEqual()
499
+ .verify()
500
+ .push(1)
501
+
502
+ const customBuilt = custom.build()
503
+ console.log("Operations:", customBuilt.operations.length)
504
+ console.log("ASM:", customBuilt.cleanedASM)
505
+
506
+ // Example 3: Documentation
507
+ console.log("\nšŸ“Š Example 3: Documentation Generation")
508
+ const docs = custom.document()
509
+ console.log("Structure analysis:", docs.structure)
510
+ console.log("Comments:")
511
+ docs.comments.forEach(comment => console.log(" " + comment))
512
+ }