@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.
- package/CHANGELOG.md +123 -1
- package/README.md +233 -277
- package/bsv.bundle.js +39 -0
- package/bsv.min.js +8 -8
- package/docs/ADVANCED_COVENANT_DEVELOPMENT.md +533 -0
- package/docs/COVENANT_DEVELOPMENT_RESOLVED.md +169 -0
- package/docs/CUSTOM_SCRIPT_DEVELOPMENT.md +320 -0
- package/docs/README.md +201 -0
- package/docs/block.md +46 -0
- package/docs/ecies.md +102 -0
- package/docs/index.md +104 -0
- package/docs/nchain.md +958 -0
- package/docs/networks.md +55 -0
- package/docs/preimage.md +126 -0
- package/docs/script.md +139 -0
- package/docs/transaction.md +174 -0
- package/docs/unspentoutput.md +32 -0
- package/examples/README.md +200 -0
- package/examples/basic/transaction-creation.js +534 -0
- package/examples/basic/transaction_signature_api_gap.js +178 -0
- package/examples/covenants/advanced_covenant_demo.js +219 -0
- package/examples/covenants/covenant_interface_demo.js +270 -0
- package/examples/covenants/covenant_manual_signature_resolved.js +212 -0
- package/examples/covenants/covenant_signature_template.js +117 -0
- package/examples/covenants2/covenant_bidirectional_example.js +262 -0
- package/examples/covenants2/covenant_utils_demo.js +120 -0
- package/examples/covenants2/preimage_covenant_utils.js +287 -0
- package/examples/covenants2/production_integration.js +256 -0
- package/examples/data/covenant_utxos.json +28 -0
- package/examples/data/utxos.json +26 -0
- package/examples/preimage/README.md +178 -0
- package/examples/preimage/extract_preimage_bidirectional.js +421 -0
- package/examples/preimage/generate_sample_preimage.js +208 -0
- package/examples/preimage/generate_sighash_examples.js +152 -0
- package/examples/preimage/parse_preimage.js +117 -0
- package/examples/preimage/test_preimage_extractor.js +53 -0
- package/examples/preimage/test_varint_extraction.js +95 -0
- package/examples/scripts/custom_script_helper_example.js +273 -0
- package/examples/scripts/custom_script_signature_test.js +344 -0
- package/examples/scripts/script_interpreter.js +193 -0
- package/examples/smart_contract/complete_workflow_demo.js +343 -0
- package/examples/smart_contract/covenant_builder_demo.js +176 -0
- package/examples/smart_contract/script_testing_integration.js +198 -0
- package/index.js +3 -0
- package/lib/covenant-interface.js +713 -0
- package/lib/opcode.js +14 -7
- package/lib/smart_contract/API_REFERENCE.md +862 -0
- package/lib/smart_contract/DOCUMENTATION_SUMMARY.md +201 -0
- package/lib/smart_contract/EXAMPLES.md +751 -0
- package/lib/smart_contract/QUICK_START.md +549 -0
- package/lib/smart_contract/README.md +395 -0
- package/lib/smart_contract/builder.js +452 -0
- package/lib/smart_contract/covenant.js +336 -0
- package/lib/smart_contract/covenant_builder.js +512 -0
- package/lib/smart_contract/index.js +350 -0
- package/lib/smart_contract/opcode_list.js +30 -0
- package/lib/smart_contract/opcode_map.js +1174 -0
- package/lib/smart_contract/opcodes.md +1173 -0
- package/lib/smart_contract/preimage.js +903 -0
- package/lib/smart_contract/script_interpreter.js +236 -0
- package/lib/smart_contract/script_tester.js +487 -0
- package/lib/smart_contract/script_utils.js +621 -0
- package/lib/smart_contract/sighash.js +310 -0
- package/lib/smart_contract/smartledger-opcode_review.md +70 -0
- package/lib/smart_contract/stack_examiner.js +129 -0
- package/lib/smart_contract/test_integration.js +269 -0
- package/lib/smart_contract/utxo_generator.js +367 -0
- package/package.json +43 -10
- package/utilities/blockchain-state.json +20478 -3
|
@@ -0,0 +1,751 @@
|
|
|
1
|
+
# SmartContract Practical Examples
|
|
2
|
+
|
|
3
|
+
**SmartLedger-BSV v3.2.0** - Real-world covenant implementation examples
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Basic Examples](#basic-examples)
|
|
8
|
+
2. [Financial Covenants](#financial-covenants)
|
|
9
|
+
3. [Security Patterns](#security-patterns)
|
|
10
|
+
4. [Advanced Use Cases](#advanced-use-cases)
|
|
11
|
+
5. [Production Integration](#production-integration)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Basic Examples
|
|
16
|
+
|
|
17
|
+
### Example 1: Simple Value Check
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
const SmartContract = require('bsv-elliptic-fix').SmartContract
|
|
21
|
+
|
|
22
|
+
// Ensure transaction maintains minimum value
|
|
23
|
+
function createValueGuard(minimumSatoshis) {
|
|
24
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
25
|
+
|
|
26
|
+
return builder
|
|
27
|
+
.comment(`Value guard: minimum ${minimumSatoshis} satoshis`)
|
|
28
|
+
.extractField('value')
|
|
29
|
+
.push(minimumSatoshis.toString(16).padStart(16, '0'))
|
|
30
|
+
.greaterThanOrEqual()
|
|
31
|
+
.verify()
|
|
32
|
+
.build()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Usage
|
|
36
|
+
const covenant = createValueGuard(1000000) // 1M satoshi minimum
|
|
37
|
+
console.log('ASM:', covenant.cleanedASM)
|
|
38
|
+
|
|
39
|
+
// Test the covenant
|
|
40
|
+
const simulation = SmartContract.simulateScript(covenant.operations)
|
|
41
|
+
console.log('Valid:', simulation.success)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Example 2: Hash Preimage Validation
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
// Require knowledge of secret to spend
|
|
48
|
+
function createHashLock(secretHash) {
|
|
49
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
50
|
+
|
|
51
|
+
return builder
|
|
52
|
+
.comment('Hash lock: requires secret preimage')
|
|
53
|
+
.push('secret_placeholder') // Will be replaced with actual secret
|
|
54
|
+
.sha256()
|
|
55
|
+
.push(secretHash)
|
|
56
|
+
.equalVerify()
|
|
57
|
+
.build()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Usage
|
|
61
|
+
const secret = 'my_secret_key'
|
|
62
|
+
const secretHash = require('crypto')
|
|
63
|
+
.createHash('sha256')
|
|
64
|
+
.update(secret)
|
|
65
|
+
.digest('hex')
|
|
66
|
+
|
|
67
|
+
const hashLock = createHashLock(secretHash)
|
|
68
|
+
console.log('Hash lock ASM:', hashLock.cleanedASM)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Financial Covenants
|
|
74
|
+
|
|
75
|
+
### Example 3: Recurring Payment Covenant
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
// Covenant that enforces regular payments to a recipient
|
|
79
|
+
function createRecurringPayment(recipientAddress, paymentAmount, intervalBlocks) {
|
|
80
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
81
|
+
|
|
82
|
+
return builder
|
|
83
|
+
.comment('Recurring payment covenant')
|
|
84
|
+
.comment(`Payment: ${paymentAmount} satoshis every ${intervalBlocks} blocks`)
|
|
85
|
+
|
|
86
|
+
// Check time interval
|
|
87
|
+
.extractField('nLockTime')
|
|
88
|
+
.push('last_payment_time') // Track last payment
|
|
89
|
+
.sub()
|
|
90
|
+
.push(intervalBlocks.toString())
|
|
91
|
+
.greaterThanOrEqual()
|
|
92
|
+
.verify()
|
|
93
|
+
|
|
94
|
+
// Ensure correct payment amount to recipient
|
|
95
|
+
.extractField('hashOutputs')
|
|
96
|
+
.comment('Validate payment output')
|
|
97
|
+
.push(paymentAmount.toString(16).padStart(16, '0'))
|
|
98
|
+
.push(recipientAddress)
|
|
99
|
+
.cat() // Combine amount + address
|
|
100
|
+
.sha256()
|
|
101
|
+
.equalVerify()
|
|
102
|
+
|
|
103
|
+
.build()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Usage
|
|
107
|
+
const recurringPayment = createRecurringPayment(
|
|
108
|
+
'recipient_address_hash',
|
|
109
|
+
50000, // 50k satoshis per payment
|
|
110
|
+
144 // Daily payments (144 blocks ≈ 1 day)
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Example 4: Escrow with Dispute Resolution
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
// Three-party escrow with dispute resolution
|
|
118
|
+
function createEscrowCovenant(buyerPubKey, sellerPubKey, arbitratorPubKey, escrowAmount) {
|
|
119
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
120
|
+
|
|
121
|
+
return builder
|
|
122
|
+
.comment('Three-party escrow covenant')
|
|
123
|
+
.comment('Requires 2-of-3 signatures for release')
|
|
124
|
+
|
|
125
|
+
// Path 1: Buyer + Seller agree (no arbitrator needed)
|
|
126
|
+
.push('buyer_signature_placeholder')
|
|
127
|
+
.push(buyerPubKey)
|
|
128
|
+
// ... signature verification ...
|
|
129
|
+
|
|
130
|
+
.push('seller_signature_placeholder')
|
|
131
|
+
.push(sellerPubKey)
|
|
132
|
+
// ... signature verification ...
|
|
133
|
+
|
|
134
|
+
.push(2) // Require 2 valid signatures
|
|
135
|
+
.equal()
|
|
136
|
+
|
|
137
|
+
// OR Path 2: Any 2 parties including arbitrator
|
|
138
|
+
.if()
|
|
139
|
+
.push(1) // Valid 2-party agreement
|
|
140
|
+
.else()
|
|
141
|
+
.comment('Dispute resolution path')
|
|
142
|
+
// ... arbitrator signature logic ...
|
|
143
|
+
.endif()
|
|
144
|
+
|
|
145
|
+
.verify()
|
|
146
|
+
.build()
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Example 5: Savings Account with Withdrawal Limits
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
// Savings account with daily withdrawal limits
|
|
154
|
+
function createSavingsAccount(dailyLimit, lastWithdrawalTime) {
|
|
155
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
156
|
+
|
|
157
|
+
return builder
|
|
158
|
+
.comment('Savings account with withdrawal limits')
|
|
159
|
+
|
|
160
|
+
// Check if 24 hours have passed since last withdrawal
|
|
161
|
+
.extractField('nLockTime')
|
|
162
|
+
.push(lastWithdrawalTime)
|
|
163
|
+
.sub()
|
|
164
|
+
.push('86400') // 24 hours in seconds
|
|
165
|
+
.greaterThanOrEqual()
|
|
166
|
+
|
|
167
|
+
.if()
|
|
168
|
+
.comment('Daily limit reset - allow withdrawal')
|
|
169
|
+
.extractField('value')
|
|
170
|
+
.push(dailyLimit.toString())
|
|
171
|
+
.lessThanOrEqual()
|
|
172
|
+
.verify()
|
|
173
|
+
.else()
|
|
174
|
+
.comment('Within 24 hours - no withdrawal allowed')
|
|
175
|
+
.push(0)
|
|
176
|
+
.verify() // Will fail, preventing withdrawal
|
|
177
|
+
.endif()
|
|
178
|
+
|
|
179
|
+
.build()
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Security Patterns
|
|
186
|
+
|
|
187
|
+
### Example 6: Multi-Factor Authentication Covenant
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
// Covenant requiring multiple authentication factors
|
|
191
|
+
function createMFACovenant(ownerPubKey, deviceHash, locationHash) {
|
|
192
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
193
|
+
|
|
194
|
+
return builder
|
|
195
|
+
.comment('Multi-factor authentication covenant')
|
|
196
|
+
|
|
197
|
+
// Factor 1: Owner signature
|
|
198
|
+
.push('owner_signature_placeholder')
|
|
199
|
+
.push(ownerPubKey)
|
|
200
|
+
// ... signature verification ...
|
|
201
|
+
|
|
202
|
+
// Factor 2: Device authentication
|
|
203
|
+
.push('device_token_placeholder')
|
|
204
|
+
.sha256()
|
|
205
|
+
.push(deviceHash)
|
|
206
|
+
.equalVerify()
|
|
207
|
+
|
|
208
|
+
// Factor 3: Location verification (IP/GPS hash)
|
|
209
|
+
.push('location_data_placeholder')
|
|
210
|
+
.sha256()
|
|
211
|
+
.push(locationHash)
|
|
212
|
+
.equalVerify()
|
|
213
|
+
|
|
214
|
+
.comment('All factors verified')
|
|
215
|
+
.build()
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Example 7: Rate-Limited Spending
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
// Prevent rapid spending attacks
|
|
223
|
+
function createRateLimitedCovenant(spendingRate, timeWindow) {
|
|
224
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
225
|
+
|
|
226
|
+
return builder
|
|
227
|
+
.comment(`Rate limit: ${spendingRate} per ${timeWindow} seconds`)
|
|
228
|
+
|
|
229
|
+
// Track spending within time window
|
|
230
|
+
.extractField('nLockTime')
|
|
231
|
+
.push('window_start_time')
|
|
232
|
+
.sub()
|
|
233
|
+
.push(timeWindow.toString())
|
|
234
|
+
.lessThan()
|
|
235
|
+
|
|
236
|
+
.if()
|
|
237
|
+
.comment('Within time window - check rate limit')
|
|
238
|
+
.push('current_spending_amount')
|
|
239
|
+
.push(spendingRate.toString())
|
|
240
|
+
.lessThanOrEqual()
|
|
241
|
+
.verify()
|
|
242
|
+
.else()
|
|
243
|
+
.comment('New time window - reset rate limit')
|
|
244
|
+
.push(1) // Always allow first transaction in new window
|
|
245
|
+
.verify()
|
|
246
|
+
.endif()
|
|
247
|
+
|
|
248
|
+
.build()
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Example 8: Dead Man's Switch
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
// Automatically transfer funds if owner doesn't check in
|
|
256
|
+
function createDeadManSwitch(beneficiaryAddress, checkInInterval) {
|
|
257
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
258
|
+
|
|
259
|
+
return builder
|
|
260
|
+
.comment('Dead man\'s switch covenant')
|
|
261
|
+
.comment(`Auto-transfer if no activity for ${checkInInterval} blocks`)
|
|
262
|
+
|
|
263
|
+
// Check time since last owner activity
|
|
264
|
+
.extractField('nLockTime')
|
|
265
|
+
.push('last_checkin_time')
|
|
266
|
+
.sub()
|
|
267
|
+
.push(checkInInterval.toString())
|
|
268
|
+
.greaterThan()
|
|
269
|
+
|
|
270
|
+
.if()
|
|
271
|
+
.comment('Timeout reached - transfer to beneficiary')
|
|
272
|
+
.extractField('hashOutputs')
|
|
273
|
+
.push(beneficiaryAddress)
|
|
274
|
+
.equalVerify() // Ensure funds go to beneficiary
|
|
275
|
+
.else()
|
|
276
|
+
.comment('Owner still active - normal spending rules')
|
|
277
|
+
// ... owner signature verification ...
|
|
278
|
+
.endif()
|
|
279
|
+
|
|
280
|
+
.build()
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Advanced Use Cases
|
|
287
|
+
|
|
288
|
+
### Example 9: Decentralized Exchange Covenant
|
|
289
|
+
|
|
290
|
+
```javascript
|
|
291
|
+
// Atomic swap covenant for decentralized exchange
|
|
292
|
+
function createAtomicSwapCovenant(counterpartyPubKey, exchangeRate, timeoutBlocks) {
|
|
293
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
294
|
+
|
|
295
|
+
return builder
|
|
296
|
+
.comment('Atomic swap covenant')
|
|
297
|
+
.comment(`Exchange rate: ${exchangeRate}, Timeout: ${timeoutBlocks} blocks`)
|
|
298
|
+
|
|
299
|
+
// Path 1: Successful swap
|
|
300
|
+
.push('swap_secret_placeholder')
|
|
301
|
+
.sha256()
|
|
302
|
+
.push('expected_secret_hash')
|
|
303
|
+
.equal()
|
|
304
|
+
|
|
305
|
+
.if()
|
|
306
|
+
.comment('Secret revealed - complete swap')
|
|
307
|
+
.push('counterparty_signature_placeholder')
|
|
308
|
+
.push(counterpartyPubKey)
|
|
309
|
+
// ... signature verification ...
|
|
310
|
+
|
|
311
|
+
// Verify exchange rate
|
|
312
|
+
.extractField('value')
|
|
313
|
+
.push(exchangeRate.toString())
|
|
314
|
+
.mul()
|
|
315
|
+
.push('expected_output_value')
|
|
316
|
+
.equalVerify()
|
|
317
|
+
|
|
318
|
+
.else()
|
|
319
|
+
.comment('Timeout path - refund original owner')
|
|
320
|
+
.extractField('nLockTime')
|
|
321
|
+
.push(timeoutBlocks.toString())
|
|
322
|
+
.greaterThan()
|
|
323
|
+
.verify()
|
|
324
|
+
|
|
325
|
+
// ... owner signature verification for refund ...
|
|
326
|
+
.endif()
|
|
327
|
+
|
|
328
|
+
.build()
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Example 10: Supply Chain Tracking Covenant
|
|
333
|
+
|
|
334
|
+
```javascript
|
|
335
|
+
// Track product ownership through supply chain
|
|
336
|
+
function createSupplyChainCovenant(productId, currentOwner, nextOwner) {
|
|
337
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
338
|
+
|
|
339
|
+
return builder
|
|
340
|
+
.comment('Supply chain tracking covenant')
|
|
341
|
+
.comment(`Product: ${productId}`)
|
|
342
|
+
|
|
343
|
+
// Verify product ID hasn't changed
|
|
344
|
+
.push(productId)
|
|
345
|
+
.extractField('scriptCode')
|
|
346
|
+
.push(0) // Product ID at position 0
|
|
347
|
+
.push(32) // 32 bytes for product ID
|
|
348
|
+
.substr()
|
|
349
|
+
.equalVerify()
|
|
350
|
+
|
|
351
|
+
// Verify ownership transfer signature
|
|
352
|
+
.push('transfer_signature_placeholder')
|
|
353
|
+
.push(currentOwner)
|
|
354
|
+
// ... signature verification ...
|
|
355
|
+
|
|
356
|
+
// Update ownership record
|
|
357
|
+
.push(nextOwner)
|
|
358
|
+
.push('ownership_updated')
|
|
359
|
+
.cat()
|
|
360
|
+
.sha256()
|
|
361
|
+
|
|
362
|
+
// Create new covenant with updated owner
|
|
363
|
+
.build()
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Example 11: Subscription Service Covenant
|
|
368
|
+
|
|
369
|
+
```javascript
|
|
370
|
+
// Recurring subscription with auto-renewal
|
|
371
|
+
function createSubscriptionCovenant(serviceProvider, subscriptionFee, renewalPeriod) {
|
|
372
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
373
|
+
|
|
374
|
+
return builder
|
|
375
|
+
.comment('Subscription service covenant')
|
|
376
|
+
.comment(`Fee: ${subscriptionFee}, Period: ${renewalPeriod} blocks`)
|
|
377
|
+
|
|
378
|
+
// Check if renewal period has elapsed
|
|
379
|
+
.extractField('nLockTime')
|
|
380
|
+
.push('last_payment_time')
|
|
381
|
+
.sub()
|
|
382
|
+
.push(renewalPeriod.toString())
|
|
383
|
+
.greaterThanOrEqual()
|
|
384
|
+
|
|
385
|
+
.if()
|
|
386
|
+
.comment('Renewal due - process payment')
|
|
387
|
+
.extractField('hashOutputs')
|
|
388
|
+
|
|
389
|
+
// Payment to service provider
|
|
390
|
+
.push(subscriptionFee.toString(16).padStart(16, '0'))
|
|
391
|
+
.push(serviceProvider)
|
|
392
|
+
.cat()
|
|
393
|
+
.sha256()
|
|
394
|
+
|
|
395
|
+
// Remaining funds continue subscription
|
|
396
|
+
.extractField('value')
|
|
397
|
+
.push(subscriptionFee.toString())
|
|
398
|
+
.sub()
|
|
399
|
+
.push('continuation_covenant_hash')
|
|
400
|
+
.cat()
|
|
401
|
+
.sha256()
|
|
402
|
+
|
|
403
|
+
.equalVerify()
|
|
404
|
+
|
|
405
|
+
.else()
|
|
406
|
+
.comment('Subscription active - no payment due')
|
|
407
|
+
.push(1)
|
|
408
|
+
.verify()
|
|
409
|
+
.endif()
|
|
410
|
+
|
|
411
|
+
.build()
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
## Production Integration
|
|
418
|
+
|
|
419
|
+
### Example 12: Complete Covenant Deployment
|
|
420
|
+
|
|
421
|
+
```javascript
|
|
422
|
+
const bsv = require('bsv-elliptic-fix')
|
|
423
|
+
const SmartContract = bsv.SmartContract
|
|
424
|
+
|
|
425
|
+
async function deployValueLockCovenant(privateKey, minimumValue, utxo) {
|
|
426
|
+
try {
|
|
427
|
+
// 1. Create covenant script
|
|
428
|
+
const builder = SmartContract.createCovenantBuilder()
|
|
429
|
+
const covenant = builder
|
|
430
|
+
.comment('Production value lock covenant')
|
|
431
|
+
.extractField('value')
|
|
432
|
+
.push(minimumValue.toString(16).padStart(16, '0'))
|
|
433
|
+
.greaterThanOrEqual()
|
|
434
|
+
.verify()
|
|
435
|
+
.build()
|
|
436
|
+
|
|
437
|
+
// 2. Test covenant locally
|
|
438
|
+
console.log('Testing covenant...')
|
|
439
|
+
const simulation = SmartContract.simulateScript(covenant.operations)
|
|
440
|
+
if (!simulation.success) {
|
|
441
|
+
throw new Error(`Covenant validation failed: ${simulation.error}`)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// 3. Create P2SH address for covenant
|
|
445
|
+
const script = bsv.Script.fromASM(covenant.cleanedASM)
|
|
446
|
+
const address = script.toAddress()
|
|
447
|
+
|
|
448
|
+
// 4. Create transaction to fund covenant
|
|
449
|
+
const tx = new bsv.Transaction()
|
|
450
|
+
.from(utxo)
|
|
451
|
+
.to(address, utxo.satoshis - 1000) // Leave 1000 sats for fee
|
|
452
|
+
.sign(privateKey)
|
|
453
|
+
|
|
454
|
+
// 5. Broadcast transaction
|
|
455
|
+
console.log('Broadcasting covenant creation transaction...')
|
|
456
|
+
const result = await broadcastTransaction(tx)
|
|
457
|
+
|
|
458
|
+
console.log('✅ Covenant deployed successfully!')
|
|
459
|
+
console.log('Covenant address:', address.toString())
|
|
460
|
+
console.log('Transaction ID:', result.txid)
|
|
461
|
+
console.log('Covenant script:', covenant.cleanedASM)
|
|
462
|
+
|
|
463
|
+
return {
|
|
464
|
+
success: true,
|
|
465
|
+
address: address.toString(),
|
|
466
|
+
txid: result.txid,
|
|
467
|
+
script: covenant.cleanedASM
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
} catch (error) {
|
|
471
|
+
console.log('❌ Deployment failed:', error.message)
|
|
472
|
+
return {
|
|
473
|
+
success: false,
|
|
474
|
+
error: error.message
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Usage
|
|
480
|
+
async function main() {
|
|
481
|
+
const privateKey = bsv.PrivateKey.fromWIF('your_private_key_wif')
|
|
482
|
+
const utxo = {
|
|
483
|
+
txid: 'your_utxo_txid',
|
|
484
|
+
vout: 0,
|
|
485
|
+
satoshis: 100000,
|
|
486
|
+
script: 'your_utxo_script'
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const result = await deployValueLockCovenant(privateKey, 50000, utxo)
|
|
490
|
+
console.log('Deployment result:', result)
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Example 13: Covenant Testing Framework
|
|
495
|
+
|
|
496
|
+
```javascript
|
|
497
|
+
// Comprehensive testing framework for covenants
|
|
498
|
+
class CovenantTester {
|
|
499
|
+
constructor() {
|
|
500
|
+
this.testResults = []
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Test covenant with various scenarios
|
|
504
|
+
async testCovenant(covenant, testCases) {
|
|
505
|
+
console.log('🧪 Starting covenant test suite...')
|
|
506
|
+
|
|
507
|
+
for (const testCase of testCases) {
|
|
508
|
+
try {
|
|
509
|
+
const result = await this.runTestCase(covenant, testCase)
|
|
510
|
+
this.testResults.push(result)
|
|
511
|
+
|
|
512
|
+
if (result.success) {
|
|
513
|
+
console.log(`✅ ${testCase.name}: PASSED`)
|
|
514
|
+
} else {
|
|
515
|
+
console.log(`❌ ${testCase.name}: FAILED - ${result.error}`)
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
} catch (error) {
|
|
519
|
+
console.log(`💥 ${testCase.name}: ERROR - ${error.message}`)
|
|
520
|
+
this.testResults.push({
|
|
521
|
+
name: testCase.name,
|
|
522
|
+
success: false,
|
|
523
|
+
error: error.message
|
|
524
|
+
})
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return this.generateReport()
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
async runTestCase(covenant, testCase) {
|
|
532
|
+
// Create test environment
|
|
533
|
+
const testEnv = SmartContract.createTestEnvironment()
|
|
534
|
+
|
|
535
|
+
// Simulate covenant with test data
|
|
536
|
+
const simulation = SmartContract.simulateScript(
|
|
537
|
+
covenant.operations,
|
|
538
|
+
testCase.initialStack || []
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
// Validate expected outcome
|
|
542
|
+
const expectedSuccess = testCase.expectedSuccess !== false
|
|
543
|
+
const actualSuccess = simulation.success
|
|
544
|
+
|
|
545
|
+
if (expectedSuccess === actualSuccess) {
|
|
546
|
+
return {
|
|
547
|
+
name: testCase.name,
|
|
548
|
+
success: true,
|
|
549
|
+
simulation: simulation
|
|
550
|
+
}
|
|
551
|
+
} else {
|
|
552
|
+
return {
|
|
553
|
+
name: testCase.name,
|
|
554
|
+
success: false,
|
|
555
|
+
error: `Expected ${expectedSuccess ? 'success' : 'failure'}, got ${actualSuccess ? 'success' : 'failure'}`,
|
|
556
|
+
simulation: simulation
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
generateReport() {
|
|
562
|
+
const total = this.testResults.length
|
|
563
|
+
const passed = this.testResults.filter(r => r.success).length
|
|
564
|
+
const failed = total - passed
|
|
565
|
+
|
|
566
|
+
console.log('\n📊 Test Report:')
|
|
567
|
+
console.log(`Total tests: ${total}`)
|
|
568
|
+
console.log(`Passed: ${passed}`)
|
|
569
|
+
console.log(`Failed: ${failed}`)
|
|
570
|
+
console.log(`Success rate: ${((passed / total) * 100).toFixed(1)}%`)
|
|
571
|
+
|
|
572
|
+
return {
|
|
573
|
+
total,
|
|
574
|
+
passed,
|
|
575
|
+
failed,
|
|
576
|
+
successRate: (passed / total) * 100,
|
|
577
|
+
results: this.testResults
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Usage example
|
|
583
|
+
async function testValueLockCovenant() {
|
|
584
|
+
const covenant = SmartContract.createValueLockCovenant('1000000')
|
|
585
|
+
const tester = new CovenantTester()
|
|
586
|
+
|
|
587
|
+
const testCases = [
|
|
588
|
+
{
|
|
589
|
+
name: 'Valid high value transaction',
|
|
590
|
+
initialStack: ['2000000'], // 2M satoshis
|
|
591
|
+
expectedSuccess: true
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
name: 'Valid minimum value transaction',
|
|
595
|
+
initialStack: ['1000000'], // Exactly 1M satoshis
|
|
596
|
+
expectedSuccess: true
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
name: 'Invalid low value transaction',
|
|
600
|
+
initialStack: ['500000'], // 500k satoshis (too low)
|
|
601
|
+
expectedSuccess: false
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
name: 'Empty stack test',
|
|
605
|
+
initialStack: [],
|
|
606
|
+
expectedSuccess: false
|
|
607
|
+
}
|
|
608
|
+
]
|
|
609
|
+
|
|
610
|
+
const report = await tester.testCovenant(covenant, testCases)
|
|
611
|
+
return report
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### Example 14: Production Monitoring
|
|
616
|
+
|
|
617
|
+
```javascript
|
|
618
|
+
// Monitor covenant transactions on the blockchain
|
|
619
|
+
class CovenantMonitor {
|
|
620
|
+
constructor(covenantAddress, options = {}) {
|
|
621
|
+
this.address = covenantAddress
|
|
622
|
+
this.options = options
|
|
623
|
+
this.transactions = []
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Monitor for new transactions involving the covenant
|
|
627
|
+
async startMonitoring() {
|
|
628
|
+
console.log(`🔍 Monitoring covenant at ${this.address}`)
|
|
629
|
+
|
|
630
|
+
// Poll blockchain for new transactions
|
|
631
|
+
setInterval(async () => {
|
|
632
|
+
try {
|
|
633
|
+
await this.checkForNewTransactions()
|
|
634
|
+
} catch (error) {
|
|
635
|
+
console.log('Monitoring error:', error.message)
|
|
636
|
+
}
|
|
637
|
+
}, this.options.pollInterval || 30000) // 30 seconds
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
async checkForNewTransactions() {
|
|
641
|
+
// Fetch transactions for covenant address
|
|
642
|
+
const newTxs = await this.fetchTransactions()
|
|
643
|
+
|
|
644
|
+
for (const tx of newTxs) {
|
|
645
|
+
if (!this.transactions.find(t => t.txid === tx.txid)) {
|
|
646
|
+
this.transactions.push(tx)
|
|
647
|
+
await this.processCcovenantTransaction(tx)
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
async processCovenantTransaction(tx) {
|
|
653
|
+
console.log(`📝 New covenant transaction: ${tx.txid}`)
|
|
654
|
+
|
|
655
|
+
// Validate covenant compliance
|
|
656
|
+
const validation = await this.validateTransaction(tx)
|
|
657
|
+
|
|
658
|
+
if (validation.valid) {
|
|
659
|
+
console.log('✅ Transaction complies with covenant rules')
|
|
660
|
+
this.onValidTransaction(tx, validation)
|
|
661
|
+
} else {
|
|
662
|
+
console.log('❌ Transaction violates covenant rules:', validation.errors)
|
|
663
|
+
this.onInvalidTransaction(tx, validation)
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
async validateTransaction(tx) {
|
|
668
|
+
// Extract preimage and validate against covenant rules
|
|
669
|
+
const preimage = this.extractPreimage(tx)
|
|
670
|
+
|
|
671
|
+
const result = SmartContract.testCovenant(preimage, {
|
|
672
|
+
// Covenant-specific validation rules
|
|
673
|
+
})
|
|
674
|
+
|
|
675
|
+
return result
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
onValidTransaction(tx, validation) {
|
|
679
|
+
// Handle valid covenant transaction
|
|
680
|
+
if (this.options.onValidTx) {
|
|
681
|
+
this.options.onValidTx(tx, validation)
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
onInvalidTransaction(tx, validation) {
|
|
686
|
+
// Handle invalid covenant transaction
|
|
687
|
+
if (this.options.onInvalidTx) {
|
|
688
|
+
this.options.onInvalidTx(tx, validation)
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Could trigger alerts, notifications, etc.
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// Usage
|
|
696
|
+
const monitor = new CovenantMonitor('covenant_address', {
|
|
697
|
+
pollInterval: 15000, // 15 seconds
|
|
698
|
+
onValidTx: (tx, validation) => {
|
|
699
|
+
console.log('Valid covenant transaction processed:', tx.txid)
|
|
700
|
+
// Send notification, update database, etc.
|
|
701
|
+
},
|
|
702
|
+
onInvalidTx: (tx, validation) => {
|
|
703
|
+
console.log('ALERT: Invalid covenant transaction detected!', tx.txid)
|
|
704
|
+
// Send alert, log violation, etc.
|
|
705
|
+
}
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
monitor.startMonitoring()
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
---
|
|
712
|
+
|
|
713
|
+
## Testing Utilities
|
|
714
|
+
|
|
715
|
+
```javascript
|
|
716
|
+
// Helper function to create realistic test data
|
|
717
|
+
function createTestPreimage(options = {}) {
|
|
718
|
+
return SmartContract.createTestEnvironment(options).preimage
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Helper function to validate covenant against multiple preimages
|
|
722
|
+
function validateCovenantBatch(covenant, preimages) {
|
|
723
|
+
return preimages.map(preimage => {
|
|
724
|
+
const result = SmartContract.testCovenant(preimage, {
|
|
725
|
+
// Validation rules
|
|
726
|
+
})
|
|
727
|
+
return {
|
|
728
|
+
preimage,
|
|
729
|
+
valid: result.success,
|
|
730
|
+
details: result
|
|
731
|
+
}
|
|
732
|
+
})
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// Helper function to estimate covenant costs
|
|
736
|
+
function estimateCovenantCost(covenant) {
|
|
737
|
+
const scriptSize = covenant.operations.length
|
|
738
|
+
const estimatedBytes = scriptSize * 1.5 // Rough estimate
|
|
739
|
+
const estimatedFee = estimatedBytes * 0.5 // 0.5 sat/byte
|
|
740
|
+
|
|
741
|
+
return {
|
|
742
|
+
operations: scriptSize,
|
|
743
|
+
estimatedBytes,
|
|
744
|
+
estimatedFee
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
These examples demonstrate real-world covenant patterns and production integration strategies. The SmartContract framework provides the tools to implement complex financial and security logic while maintaining Bitcoin Script compatibility and performance.
|
|
750
|
+
|
|
751
|
+
For more examples and advanced patterns, explore the `/examples` directory in the repository.
|