@smartledger/bsv 3.1.1 → 3.2.1

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 (69) 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 +862 -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 +350 -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_interpreter.js +236 -0
  61. package/lib/smart_contract/script_tester.js +487 -0
  62. package/lib/smart_contract/script_utils.js +621 -0
  63. package/lib/smart_contract/sighash.js +310 -0
  64. package/lib/smart_contract/smartledger-opcode_review.md +70 -0
  65. package/lib/smart_contract/stack_examiner.js +129 -0
  66. package/lib/smart_contract/test_integration.js +269 -0
  67. package/lib/smart_contract/utxo_generator.js +367 -0
  68. package/package.json +43 -10
  69. package/utilities/blockchain-state.json +20478 -3
@@ -0,0 +1,452 @@
1
+ /**
2
+ * SmartContract.Builder Class
3
+ * ============================
4
+ *
5
+ * Advanced covenant builder with:
6
+ * - Multi-field preimage validation
7
+ * - Dynamic script construction
8
+ * - Template-based covenant creation
9
+ * - Complex condition chaining
10
+ *
11
+ * Based on examples/covenants2/covenant_bidirectional_example.js
12
+ */
13
+
14
+ 'use strict'
15
+
16
+ var bsv = require('../..')
17
+
18
+ /**
19
+ * Builder Class - Advanced covenant construction
20
+ * @param {PrivateKey} privateKey - Private key for covenant operations
21
+ * @param {Object} options - Configuration options
22
+ */
23
+ function Builder(privateKey, options) {
24
+ if (!(this instanceof Builder)) {
25
+ return new Builder(privateKey, options)
26
+ }
27
+
28
+ this.privateKey = privateKey
29
+ this.publicKey = privateKey ? privateKey.publicKey : null
30
+ this.options = options || {}
31
+
32
+ // Builder state
33
+ this.conditions = []
34
+ this.preimageFields = []
35
+ this.scriptTemplate = null
36
+ this.validationRules = []
37
+
38
+ this.sighashType = this.options.sighashType ||
39
+ (bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID)
40
+ }
41
+
42
+ /**
43
+ * Add preimage field validation
44
+ * @param {string} field - Preimage field name
45
+ * @param {string|Buffer} expectedValue - Expected value or validation rule
46
+ * @param {Object} options - Validation options
47
+ * @returns {Builder} Builder instance for chaining
48
+ */
49
+ Builder.prototype.validateField = function(field, expectedValue, options) {
50
+ options = options || {}
51
+
52
+ var validation = {
53
+ field: field,
54
+ expectedValue: expectedValue,
55
+ operator: options.operator || 'EQUAL',
56
+ required: options.required !== false,
57
+ description: options.description || 'Validate ' + field
58
+ }
59
+
60
+ this.validationRules.push(validation)
61
+ return this
62
+ }
63
+
64
+ /**
65
+ * Add custom script condition
66
+ * @param {string|Function} condition - Script opcode or custom function
67
+ * @param {Object} options - Condition options
68
+ * @returns {Builder} Builder instance for chaining
69
+ */
70
+ Builder.prototype.addCondition = function(condition, options) {
71
+ options = options || {}
72
+
73
+ var conditionObj = {
74
+ type: typeof condition === 'function' ? 'CUSTOM' : 'OPCODE',
75
+ condition: condition,
76
+ description: options.description || 'Custom condition',
77
+ required: options.required !== false
78
+ }
79
+
80
+ this.conditions.push(conditionObj)
81
+ return this
82
+ }
83
+
84
+ /**
85
+ * Set script template for covenant construction
86
+ * @param {string} template - Script template name or custom script
87
+ * @param {Object} params - Template parameters
88
+ * @returns {Builder} Builder instance for chaining
89
+ */
90
+ Builder.prototype.useTemplate = function(template, params) {
91
+ this.scriptTemplate = {
92
+ name: template,
93
+ params: params || {},
94
+ customScript: typeof template === 'object' ? template : null
95
+ }
96
+ return this
97
+ }
98
+
99
+ /**
100
+ * Build covenant locking script
101
+ * @param {Object} preimageData - Preimage data for validation setup
102
+ * @returns {Script} Constructed locking script
103
+ */
104
+ Builder.prototype.buildLockingScript = function(preimageData) {
105
+ var script = new bsv.Script()
106
+
107
+ if (this.scriptTemplate) {
108
+ return this._buildFromTemplate(preimageData)
109
+ }
110
+
111
+ // Default multi-field validation covenant
112
+ return this._buildMultiFieldCovenant(preimageData)
113
+ }
114
+
115
+ /**
116
+ * Build unlocking script for spending covenant
117
+ * @param {Transaction} spendingTx - Transaction being signed
118
+ * @param {number} inputIndex - Input index
119
+ * @param {Object} covenantData - Original covenant data
120
+ * @returns {Script} Constructed unlocking script
121
+ */
122
+ Builder.prototype.buildUnlockingScript = function(spendingTx, inputIndex, covenantData) {
123
+ var script = new bsv.Script()
124
+
125
+ // Add signature
126
+ var covenantScript = bsv.Script.fromHex(covenantData.script)
127
+ var signature = bsv.Transaction.sighash.sign(
128
+ spendingTx,
129
+ this.privateKey,
130
+ this.sighashType,
131
+ inputIndex,
132
+ covenantScript,
133
+ new bsv.crypto.BN(covenantData.satoshis)
134
+ )
135
+
136
+ var fullSignature = Buffer.concat([
137
+ signature.toDER(),
138
+ Buffer.from([this.sighashType])
139
+ ])
140
+
141
+ script.add(fullSignature)
142
+
143
+ // Add preimage if required
144
+ if (covenantData.originalPreimage) {
145
+ script.add(Buffer.from(covenantData.originalPreimage, 'hex'))
146
+ }
147
+
148
+ // Add any additional unlock conditions
149
+ this.conditions.forEach(function(condition) {
150
+ if (condition.type === 'UNLOCK_DATA') {
151
+ script.add(condition.data)
152
+ }
153
+ })
154
+
155
+ return script
156
+ }
157
+
158
+ /**
159
+ * Create complete covenant from P2PKH
160
+ * @param {Object} utxo - P2PKH UTXO
161
+ * @param {Object} buildOptions - Build options
162
+ * @returns {Object} Created covenant with metadata
163
+ */
164
+ Builder.prototype.createCovenant = function(utxo, buildOptions) {
165
+ buildOptions = buildOptions || {}
166
+
167
+ // Create covenant creation transaction
168
+ var creationTx = new bsv.Transaction()
169
+ .from({
170
+ txId: utxo.txid,
171
+ outputIndex: utxo.vout,
172
+ script: utxo.script,
173
+ satoshis: utxo.satoshis
174
+ })
175
+ .to(this.privateKey.toAddress(), utxo.satoshis - (buildOptions.fee || 1000))
176
+
177
+ // Generate creation preimage
178
+ var p2pkhScript = bsv.Script.fromHex(utxo.script)
179
+ var creationPreimage = bsv.Transaction.sighash.sighashPreimage(
180
+ creationTx,
181
+ this.sighashType,
182
+ 0,
183
+ p2pkhScript,
184
+ new bsv.crypto.BN(utxo.satoshis)
185
+ )
186
+
187
+ // Extract preimage fields for covenant construction
188
+ var Preimage = require('./preimage')
189
+ var preimageObj = new Preimage(creationPreimage)
190
+ var preimageFields = preimageObj.extract()
191
+
192
+ // Build covenant locking script
193
+ var covenantScript = this.buildLockingScript({
194
+ preimage: creationPreimage,
195
+ fields: preimageFields,
196
+ transaction: creationTx
197
+ })
198
+
199
+ // Update transaction output
200
+ creationTx.outputs[0].setScript(covenantScript)
201
+
202
+ // Sign creation transaction
203
+ creationTx.sign(this.privateKey)
204
+
205
+ var covenantUtxo = {
206
+ txid: creationTx.id,
207
+ vout: 0,
208
+ satoshis: utxo.satoshis - (buildOptions.fee || 1000),
209
+ script: covenantScript.toHex(),
210
+ originalPreimage: creationPreimage.toString('hex'),
211
+ preimageFields: preimageFields,
212
+ validationRules: this.validationRules.slice(), // Copy rules
213
+ conditions: this.conditions.slice(), // Copy conditions
214
+ template: this.scriptTemplate,
215
+ createdAt: new Date().toISOString(),
216
+ type: 'builder_covenant'
217
+ }
218
+
219
+ return {
220
+ creationTx: creationTx,
221
+ covenantUtxo: covenantUtxo,
222
+ lockingScript: covenantScript,
223
+ preimageData: {
224
+ preimage: creationPreimage,
225
+ fields: preimageFields
226
+ }
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Validate covenant spending transaction
232
+ * @param {Transaction} spendingTx - Transaction to validate
233
+ * @param {Object} covenantUtxo - Original covenant UTXO
234
+ * @returns {Object} Validation result
235
+ */
236
+ Builder.prototype.validateSpending = function(spendingTx, covenantUtxo) {
237
+ var validation = {
238
+ valid: true,
239
+ errors: [],
240
+ warnings: [],
241
+ fieldValidations: []
242
+ }
243
+
244
+ // Generate spending preimage
245
+ var covenantScript = bsv.Script.fromHex(covenantUtxo.script)
246
+ var spendingPreimage = bsv.Transaction.sighash.sighashPreimage(
247
+ spendingTx,
248
+ this.sighashType,
249
+ 0,
250
+ covenantScript,
251
+ new bsv.crypto.BN(covenantUtxo.satoshis)
252
+ )
253
+
254
+ var Preimage = require('./preimage')
255
+ var preimageObj = new Preimage(spendingPreimage)
256
+ var spendingFields = preimageObj.extract()
257
+
258
+ // Validate against original rules
259
+ if (covenantUtxo.validationRules) {
260
+ covenantUtxo.validationRules.forEach(function(rule) {
261
+ var fieldValidation = this._validateFieldRule(rule, spendingFields, covenantUtxo.preimageFields)
262
+ validation.fieldValidations.push(fieldValidation)
263
+
264
+ if (!fieldValidation.passed && rule.required) {
265
+ validation.valid = false
266
+ validation.errors.push(fieldValidation.error)
267
+ }
268
+ }.bind(this))
269
+ }
270
+
271
+ // Run Script.Interpreter validation
272
+ var interpreter = new bsv.Script.Interpreter()
273
+ var flags = bsv.Script.Interpreter.SCRIPT_VERIFY_P2SH |
274
+ bsv.Script.Interpreter.SCRIPT_VERIFY_STRICTENC |
275
+ bsv.Script.Interpreter.SCRIPT_VERIFY_DERSIG |
276
+ bsv.Script.Interpreter.SCRIPT_VERIFY_LOW_S |
277
+ bsv.Script.Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
278
+
279
+ var unlockingScript = spendingTx.inputs[0].script
280
+ var lockingScript = bsv.Script.fromHex(covenantUtxo.script)
281
+
282
+ var interpreterResult = interpreter.verify(
283
+ unlockingScript,
284
+ lockingScript,
285
+ spendingTx,
286
+ 0,
287
+ flags,
288
+ new bsv.crypto.BN(covenantUtxo.satoshis)
289
+ )
290
+
291
+ if (!interpreterResult) {
292
+ validation.valid = false
293
+ validation.errors.push('Script interpreter validation failed: ' + interpreter.errstr)
294
+ }
295
+
296
+ return validation
297
+ }
298
+
299
+ /**
300
+ * Private helper methods
301
+ */
302
+
303
+ /**
304
+ * Build covenant from template
305
+ * @private
306
+ */
307
+ Builder.prototype._buildFromTemplate = function(preimageData) {
308
+ var template = this.scriptTemplate
309
+
310
+ if (template.name === 'HASH_LOCK') {
311
+ return this._buildHashLockTemplate(preimageData, template.params)
312
+ } else if (template.name === 'MULTI_FIELD') {
313
+ return this._buildMultiFieldTemplate(preimageData, template.params)
314
+ } else if (template.customScript) {
315
+ return template.customScript
316
+ }
317
+
318
+ throw new Error('Unknown template: ' + template.name)
319
+ }
320
+
321
+ /**
322
+ * Build multi-field validation covenant
323
+ * @private
324
+ */
325
+ Builder.prototype._buildMultiFieldCovenant = function(preimageData) {
326
+ var script = new bsv.Script()
327
+
328
+ // Duplicate preimage for multiple validations
329
+ script.add('OP_DUP')
330
+
331
+ // Add field validation opcodes based on rules
332
+ this.validationRules.forEach(function(rule, index) {
333
+ if (index > 0) script.add('OP_DUP') // Duplicate for next validation
334
+
335
+ script.add('OP_HASH256')
336
+
337
+ if (rule.expectedValue) {
338
+ var expectedHash = bsv.crypto.Hash.sha256sha256(Buffer.from(rule.expectedValue, 'hex'))
339
+ script.add(expectedHash)
340
+ script.add('OP_EQUALVERIFY')
341
+ }
342
+ })
343
+
344
+ // Clean up stack and add signature check
345
+ script.add('OP_DROP')
346
+
347
+ if (this.publicKey) {
348
+ script.add(this.publicKey.toBuffer())
349
+ script.add('OP_CHECKSIG')
350
+ }
351
+
352
+ return script
353
+ }
354
+
355
+ /**
356
+ * Build hash lock template
357
+ * @private
358
+ */
359
+ Builder.prototype._buildHashLockTemplate = function(preimageData, params) {
360
+ var script = new bsv.Script()
361
+
362
+ script.add('OP_DUP')
363
+ script.add('OP_HASH256')
364
+
365
+ var expectedHash = params.hash || bsv.crypto.Hash.sha256sha256(preimageData.preimage)
366
+ script.add(expectedHash)
367
+ script.add('OP_EQUALVERIFY')
368
+ script.add('OP_DROP')
369
+
370
+ if (this.publicKey) {
371
+ script.add(this.publicKey.toBuffer())
372
+ script.add('OP_CHECKSIG')
373
+ }
374
+
375
+ return script
376
+ }
377
+
378
+ /**
379
+ * Validate individual field rule
380
+ * @private
381
+ */
382
+ Builder.prototype._validateFieldRule = function(rule, spendingFields, originalFields) {
383
+ var fieldValue = spendingFields[rule.field]
384
+ var expectedValue = rule.expectedValue
385
+
386
+ // If expected value references original field
387
+ if (typeof expectedValue === 'string' && expectedValue.startsWith('ORIGINAL_')) {
388
+ var originalField = expectedValue.replace('ORIGINAL_', '')
389
+ expectedValue = originalFields[originalField]
390
+ }
391
+
392
+ var passed = false
393
+ var error = null
394
+
395
+ switch (rule.operator) {
396
+ case 'EQUAL':
397
+ passed = fieldValue && fieldValue.equals ? fieldValue.equals(expectedValue) : fieldValue === expectedValue
398
+ if (!passed) error = rule.field + ' does not equal expected value'
399
+ break
400
+ case 'NOT_EQUAL':
401
+ passed = fieldValue && fieldValue.equals ? !fieldValue.equals(expectedValue) : fieldValue !== expectedValue
402
+ if (!passed) error = rule.field + ' should not equal specified value'
403
+ break
404
+ case 'PRESENT':
405
+ passed = !!fieldValue
406
+ if (!passed) error = rule.field + ' is required but not present'
407
+ break
408
+ default:
409
+ error = 'Unknown validation operator: ' + rule.operator
410
+ }
411
+
412
+ return {
413
+ field: rule.field,
414
+ operator: rule.operator,
415
+ passed: passed,
416
+ error: error,
417
+ description: rule.description
418
+ }
419
+ }
420
+
421
+ /**
422
+ * Static utility methods
423
+ */
424
+
425
+ /**
426
+ * Create simple hash-lock covenant builder
427
+ * @param {PrivateKey} privateKey - Private key for covenant
428
+ * @param {Buffer} expectedHash - Expected preimage hash
429
+ * @returns {Builder} Configured builder
430
+ */
431
+ Builder.createHashLock = function(privateKey, expectedHash) {
432
+ return new Builder(privateKey)
433
+ .useTemplate('HASH_LOCK', { hash: expectedHash })
434
+ }
435
+
436
+ /**
437
+ * Create multi-field validation covenant builder
438
+ * @param {PrivateKey} privateKey - Private key for covenant
439
+ * @param {Array} fieldRules - Array of field validation rules
440
+ * @returns {Builder} Configured builder
441
+ */
442
+ Builder.createMultiField = function(privateKey, fieldRules) {
443
+ var builder = new Builder(privateKey)
444
+
445
+ fieldRules.forEach(function(rule) {
446
+ builder.validateField(rule.field, rule.expectedValue, rule.options)
447
+ })
448
+
449
+ return builder
450
+ }
451
+
452
+ module.exports = Builder