@smartledger/bsv 3.4.2 → 3.4.4
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 +336 -0
- package/README.md +72 -72
- package/SECURITY.md +88 -0
- package/bin/cli.js +13 -8
- package/bsv-covenant.min.js +4 -4
- package/bsv-gdaf.min.js +5 -5
- package/bsv-ltp.min.js +7 -7
- package/bsv-smartcontract.min.js +5 -5
- package/bsv.bundle.js +5 -5
- package/bsv.d.ts +486 -9
- package/bsv.min.js +5 -5
- package/docs/COVENANT_DEVELOPMENT_RESOLVED.md +2 -2
- package/docs/MODULE_REFERENCE_COMPLETE.md +61 -58
- package/docs/advanced/LEGAL_TOKEN_PROTOCOL.md +3 -3
- package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
- package/docs/getting-started/INSTALLATION.md +30 -30
- package/docs/getting-started/QUICK_START.md +18 -18
- package/docs/migration/FROM_BSV_1_5_6.md +16 -10
- package/gdaf-entry.js +1 -2
- package/index.js +20 -7
- package/lib/smart_contract/covenant.js +10 -1
- package/lib/smartutxo.js +20 -12
- package/lib/transaction/transaction.js +7 -0
- package/ltp-entry.js +1 -2
- package/package.json +3 -3
- package/utilities/blockchain-state.js +32 -23
- package/demos/README.md +0 -188
- package/demos/architecture_demo.js +0 -247
- package/demos/browser-test.html +0 -1208
- package/demos/bsv_wallet_demo.js +0 -242
- package/demos/complete_ltp_demo.js +0 -511
- package/demos/debug_tools_demo.js +0 -87
- package/demos/demo_features.js +0 -123
- package/demos/easy_interface_demo.js +0 -109
- package/demos/ecies_demo.js +0 -182
- package/demos/gdaf_demo.js +0 -237
- package/demos/ltp_demo.js +0 -361
- package/demos/ltp_primitives_demo.js +0 -403
- package/demos/message_demo.js +0 -209
- package/demos/preimage_separation_demo.js +0 -383
- package/demos/script_helper_demo.js +0 -289
- package/demos/security_demo.js +0 -287
- package/demos/shamir_demo.js +0 -121
- package/demos/simple_demo.js +0 -204
- package/demos/simple_p2pkh_demo.js +0 -169
- package/demos/simple_utxo_preimage_demo.js +0 -196
- package/demos/smart_contract_demo.html +0 -1347
- package/demos/smart_contract_demo.js +0 -910
- package/demos/utxo_generator_demo.js +0 -244
- package/demos/validation_pipeline_demo.js +0 -155
- package/demos/web3keys.html +0 -740
- package/examples/README.md +0 -200
- package/examples/basic/transaction-creation.js +0 -534
- package/examples/basic/transaction_signature_api_gap.js +0 -178
- package/examples/complete_workflow_demo.js +0 -783
- package/examples/covenants/advanced_covenant_demo.js +0 -219
- package/examples/covenants/covenant_interface_demo.js +0 -270
- package/examples/covenants/covenant_manual_signature_resolved.js +0 -212
- package/examples/covenants/covenant_signature_template.js +0 -117
- package/examples/covenants2/covenant_bidirectional_example.js +0 -262
- package/examples/covenants2/covenant_utils_demo.js +0 -120
- package/examples/covenants2/preimage_covenant_utils.js +0 -287
- package/examples/covenants2/production_integration.js +0 -256
- package/examples/data/covenant_utxos.json +0 -28
- package/examples/data/utxos.json +0 -26
- package/examples/definitive_working_demo.js +0 -261
- package/examples/final_working_contracts.js +0 -338
- package/examples/legacy/README.md +0 -11
- package/examples/legacy/smart_contract_test_integration.js +0 -269
- package/examples/legacy/test_builtin_verify.js +0 -117
- package/examples/legacy/test_debug_integration.js +0 -71
- package/examples/legacy/test_ecdsa_little.js +0 -70
- package/examples/legacy/test_shamir.js +0 -221
- package/examples/legacy/test_smartverify_der.js +0 -110
- package/examples/preimage/README.md +0 -178
- package/examples/preimage/extract_preimage_bidirectional.js +0 -421
- package/examples/preimage/generate_sample_preimage.js +0 -208
- package/examples/preimage/generate_sighash_examples.js +0 -152
- package/examples/preimage/parse_preimage.js +0 -117
- package/examples/preimage/test_preimage_extractor.js +0 -53
- package/examples/preimage/test_varint_extraction.js +0 -95
- package/examples/scripts/custom_script_helper_example.js +0 -273
- package/examples/scripts/script_interpreter.js +0 -193
- package/examples/smart_contract/complete_workflow_demo.js +0 -343
- package/examples/smart_contract/covenant_builder_demo.js +0 -176
- package/examples/smart_contract/script_testing_integration.js +0 -198
- package/examples/smart_contract_templates.js +0 -718
- package/examples/working_smart_contracts.js +0 -348
|
@@ -1,1347 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>BSV Smart Contract Library Demo</title>
|
|
7
|
-
<style>
|
|
8
|
-
body {
|
|
9
|
-
font-family: 'Monaco', 'Courier New', monospace;
|
|
10
|
-
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
|
|
11
|
-
color: #fff;
|
|
12
|
-
margin: 0;
|
|
13
|
-
padding: 20px;
|
|
14
|
-
line-height: 1.6;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.container {
|
|
18
|
-
max-width: 1200px;
|
|
19
|
-
margin: 0 auto;
|
|
20
|
-
background: rgba(0, 0, 0, 0.2);
|
|
21
|
-
border-radius: 15px;
|
|
22
|
-
padding: 30px;
|
|
23
|
-
backdrop-filter: blur(10px);
|
|
24
|
-
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
h1 {
|
|
28
|
-
text-align: center;
|
|
29
|
-
font-size: 2.5em;
|
|
30
|
-
margin-bottom: 30px;
|
|
31
|
-
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
|
|
32
|
-
background: linear-gradient(45deg, #ffd700, #ffed4e);
|
|
33
|
-
-webkit-background-clip: text;
|
|
34
|
-
-webkit-text-fill-color: transparent;
|
|
35
|
-
background-clip: text;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.demo-section {
|
|
39
|
-
background: rgba(255, 255, 255, 0.1);
|
|
40
|
-
border-radius: 10px;
|
|
41
|
-
padding: 20px;
|
|
42
|
-
margin: 20px 0;
|
|
43
|
-
border-left: 4px solid #ffd700;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.demo-section h2 {
|
|
47
|
-
color: #ffd700;
|
|
48
|
-
margin-top: 0;
|
|
49
|
-
font-size: 1.5em;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.button-group {
|
|
53
|
-
display: flex;
|
|
54
|
-
gap: 10px;
|
|
55
|
-
flex-wrap: wrap;
|
|
56
|
-
margin: 15px 0;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
button {
|
|
60
|
-
background: linear-gradient(45deg, #007bff, #0056b3);
|
|
61
|
-
color: white;
|
|
62
|
-
border: none;
|
|
63
|
-
padding: 12px 20px;
|
|
64
|
-
border-radius: 8px;
|
|
65
|
-
cursor: pointer;
|
|
66
|
-
font-family: inherit;
|
|
67
|
-
font-weight: bold;
|
|
68
|
-
transition: all 0.3s ease;
|
|
69
|
-
box-shadow: 0 4px 15px rgba(0, 123, 255, 0.3);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
button:hover {
|
|
73
|
-
transform: translateY(-2px);
|
|
74
|
-
box-shadow: 0 6px 20px rgba(0, 123, 255, 0.4);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
button:active {
|
|
78
|
-
transform: translateY(0);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
button.success {
|
|
82
|
-
background: linear-gradient(45deg, #28a745, #1e7e34);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
button.warning {
|
|
86
|
-
background: linear-gradient(45deg, #ffc107, #e0a800);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
button.danger {
|
|
90
|
-
background: linear-gradient(45deg, #dc3545, #c82333);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.output {
|
|
94
|
-
background: rgba(0, 0, 0, 0.4);
|
|
95
|
-
border-radius: 8px;
|
|
96
|
-
padding: 15px;
|
|
97
|
-
margin: 15px 0;
|
|
98
|
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
99
|
-
font-size: 0.9em;
|
|
100
|
-
line-height: 1.4;
|
|
101
|
-
max-height: 300px;
|
|
102
|
-
overflow-y: auto;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.output pre {
|
|
106
|
-
margin: 0;
|
|
107
|
-
white-space: pre-wrap;
|
|
108
|
-
word-wrap: break-word;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.status {
|
|
112
|
-
padding: 10px;
|
|
113
|
-
border-radius: 5px;
|
|
114
|
-
margin: 10px 0;
|
|
115
|
-
font-weight: bold;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.status.success {
|
|
119
|
-
background: rgba(40, 167, 69, 0.2);
|
|
120
|
-
border: 1px solid #28a745;
|
|
121
|
-
color: #d4edda;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.status.error {
|
|
125
|
-
background: rgba(220, 53, 69, 0.2);
|
|
126
|
-
border: 1px solid #dc3545;
|
|
127
|
-
color: #f8d7da;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.status.info {
|
|
131
|
-
background: rgba(23, 162, 184, 0.2);
|
|
132
|
-
border: 1px solid #17a2b8;
|
|
133
|
-
color: #d1ecf1;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.feature-grid {
|
|
137
|
-
display: grid;
|
|
138
|
-
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
139
|
-
gap: 20px;
|
|
140
|
-
margin: 20px 0;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
.feature-card {
|
|
144
|
-
background: rgba(255, 255, 255, 0.05);
|
|
145
|
-
padding: 20px;
|
|
146
|
-
border-radius: 10px;
|
|
147
|
-
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
.feature-card h3 {
|
|
151
|
-
color: #ffd700;
|
|
152
|
-
margin-top: 0;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.code-block {
|
|
156
|
-
background: rgba(0, 0, 0, 0.6);
|
|
157
|
-
border-radius: 5px;
|
|
158
|
-
padding: 15px;
|
|
159
|
-
margin: 10px 0;
|
|
160
|
-
border-left: 3px solid #ffd700;
|
|
161
|
-
font-family: 'Monaco', 'Courier New', monospace;
|
|
162
|
-
font-size: 0.85em;
|
|
163
|
-
overflow-x: auto;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
.loading {
|
|
167
|
-
display: inline-block;
|
|
168
|
-
width: 20px;
|
|
169
|
-
height: 20px;
|
|
170
|
-
border: 3px solid rgba(255, 255, 255, 0.3);
|
|
171
|
-
border-radius: 50%;
|
|
172
|
-
border-top-color: #ffd700;
|
|
173
|
-
animation: spin 1s ease-in-out infinite;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
@keyframes spin {
|
|
177
|
-
to { transform: rotate(360deg); }
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.tab-container {
|
|
181
|
-
margin: 20px 0;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
.tab-buttons {
|
|
185
|
-
display: flex;
|
|
186
|
-
border-bottom: 2px solid rgba(255, 255, 255, 0.1);
|
|
187
|
-
margin-bottom: 20px;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
.tab-button {
|
|
191
|
-
background: transparent;
|
|
192
|
-
border: none;
|
|
193
|
-
padding: 10px 20px;
|
|
194
|
-
color: rgba(255, 255, 255, 0.7);
|
|
195
|
-
cursor: pointer;
|
|
196
|
-
border-bottom: 2px solid transparent;
|
|
197
|
-
transition: all 0.3s ease;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
.tab-button.active {
|
|
201
|
-
color: #ffd700;
|
|
202
|
-
border-bottom-color: #ffd700;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.tab-content {
|
|
206
|
-
display: none;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.tab-content.active {
|
|
210
|
-
display: block;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.input-group {
|
|
214
|
-
margin: 15px 0;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
.input-group label {
|
|
218
|
-
display: block;
|
|
219
|
-
margin-bottom: 5px;
|
|
220
|
-
color: #ffd700;
|
|
221
|
-
font-weight: bold;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.input-group input, .input-group textarea, .input-group select {
|
|
225
|
-
width: 100%;
|
|
226
|
-
padding: 10px;
|
|
227
|
-
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
228
|
-
border-radius: 5px;
|
|
229
|
-
background: rgba(0, 0, 0, 0.3);
|
|
230
|
-
color: #fff;
|
|
231
|
-
font-family: inherit;
|
|
232
|
-
box-sizing: border-box;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.input-group input:focus, .input-group textarea:focus, .input-group select:focus {
|
|
236
|
-
outline: none;
|
|
237
|
-
border-color: #ffd700;
|
|
238
|
-
box-shadow: 0 0 10px rgba(255, 215, 0, 0.3);
|
|
239
|
-
}
|
|
240
|
-
</style>
|
|
241
|
-
</head>
|
|
242
|
-
<body>
|
|
243
|
-
<div class="container">
|
|
244
|
-
<h1>🚀 BSV Smart Contract Library Demo</h1>
|
|
245
|
-
|
|
246
|
-
<div class="demo-section">
|
|
247
|
-
<h2>🌟 SmartLedger BSV Smart Contract Framework</h2>
|
|
248
|
-
<p>This interactive demo showcases the powerful smart contract capabilities of the SmartLedger BSV library.
|
|
249
|
-
Explore covenant creation, preimage parsing, script building, and UTXO management with real Bitcoin SV functionality.</p>
|
|
250
|
-
|
|
251
|
-
<div class="feature-grid">
|
|
252
|
-
<div class="feature-card">
|
|
253
|
-
<h3>🔒 Covenant Builder</h3>
|
|
254
|
-
<p>Create complex Bitcoin Script covenants with JavaScript syntax</p>
|
|
255
|
-
</div>
|
|
256
|
-
<div class="feature-card">
|
|
257
|
-
<h3>🧾 Preimage Parser</h3>
|
|
258
|
-
<p>Extract and validate BIP-143 transaction preimage fields</p>
|
|
259
|
-
</div>
|
|
260
|
-
<div class="feature-card">
|
|
261
|
-
<h3>🛠️ Script Tools</h3>
|
|
262
|
-
<p>Build, test, and debug Bitcoin Scripts locally</p>
|
|
263
|
-
</div>
|
|
264
|
-
<div class="feature-card">
|
|
265
|
-
<h3>💎 UTXO Generator</h3>
|
|
266
|
-
<p>Generate authentic test UTXOs for development</p>
|
|
267
|
-
</div>
|
|
268
|
-
</div>
|
|
269
|
-
</div>
|
|
270
|
-
|
|
271
|
-
<div class="tab-container">
|
|
272
|
-
<div class="tab-buttons">
|
|
273
|
-
<button class="tab-button active" onclick="switchTab('basics')">📚 Basics</button>
|
|
274
|
-
<button class="tab-button" onclick="switchTab('covenant')">🔒 Covenant Builder</button>
|
|
275
|
-
<button class="tab-button" onclick="switchTab('preimage')">🧾 Preimage Parser</button>
|
|
276
|
-
<button class="tab-button" onclick="switchTab('utxo')">💎 UTXO Generator</button>
|
|
277
|
-
<button class="tab-button" onclick="switchTab('scripts')">🛠️ Script Tools</button>
|
|
278
|
-
</div>
|
|
279
|
-
|
|
280
|
-
<!-- Basics Tab -->
|
|
281
|
-
<div id="basics" class="tab-content active">
|
|
282
|
-
<div class="demo-section">
|
|
283
|
-
<h2>📚 Smart Contract Basics</h2>
|
|
284
|
-
<div class="button-group">
|
|
285
|
-
<button onclick="loadLibrary()">📦 Load BSV Smart Contract Library</button>
|
|
286
|
-
<button onclick="showFeatures()" class="success">🌟 Show Available Features</button>
|
|
287
|
-
<button onclick="runBasicTests()" class="warning">🧪 Run Basic Tests</button>
|
|
288
|
-
</div>
|
|
289
|
-
<div id="basics-output" class="output"></div>
|
|
290
|
-
</div>
|
|
291
|
-
</div>
|
|
292
|
-
|
|
293
|
-
<!-- Covenant Builder Tab -->
|
|
294
|
-
<div id="covenant" class="tab-content">
|
|
295
|
-
<div class="demo-section">
|
|
296
|
-
<h2>🔒 Covenant Builder Demo</h2>
|
|
297
|
-
<p>Create Bitcoin Script covenants using JavaScript syntax. Covenants enforce spending conditions on future transactions.</p>
|
|
298
|
-
|
|
299
|
-
<div class="input-group">
|
|
300
|
-
<label>Covenant Type:</label>
|
|
301
|
-
<select id="covenant-type">
|
|
302
|
-
<option value="simple">Simple Amount Lock</option>
|
|
303
|
-
<option value="timelock">Time Lock Covenant</option>
|
|
304
|
-
<option value="multisig">Multi-Signature Covenant</option>
|
|
305
|
-
<option value="conditional">Conditional Spending</option>
|
|
306
|
-
</select>
|
|
307
|
-
</div>
|
|
308
|
-
|
|
309
|
-
<div class="input-group">
|
|
310
|
-
<label>Amount (satoshis):</label>
|
|
311
|
-
<input type="number" id="covenant-amount" value="100000" min="546">
|
|
312
|
-
</div>
|
|
313
|
-
|
|
314
|
-
<div class="input-group">
|
|
315
|
-
<label>Recipient Address:</label>
|
|
316
|
-
<input type="text" id="covenant-address" placeholder="1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa">
|
|
317
|
-
</div>
|
|
318
|
-
|
|
319
|
-
<div class="button-group">
|
|
320
|
-
<button onclick="generateCovenant()">🏗️ Generate Covenant</button>
|
|
321
|
-
<button onclick="testCovenant()" class="success">✅ Test Covenant</button>
|
|
322
|
-
<button onclick="showCovenantScript()" class="warning">📜 Show Script ASM</button>
|
|
323
|
-
</div>
|
|
324
|
-
<div id="covenant-output" class="output"></div>
|
|
325
|
-
</div>
|
|
326
|
-
</div>
|
|
327
|
-
|
|
328
|
-
<!-- Preimage Parser Tab -->
|
|
329
|
-
<div id="preimage" class="tab-content">
|
|
330
|
-
<div class="demo-section">
|
|
331
|
-
<h2>🧾 BIP-143 Preimage Parser</h2>
|
|
332
|
-
<p>Parse and extract fields from Bitcoin transaction preimages for covenant validation.</p>
|
|
333
|
-
|
|
334
|
-
<div class="input-group">
|
|
335
|
-
<label>Transaction Hex (or use sample):</label>
|
|
336
|
-
<textarea id="tx-hex" rows="4" placeholder="Paste transaction hex here or click 'Generate Sample'"></textarea>
|
|
337
|
-
</div>
|
|
338
|
-
|
|
339
|
-
<div class="button-group">
|
|
340
|
-
<button onclick="generateSampleTx()">🎲 Generate Sample Transaction</button>
|
|
341
|
-
<button onclick="parsePreimage()" class="success">🔍 Parse Preimage</button>
|
|
342
|
-
<button onclick="extractSighash()" class="warning">📊 Extract SIGHASH</button>
|
|
343
|
-
<button onclick="validatePreimage()" class="danger">✅ Validate Fields</button>
|
|
344
|
-
</div>
|
|
345
|
-
<div id="preimage-output" class="output"></div>
|
|
346
|
-
</div>
|
|
347
|
-
</div>
|
|
348
|
-
|
|
349
|
-
<!-- UTXO Generator Tab -->
|
|
350
|
-
<div id="utxo" class="tab-content">
|
|
351
|
-
<div class="demo-section">
|
|
352
|
-
<h2>💎 Mock UTXO Generator</h2>
|
|
353
|
-
<p>Generate authentic test UTXOs for smart contract development and testing.</p>
|
|
354
|
-
|
|
355
|
-
<div class="input-group">
|
|
356
|
-
<label>Private Key (WIF) - leave blank for random:</label>
|
|
357
|
-
<input type="text" id="utxo-wif" placeholder="L1234... (leave blank for random generation)">
|
|
358
|
-
</div>
|
|
359
|
-
|
|
360
|
-
<div class="input-group">
|
|
361
|
-
<label>UTXO Value (satoshis):</label>
|
|
362
|
-
<input type="number" id="utxo-amount" value="100000" min="546">
|
|
363
|
-
</div>
|
|
364
|
-
|
|
365
|
-
<div class="input-group">
|
|
366
|
-
<label>Network:</label>
|
|
367
|
-
<select id="utxo-network">
|
|
368
|
-
<option value="livenet">Mainnet</option>
|
|
369
|
-
<option value="testnet">Testnet</option>
|
|
370
|
-
<option value="regtest">Regtest</option>
|
|
371
|
-
</select>
|
|
372
|
-
</div>
|
|
373
|
-
|
|
374
|
-
<div class="button-group">
|
|
375
|
-
<button onclick="generateUTXO()">💎 Generate UTXO</button>
|
|
376
|
-
<button onclick="createSpendingTx()" class="success">💸 Create Spending TX</button>
|
|
377
|
-
<button onclick="showUTXODetails()" class="warning">📋 Show UTXO Details</button>
|
|
378
|
-
</div>
|
|
379
|
-
<div id="utxo-output" class="output"></div>
|
|
380
|
-
</div>
|
|
381
|
-
</div>
|
|
382
|
-
|
|
383
|
-
<!-- Script Tools Tab -->
|
|
384
|
-
<div id="scripts" class="tab-content">
|
|
385
|
-
<div class="demo-section">
|
|
386
|
-
<h2>🛠️ Script Development Tools</h2>
|
|
387
|
-
<p>Build, test, and debug Bitcoin Scripts with comprehensive tooling.</p>
|
|
388
|
-
|
|
389
|
-
<div class="input-group">
|
|
390
|
-
<label>Script ASM:</label>
|
|
391
|
-
<textarea id="script-asm" rows="3" placeholder="OP_DUP OP_HASH160 OP_PUSHDATA1 0x14 0x... OP_EQUALVERIFY OP_CHECKSIG">OP_DUP OP_HASH160 OP_PUSHDATA1 0x14 0x1234567890123456789012345678901234567890 OP_EQUALVERIFY OP_CHECKSIG</textarea>
|
|
392
|
-
</div>
|
|
393
|
-
|
|
394
|
-
<div class="input-group">
|
|
395
|
-
<label>Script Type:</label>
|
|
396
|
-
<select id="script-type">
|
|
397
|
-
<option value="p2pkh">Pay-to-Public-Key-Hash</option>
|
|
398
|
-
<option value="p2sh">Pay-to-Script-Hash</option>
|
|
399
|
-
<option value="covenant">Covenant Script</option>
|
|
400
|
-
<option value="custom">Custom Script</option>
|
|
401
|
-
</select>
|
|
402
|
-
</div>
|
|
403
|
-
|
|
404
|
-
<div class="button-group">
|
|
405
|
-
<button onclick="buildScript()">🏗️ Build Script</button>
|
|
406
|
-
<button onclick="analyzeScript()" class="success">🔍 Analyze Script</button>
|
|
407
|
-
<button onclick="debugScript()" class="warning">🐛 Debug Execution</button>
|
|
408
|
-
<button onclick="optimizeScript()" class="danger">⚡ Optimize Script</button>
|
|
409
|
-
</div>
|
|
410
|
-
<div id="scripts-output" class="output"></div>
|
|
411
|
-
</div>
|
|
412
|
-
</div>
|
|
413
|
-
</div>
|
|
414
|
-
|
|
415
|
-
<div class="demo-section">
|
|
416
|
-
<h2>🎯 Real-World Use Cases</h2>
|
|
417
|
-
<div class="feature-grid">
|
|
418
|
-
<div class="feature-card">
|
|
419
|
-
<h3>🏦 Escrow Contracts</h3>
|
|
420
|
-
<p>Multi-party escrow with timeout conditions</p>
|
|
421
|
-
<button onclick="showEscrowExample()">View Example</button>
|
|
422
|
-
</div>
|
|
423
|
-
<div class="feature-card">
|
|
424
|
-
<h3>⏰ Time-locked Payments</h3>
|
|
425
|
-
<p>Payments that unlock after specific time</p>
|
|
426
|
-
<button onclick="showTimelockExample()">View Example</button>
|
|
427
|
-
</div>
|
|
428
|
-
<div class="feature-card">
|
|
429
|
-
<h3>🔄 Recurring Payments</h3>
|
|
430
|
-
<p>Automated recurring payment covenants</p>
|
|
431
|
-
<button onclick="showRecurringExample()">View Example</button>
|
|
432
|
-
</div>
|
|
433
|
-
<div class="feature-card">
|
|
434
|
-
<h3>🎲 Gaming Contracts</h3>
|
|
435
|
-
<p>Provably fair gaming and betting</p>
|
|
436
|
-
<button onclick="showGamingExample()">View Example</button>
|
|
437
|
-
</div>
|
|
438
|
-
</div>
|
|
439
|
-
</div>
|
|
440
|
-
|
|
441
|
-
<div class="demo-section">
|
|
442
|
-
<h2>📖 Quick Start Guide</h2>
|
|
443
|
-
<div class="code-block">
|
|
444
|
-
<pre>// BSV bundle is already loaded - access directly
|
|
445
|
-
// Core BSV functionality
|
|
446
|
-
const privateKey = new bsv.PrivateKey();
|
|
447
|
-
const address = privateKey.toAddress();
|
|
448
|
-
|
|
449
|
-
// Create a basic transaction
|
|
450
|
-
const tx = new bsv.Transaction()
|
|
451
|
-
.from(utxo) // Add input UTXO
|
|
452
|
-
.to('recipient-address', 50000) // Add output
|
|
453
|
-
.change(address) // Change back to sender
|
|
454
|
-
.sign(privateKey); // Sign transaction
|
|
455
|
-
|
|
456
|
-
// Build custom scripts
|
|
457
|
-
const script = new bsv.Script()
|
|
458
|
-
.add(bsv.Opcode.OP_DUP)
|
|
459
|
-
.add(bsv.Opcode.OP_HASH160)
|
|
460
|
-
.add(address.hashBuffer)
|
|
461
|
-
.add(bsv.Opcode.OP_EQUALVERIFY)
|
|
462
|
-
.add(bsv.Opcode.OP_CHECKSIG);
|
|
463
|
-
|
|
464
|
-
// SmartLedger-BSV Covenant Example
|
|
465
|
-
if (bsv.SmartContract) {
|
|
466
|
-
// Create preimage-based covenant
|
|
467
|
-
const covenant = new bsv.SmartContract.Covenant(privateKey);
|
|
468
|
-
|
|
469
|
-
// Generate preimage for transaction validation
|
|
470
|
-
const preimage = bsv.Transaction.sighash.sighash(
|
|
471
|
-
tx, sighashType, inputIndex, lockingScript, satoshis
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
// OP_PUSH_TX method (not an opcode, but a signing technique)
|
|
475
|
-
const covenantInterface = new bsv.CovenantInterface();
|
|
476
|
-
const pushtxCovenant = covenantInterface.createPushtxCovenant({
|
|
477
|
-
publicKey: privateKey.publicKey.toString(),
|
|
478
|
-
enforceOutputs: true
|
|
479
|
-
});
|
|
480
|
-
}</pre>
|
|
481
|
-
</div>
|
|
482
|
-
</div>
|
|
483
|
-
|
|
484
|
-
<div class="demo-section">
|
|
485
|
-
<h2>🔗 Additional Resources</h2>
|
|
486
|
-
<div class="button-group">
|
|
487
|
-
<button onclick="window.open('https://github.com/codenlighten/smartledger-bsv', '_blank')" class="success">
|
|
488
|
-
📚 Documentation
|
|
489
|
-
</button>
|
|
490
|
-
<button onclick="window.open('https://github.com/codenlighten/smartledger-bsv/tree/main/examples', '_blank')" class="warning">
|
|
491
|
-
💡 More Examples
|
|
492
|
-
</button>
|
|
493
|
-
<button onclick="window.open('https://npmjs.com/package/@smartledger/bsv', '_blank')" class="danger">
|
|
494
|
-
📦 NPM Package
|
|
495
|
-
</button>
|
|
496
|
-
</div>
|
|
497
|
-
</div>
|
|
498
|
-
</div>
|
|
499
|
-
|
|
500
|
-
<!-- Load complete BSV bundle (includes all modules) -->
|
|
501
|
-
<script src="../bsv.bundle.js"></script>
|
|
502
|
-
|
|
503
|
-
<script>
|
|
504
|
-
// Global variables
|
|
505
|
-
let SmartContract = null;
|
|
506
|
-
let currentUTXO = null;
|
|
507
|
-
let currentCovenant = null;
|
|
508
|
-
|
|
509
|
-
// Tab switching functionality
|
|
510
|
-
function switchTab(tabName) {
|
|
511
|
-
// Hide all tab contents
|
|
512
|
-
const tabContents = document.querySelectorAll('.tab-content');
|
|
513
|
-
tabContents.forEach(tab => tab.classList.remove('active'));
|
|
514
|
-
|
|
515
|
-
// Remove active class from all buttons
|
|
516
|
-
const tabButtons = document.querySelectorAll('.tab-button');
|
|
517
|
-
tabButtons.forEach(button => button.classList.remove('active'));
|
|
518
|
-
|
|
519
|
-
// Show selected tab and mark button as active
|
|
520
|
-
document.getElementById(tabName).classList.add('active');
|
|
521
|
-
event.target.classList.add('active');
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// Utility functions
|
|
525
|
-
function log(elementId, message, type = 'info') {
|
|
526
|
-
const output = document.getElementById(elementId);
|
|
527
|
-
const timestamp = new Date().toLocaleTimeString();
|
|
528
|
-
const className = type === 'error' ? 'status error' :
|
|
529
|
-
type === 'success' ? 'status success' : 'status info';
|
|
530
|
-
|
|
531
|
-
const logEntry = `<div class="${className}">[${timestamp}] ${message}</div>`;
|
|
532
|
-
output.innerHTML += logEntry;
|
|
533
|
-
output.scrollTop = output.scrollHeight;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
function clearOutput(elementId) {
|
|
537
|
-
document.getElementById(elementId).innerHTML = '';
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
// Load library function
|
|
541
|
-
function loadLibrary() {
|
|
542
|
-
clearOutput('basics-output');
|
|
543
|
-
log('basics-output', '📦 Loading BSV Smart Contract Library...', 'info');
|
|
544
|
-
|
|
545
|
-
try {
|
|
546
|
-
// Check if BSV bundle is available
|
|
547
|
-
if (typeof bsv === 'undefined') {
|
|
548
|
-
throw new Error('BSV bundle not loaded. Please ensure bsv.bundle.js is included.');
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
log('basics-output', '✅ BSV library loaded successfully!', 'success');
|
|
552
|
-
log('basics-output', `📊 BSV version: ${bsv.version || 'Bundle v3.3.4'}`, 'info');
|
|
553
|
-
|
|
554
|
-
// Check available SmartLedger modules
|
|
555
|
-
const availableModules = [];
|
|
556
|
-
if (bsv.SmartContract) availableModules.push('SmartContract');
|
|
557
|
-
if (bsv.LTP) availableModules.push('LTP');
|
|
558
|
-
if (bsv.Security) availableModules.push('Security');
|
|
559
|
-
if (bsv.GDAF) availableModules.push('GDAF');
|
|
560
|
-
if (bsv.Shamir) availableModules.push('Shamir');
|
|
561
|
-
|
|
562
|
-
log('basics-output', `🔧 Available modules: ${availableModules.join(', ')}`, 'info');
|
|
563
|
-
log('basics-output', `🎯 Core BSV classes: Transaction, Script, PrivateKey, Address`, 'info');
|
|
564
|
-
|
|
565
|
-
// Initialize SmartContract reference
|
|
566
|
-
if (bsv.SmartContract) {
|
|
567
|
-
SmartContract = bsv.SmartContract;
|
|
568
|
-
log('basics-output', '🚀 SmartContract module ready!', 'success');
|
|
569
|
-
} else {
|
|
570
|
-
log('basics-output', '⚠️ SmartContract module not found in bundle', 'error');
|
|
571
|
-
SmartContract = null;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
log('basics-output', '� Ready for smart contract development!', 'success');
|
|
575
|
-
|
|
576
|
-
} catch (error) {
|
|
577
|
-
log('basics-output', `❌ Error loading library: ${error.message}`, 'error');
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
function showFeatures() {
|
|
582
|
-
clearOutput('basics-output');
|
|
583
|
-
log('basics-output', '🌟 BSV Smart Contract Features:', 'info');
|
|
584
|
-
|
|
585
|
-
const features = [
|
|
586
|
-
'🔒 Covenant Builder - Create complex spending conditions',
|
|
587
|
-
'🧾 Preimage Parser - Extract BIP-143 transaction fields',
|
|
588
|
-
'🛠️ Script Tools - Build and debug Bitcoin Scripts',
|
|
589
|
-
'💎 UTXO Generator - Create test UTXOs for development',
|
|
590
|
-
'📊 SIGHASH Analysis - Understand signature hash types',
|
|
591
|
-
'🏗️ ASM Generator - Convert JavaScript to Bitcoin Script',
|
|
592
|
-
'🔍 Script Debugger - Step-through script execution',
|
|
593
|
-
'⚡ Script Optimizer - Minimize script size and cost',
|
|
594
|
-
'🧪 Local Testing - Verify scripts without blockchain',
|
|
595
|
-
'📦 Production Ready - Deploy to BSV mainnet'
|
|
596
|
-
];
|
|
597
|
-
|
|
598
|
-
features.forEach(feature => {
|
|
599
|
-
log('basics-output', feature, 'success');
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
log('basics-output', '🚀 All features available in @smartledger/bsv package!', 'info');
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
function runBasicTests() {
|
|
606
|
-
clearOutput('basics-output');
|
|
607
|
-
log('basics-output', '🧪 Running Basic Smart Contract Tests...', 'info');
|
|
608
|
-
|
|
609
|
-
try {
|
|
610
|
-
// Test 1: Private Key Generation
|
|
611
|
-
log('basics-output', '📝 Test 1: Private Key Generation', 'info');
|
|
612
|
-
const privateKey = new bsv.PrivateKey();
|
|
613
|
-
const address = privateKey.toAddress();
|
|
614
|
-
log('basics-output', `✅ Generated address: ${address.toString()}`, 'success');
|
|
615
|
-
|
|
616
|
-
// Test 2: Transaction Creation
|
|
617
|
-
log('basics-output', '📝 Test 2: Transaction Creation', 'info');
|
|
618
|
-
const tx = new bsv.Transaction();
|
|
619
|
-
log('basics-output', `✅ Created transaction: ${tx.id || 'empty'}`, 'success');
|
|
620
|
-
|
|
621
|
-
// Test 3: Script Building
|
|
622
|
-
log('basics-output', '📝 Test 3: Script Building', 'info');
|
|
623
|
-
const script = bsv.Script.buildPublicKeyHashOut(address);
|
|
624
|
-
log('basics-output', `✅ Built P2PKH script: ${script.toString().substring(0, 50)}...`, 'success');
|
|
625
|
-
|
|
626
|
-
// Test 4: Mock UTXO
|
|
627
|
-
log('basics-output', '📝 Test 4: Mock UTXO Creation', 'info');
|
|
628
|
-
const utxo = {
|
|
629
|
-
txId: 'mock_' + Date.now(),
|
|
630
|
-
outputIndex: 0,
|
|
631
|
-
address: address.toString(),
|
|
632
|
-
script: script.toString(),
|
|
633
|
-
satoshis: 100000
|
|
634
|
-
};
|
|
635
|
-
log('basics-output', `✅ Created mock UTXO: ${utxo.satoshis} satoshis`, 'success');
|
|
636
|
-
|
|
637
|
-
log('basics-output', '🎉 All basic tests passed! Smart contract functionality ready.', 'success');
|
|
638
|
-
|
|
639
|
-
} catch (error) {
|
|
640
|
-
log('basics-output', `❌ Test failed: ${error.message}`, 'error');
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
// Covenant Builder Functions
|
|
645
|
-
function generateCovenant() {
|
|
646
|
-
clearOutput('covenant-output');
|
|
647
|
-
log('covenant-output', '🏗️ Generating Covenant...', 'info');
|
|
648
|
-
|
|
649
|
-
try {
|
|
650
|
-
const type = document.getElementById('covenant-type').value;
|
|
651
|
-
const amount = parseInt(document.getElementById('covenant-amount').value);
|
|
652
|
-
const address = document.getElementById('covenant-address').value;
|
|
653
|
-
|
|
654
|
-
// Generate keys for covenant
|
|
655
|
-
const covenantKey = new bsv.PrivateKey();
|
|
656
|
-
const covenantAddress = covenantKey.toAddress();
|
|
657
|
-
|
|
658
|
-
log('covenant-output', `📋 Covenant Type: ${type}`, 'info');
|
|
659
|
-
log('covenant-output', `💰 Amount: ${amount} satoshis`, 'info');
|
|
660
|
-
log('covenant-output', `🏠 Covenant Address: ${covenantAddress.toString()}`, 'info');
|
|
661
|
-
|
|
662
|
-
// Build covenant script based on type
|
|
663
|
-
let script;
|
|
664
|
-
switch (type) {
|
|
665
|
-
case 'simple':
|
|
666
|
-
script = buildSimpleCovenant(amount, address);
|
|
667
|
-
break;
|
|
668
|
-
case 'timelock':
|
|
669
|
-
script = buildTimelockCovenant(amount, address, 144); // 144 blocks ≈ 24 hours
|
|
670
|
-
break;
|
|
671
|
-
case 'multisig':
|
|
672
|
-
script = buildMultisigCovenant(amount, address, 2, 3); // 2-of-3 multisig
|
|
673
|
-
break;
|
|
674
|
-
case 'conditional':
|
|
675
|
-
script = buildConditionalCovenant(amount, address);
|
|
676
|
-
break;
|
|
677
|
-
default:
|
|
678
|
-
throw new Error('Unknown covenant type');
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
currentCovenant = {
|
|
682
|
-
type: type,
|
|
683
|
-
amount: amount,
|
|
684
|
-
address: address,
|
|
685
|
-
script: script,
|
|
686
|
-
covenantKey: covenantKey,
|
|
687
|
-
covenantAddress: covenantAddress
|
|
688
|
-
};
|
|
689
|
-
|
|
690
|
-
log('covenant-output', '✅ Covenant generated successfully!', 'success');
|
|
691
|
-
log('covenant-output', `📜 Script length: ${script.toBuffer().length} bytes`, 'info');
|
|
692
|
-
|
|
693
|
-
} catch (error) {
|
|
694
|
-
log('covenant-output', `❌ Covenant generation failed: ${error.message}`, 'error');
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
function buildSimpleCovenant(amount, recipientAddress) {
|
|
699
|
-
// Simple covenant: can only be spent to specific address with exact amount
|
|
700
|
-
const script = new bsv.Script();
|
|
701
|
-
|
|
702
|
-
// Add covenant logic (simplified for demo)
|
|
703
|
-
script.add(bsv.Opcode.OP_DUP)
|
|
704
|
-
.add(bsv.Opcode.OP_HASH160)
|
|
705
|
-
.add(bsv.Address.fromString(recipientAddress || '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa').hashBuffer)
|
|
706
|
-
.add(bsv.Opcode.OP_EQUALVERIFY)
|
|
707
|
-
.add(bsv.Opcode.OP_CHECKSIG);
|
|
708
|
-
|
|
709
|
-
return script;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
function buildTimelockCovenant(amount, recipientAddress, blocks) {
|
|
713
|
-
// SmartLedger-BSV timelock using preimage validation
|
|
714
|
-
const script = new bsv.Script();
|
|
715
|
-
|
|
716
|
-
// Preimage-based timelock logic (SmartLedger-BSV method)
|
|
717
|
-
// 1. Duplicate preimage for validation
|
|
718
|
-
script.add(bsv.Opcode.OP_DUP)
|
|
719
|
-
// 2. Extract nLockTime field from preimage (bytes 36-40)
|
|
720
|
-
.add(36) // Start position for nLockTime
|
|
721
|
-
.add(4) // Length of nLockTime field
|
|
722
|
-
.add(bsv.Opcode.OP_SUBSTR)
|
|
723
|
-
// 3. Convert to number and compare with required block height
|
|
724
|
-
.add(bsv.Opcode.OP_BIN2NUM)
|
|
725
|
-
.add(blocks) // Required block height
|
|
726
|
-
.add(bsv.Opcode.OP_GREATERTHANOREQUAL)
|
|
727
|
-
.add(bsv.Opcode.OP_VERIFY)
|
|
728
|
-
// 4. Hash preimage and verify
|
|
729
|
-
.add(bsv.Opcode.OP_HASH256)
|
|
730
|
-
.add('placeholder_preimage_hash') // Will be replaced with actual hash
|
|
731
|
-
.add(bsv.Opcode.OP_EQUALVERIFY)
|
|
732
|
-
// 5. Standard P2PKH check
|
|
733
|
-
.add(bsv.Opcode.OP_DROP)
|
|
734
|
-
.add(bsv.Address.fromString(recipientAddress || '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa').hashBuffer)
|
|
735
|
-
.add(bsv.Opcode.OP_CHECKSIG);
|
|
736
|
-
|
|
737
|
-
return script;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
function buildMultisigCovenant(amount, recipientAddress, m, n) {
|
|
741
|
-
// Multisig covenant: requires m-of-n signatures
|
|
742
|
-
const script = new bsv.Script();
|
|
743
|
-
|
|
744
|
-
// Generate dummy public keys for demo
|
|
745
|
-
const pubkeys = [];
|
|
746
|
-
for (let i = 0; i < n; i++) {
|
|
747
|
-
pubkeys.push(new bsv.PrivateKey().publicKey);
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
script.add(bsv.Opcode.OP_0); // Bug in CHECKMULTISIG requires extra value
|
|
751
|
-
for (let i = 0; i < m; i++) {
|
|
752
|
-
script.add(bsv.Opcode.OP_0); // Placeholder for signatures
|
|
753
|
-
}
|
|
754
|
-
script.add(m);
|
|
755
|
-
pubkeys.forEach(pubkey => script.add(pubkey.toBuffer()));
|
|
756
|
-
script.add(n);
|
|
757
|
-
script.add(bsv.Opcode.OP_CHECKMULTISIG);
|
|
758
|
-
|
|
759
|
-
return script;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
function buildConditionalCovenant(amount, recipientAddress) {
|
|
763
|
-
// SmartLedger-BSV conditional covenant using preimage validation
|
|
764
|
-
const script = new bsv.Script();
|
|
765
|
-
|
|
766
|
-
// Conditional logic using preimage field validation
|
|
767
|
-
script.add(bsv.Opcode.OP_IF)
|
|
768
|
-
// Path 1: Direct spending with signature
|
|
769
|
-
.add(bsv.Opcode.OP_DUP)
|
|
770
|
-
.add(bsv.Opcode.OP_HASH256)
|
|
771
|
-
.add('placeholder_preimage_hash_1') // First valid preimage hash
|
|
772
|
-
.add(bsv.Opcode.OP_EQUALVERIFY)
|
|
773
|
-
.add(bsv.Opcode.OP_DROP)
|
|
774
|
-
.add(bsv.Address.fromString(recipientAddress || '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa').hashBuffer)
|
|
775
|
-
.add(bsv.Opcode.OP_CHECKSIG)
|
|
776
|
-
.add(bsv.Opcode.OP_ELSE)
|
|
777
|
-
// Path 2: Alternative spending with different preimage constraints
|
|
778
|
-
.add(bsv.Opcode.OP_DUP)
|
|
779
|
-
.add(bsv.Opcode.OP_HASH256)
|
|
780
|
-
.add('placeholder_preimage_hash_2') // Alternative preimage hash
|
|
781
|
-
.add(bsv.Opcode.OP_EQUALVERIFY)
|
|
782
|
-
.add(bsv.Opcode.OP_DROP)
|
|
783
|
-
.add(bsv.Address.fromString(recipientAddress || '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa').hashBuffer)
|
|
784
|
-
.add(bsv.Opcode.OP_CHECKSIG)
|
|
785
|
-
.add(bsv.Opcode.OP_ENDIF);
|
|
786
|
-
|
|
787
|
-
return script;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
function testCovenant() {
|
|
791
|
-
if (!currentCovenant) {
|
|
792
|
-
log('covenant-output', '❌ No covenant generated. Please generate a covenant first.', 'error');
|
|
793
|
-
return;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
log('covenant-output', '🧪 Testing Covenant...', 'info');
|
|
797
|
-
|
|
798
|
-
try {
|
|
799
|
-
// Create a test transaction
|
|
800
|
-
const tx = new bsv.Transaction();
|
|
801
|
-
|
|
802
|
-
// Add input (mock UTXO)
|
|
803
|
-
tx.from({
|
|
804
|
-
txId: 'mock_covenant_input_' + Date.now(),
|
|
805
|
-
outputIndex: 0,
|
|
806
|
-
script: currentCovenant.script.toString(),
|
|
807
|
-
satoshis: currentCovenant.amount
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
// Add output
|
|
811
|
-
tx.to(currentCovenant.address || currentCovenant.covenantAddress.toString(), currentCovenant.amount - 1000); // minus fee
|
|
812
|
-
|
|
813
|
-
log('covenant-output', '✅ Test transaction created successfully!', 'success');
|
|
814
|
-
log('covenant-output', `📊 Transaction ID: ${tx.id}`, 'info');
|
|
815
|
-
log('covenant-output', `💰 Input amount: ${currentCovenant.amount} satoshis`, 'info');
|
|
816
|
-
log('covenant-output', `💸 Output amount: ${currentCovenant.amount - 1000} satoshis`, 'info');
|
|
817
|
-
log('covenant-output', `🏦 Fee: 1000 satoshis`, 'info');
|
|
818
|
-
|
|
819
|
-
} catch (error) {
|
|
820
|
-
log('covenant-output', `❌ Covenant test failed: ${error.message}`, 'error');
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
function showCovenantScript() {
|
|
825
|
-
if (!currentCovenant) {
|
|
826
|
-
log('covenant-output', '❌ No covenant generated. Please generate a covenant first.', 'error');
|
|
827
|
-
return;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
log('covenant-output', '📜 Covenant Script ASM:', 'info');
|
|
831
|
-
log('covenant-output', `<pre>${currentCovenant.script.toString()}</pre>`, 'success');
|
|
832
|
-
log('covenant-output', `📏 Script size: ${currentCovenant.script.toBuffer().length} bytes`, 'info');
|
|
833
|
-
log('covenant-output', `🔢 Script hex: ${currentCovenant.script.toBuffer().toString('hex')}`, 'info');
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
// Preimage Parser Functions
|
|
837
|
-
function generateSampleTx() {
|
|
838
|
-
clearOutput('preimage-output');
|
|
839
|
-
log('preimage-output', '🎲 Generating Sample Transaction...', 'info');
|
|
840
|
-
|
|
841
|
-
try {
|
|
842
|
-
const privateKey = new bsv.PrivateKey();
|
|
843
|
-
const address = privateKey.toAddress();
|
|
844
|
-
|
|
845
|
-
const tx = new bsv.Transaction()
|
|
846
|
-
.from({
|
|
847
|
-
txId: 'sample_' + Date.now(),
|
|
848
|
-
outputIndex: 0,
|
|
849
|
-
script: bsv.Script.buildPublicKeyHashOut(address).toString(),
|
|
850
|
-
satoshis: 100000
|
|
851
|
-
})
|
|
852
|
-
.to('1BitcoinEaterAddressDontSendf59kuE', 50000)
|
|
853
|
-
.change(address)
|
|
854
|
-
.sign(privateKey);
|
|
855
|
-
|
|
856
|
-
document.getElementById('tx-hex').value = tx.toString();
|
|
857
|
-
log('preimage-output', '✅ Sample transaction generated!', 'success');
|
|
858
|
-
log('preimage-output', `📊 Transaction ID: ${tx.id}`, 'info');
|
|
859
|
-
log('preimage-output', `📏 Transaction size: ${tx.toString().length / 2} bytes`, 'info');
|
|
860
|
-
|
|
861
|
-
} catch (error) {
|
|
862
|
-
log('preimage-output', `❌ Failed to generate sample: ${error.message}`, 'error');
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
function parsePreimage() {
|
|
867
|
-
const txHex = document.getElementById('tx-hex').value.trim();
|
|
868
|
-
if (!txHex) {
|
|
869
|
-
log('preimage-output', '❌ Please provide transaction hex or generate a sample.', 'error');
|
|
870
|
-
return;
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
clearOutput('preimage-output');
|
|
874
|
-
log('preimage-output', '🔍 Parsing Preimage...', 'info');
|
|
875
|
-
|
|
876
|
-
try {
|
|
877
|
-
const tx = new bsv.Transaction(txHex);
|
|
878
|
-
|
|
879
|
-
// Extract preimage components (BIP-143)
|
|
880
|
-
log('preimage-output', '📋 BIP-143 Preimage Components:', 'info');
|
|
881
|
-
log('preimage-output', `📝 Version: ${tx.version}`, 'success');
|
|
882
|
-
log('preimage-output', `🔗 Input Count: ${tx.inputs.length}`, 'success');
|
|
883
|
-
log('preimage-output', `📤 Output Count: ${tx.outputs.length}`, 'success');
|
|
884
|
-
log('preimage-output', `⏰ Lock Time: ${tx.nLockTime}`, 'success');
|
|
885
|
-
|
|
886
|
-
// Show input details
|
|
887
|
-
tx.inputs.forEach((input, index) => {
|
|
888
|
-
log('preimage-output', `🔍 Input ${index}: ${input.prevTxId}:${input.outputIndex}`, 'info');
|
|
889
|
-
});
|
|
890
|
-
|
|
891
|
-
// Show output details
|
|
892
|
-
tx.outputs.forEach((output, index) => {
|
|
893
|
-
log('preimage-output', `📤 Output ${index}: ${output.satoshis} sats to ${output.script.toString().substring(0, 50)}...`, 'info');
|
|
894
|
-
});
|
|
895
|
-
|
|
896
|
-
} catch (error) {
|
|
897
|
-
log('preimage-output', `❌ Preimage parsing failed: ${error.message}`, 'error');
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
function extractSighash() {
|
|
902
|
-
const txHex = document.getElementById('tx-hex').value.trim();
|
|
903
|
-
if (!txHex) {
|
|
904
|
-
log('preimage-output', '❌ Please provide transaction hex first.', 'error');
|
|
905
|
-
return;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
log('preimage-output', '📊 Extracting SIGHASH information...', 'info');
|
|
909
|
-
|
|
910
|
-
try {
|
|
911
|
-
const tx = new bsv.Transaction(txHex);
|
|
912
|
-
|
|
913
|
-
// SIGHASH flags
|
|
914
|
-
const sighashTypes = {
|
|
915
|
-
0x01: 'SIGHASH_ALL',
|
|
916
|
-
0x02: 'SIGHASH_NONE',
|
|
917
|
-
0x03: 'SIGHASH_SINGLE',
|
|
918
|
-
0x81: 'SIGHASH_ALL | ANYONECANPAY',
|
|
919
|
-
0x82: 'SIGHASH_NONE | ANYONECANPAY',
|
|
920
|
-
0x83: 'SIGHASH_SINGLE | ANYONECANPAY'
|
|
921
|
-
};
|
|
922
|
-
|
|
923
|
-
log('preimage-output', '🔒 SIGHASH Analysis:', 'success');
|
|
924
|
-
log('preimage-output', '📋 Available SIGHASH types:', 'info');
|
|
925
|
-
|
|
926
|
-
Object.entries(sighashTypes).forEach(([flag, name]) => {
|
|
927
|
-
log('preimage-output', ` ${flag}: ${name}`, 'info');
|
|
928
|
-
});
|
|
929
|
-
|
|
930
|
-
log('preimage-output', '💡 Most common: SIGHASH_ALL (0x01) - signs all inputs and outputs', 'success');
|
|
931
|
-
|
|
932
|
-
} catch (error) {
|
|
933
|
-
log('preimage-output', `❌ SIGHASH extraction failed: ${error.message}`, 'error');
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
function validatePreimage() {
|
|
938
|
-
const txHex = document.getElementById('tx-hex').value.trim();
|
|
939
|
-
if (!txHex) {
|
|
940
|
-
log('preimage-output', '❌ Please provide transaction hex first.', 'error');
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
log('preimage-output', '✅ Validating Preimage Fields...', 'info');
|
|
945
|
-
|
|
946
|
-
try {
|
|
947
|
-
const tx = new bsv.Transaction(txHex);
|
|
948
|
-
|
|
949
|
-
// Validation checks
|
|
950
|
-
const validations = [
|
|
951
|
-
{ name: 'Version', check: tx.version >= 1, value: tx.version },
|
|
952
|
-
{ name: 'Input Count', check: tx.inputs.length > 0, value: tx.inputs.length },
|
|
953
|
-
{ name: 'Output Count', check: tx.outputs.length > 0, value: tx.outputs.length },
|
|
954
|
-
{ name: 'Lock Time', check: tx.nLockTime >= 0, value: tx.nLockTime },
|
|
955
|
-
{ name: 'Transaction Size', check: txHex.length <= 200000, value: `${txHex.length / 2} bytes` }
|
|
956
|
-
];
|
|
957
|
-
|
|
958
|
-
validations.forEach(validation => {
|
|
959
|
-
const status = validation.check ? '✅' : '❌';
|
|
960
|
-
const type = validation.check ? 'success' : 'error';
|
|
961
|
-
log('preimage-output', `${status} ${validation.name}: ${validation.value}`, type);
|
|
962
|
-
});
|
|
963
|
-
|
|
964
|
-
const allValid = validations.every(v => v.check);
|
|
965
|
-
log('preimage-output', allValid ? '🎉 All validations passed!' : '⚠️ Some validations failed!',
|
|
966
|
-
allValid ? 'success' : 'error');
|
|
967
|
-
|
|
968
|
-
} catch (error) {
|
|
969
|
-
log('preimage-output', `❌ Validation failed: ${error.message}`, 'error');
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
// UTXO Generator Functions
|
|
974
|
-
function generateUTXO() {
|
|
975
|
-
clearOutput('utxo-output');
|
|
976
|
-
log('utxo-output', '💎 Generating Mock UTXO...', 'info');
|
|
977
|
-
|
|
978
|
-
try {
|
|
979
|
-
const wif = document.getElementById('utxo-wif').value.trim();
|
|
980
|
-
const amount = parseInt(document.getElementById('utxo-amount').value);
|
|
981
|
-
const network = document.getElementById('utxo-network').value;
|
|
982
|
-
|
|
983
|
-
// Generate or use provided private key
|
|
984
|
-
let privateKey;
|
|
985
|
-
if (wif) {
|
|
986
|
-
privateKey = bsv.PrivateKey.fromWIF(wif);
|
|
987
|
-
log('utxo-output', '🔑 Using provided private key', 'info');
|
|
988
|
-
} else {
|
|
989
|
-
privateKey = new bsv.PrivateKey(undefined, network);
|
|
990
|
-
log('utxo-output', '🎲 Generated new random private key', 'info');
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
const address = privateKey.toAddress(network);
|
|
994
|
-
const script = bsv.Script.buildPublicKeyHashOut(address);
|
|
995
|
-
|
|
996
|
-
// Create mock UTXO
|
|
997
|
-
currentUTXO = {
|
|
998
|
-
txId: 'mock_utxo_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9),
|
|
999
|
-
outputIndex: 0,
|
|
1000
|
-
address: address.toString(),
|
|
1001
|
-
script: script.toString(),
|
|
1002
|
-
satoshis: amount,
|
|
1003
|
-
privateKey: privateKey,
|
|
1004
|
-
network: network
|
|
1005
|
-
};
|
|
1006
|
-
|
|
1007
|
-
log('utxo-output', '✅ Mock UTXO generated successfully!', 'success');
|
|
1008
|
-
log('utxo-output', `🆔 UTXO ID: ${currentUTXO.txId}:${currentUTXO.outputIndex}`, 'info');
|
|
1009
|
-
log('utxo-output', `🏠 Address: ${currentUTXO.address}`, 'info');
|
|
1010
|
-
log('utxo-output', `💰 Value: ${currentUTXO.satoshis} satoshis`, 'info');
|
|
1011
|
-
log('utxo-output', `🌐 Network: ${currentUTXO.network}`, 'info');
|
|
1012
|
-
log('utxo-output', `🔑 Private Key (WIF): ${currentUTXO.privateKey.toWIF()}`, 'info');
|
|
1013
|
-
|
|
1014
|
-
} catch (error) {
|
|
1015
|
-
log('utxo-output', `❌ UTXO generation failed: ${error.message}`, 'error');
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
function createSpendingTx() {
|
|
1020
|
-
if (!currentUTXO) {
|
|
1021
|
-
log('utxo-output', '❌ No UTXO available. Please generate a UTXO first.', 'error');
|
|
1022
|
-
return;
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
log('utxo-output', '💸 Creating Spending Transaction...', 'info');
|
|
1026
|
-
|
|
1027
|
-
try {
|
|
1028
|
-
const recipientAddress = '1BitcoinEaterAddressDontSendf59kuE'; // Burn address for demo
|
|
1029
|
-
const fee = 1000;
|
|
1030
|
-
const outputAmount = currentUTXO.satoshis - fee;
|
|
1031
|
-
|
|
1032
|
-
if (outputAmount <= 0) {
|
|
1033
|
-
throw new Error('Insufficient funds for transaction fee');
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
const tx = new bsv.Transaction()
|
|
1037
|
-
.from(currentUTXO)
|
|
1038
|
-
.to(recipientAddress, outputAmount)
|
|
1039
|
-
.sign(currentUTXO.privateKey);
|
|
1040
|
-
|
|
1041
|
-
log('utxo-output', '✅ Spending transaction created!', 'success');
|
|
1042
|
-
log('utxo-output', `📊 Transaction ID: ${tx.id}`, 'info');
|
|
1043
|
-
log('utxo-output', `💰 Input: ${currentUTXO.satoshis} satoshis`, 'info');
|
|
1044
|
-
log('utxo-output', `💸 Output: ${outputAmount} satoshis`, 'info');
|
|
1045
|
-
log('utxo-output', `🏦 Fee: ${fee} satoshis`, 'info');
|
|
1046
|
-
log('utxo-output', `📏 Transaction size: ${tx.toString().length / 2} bytes`, 'info');
|
|
1047
|
-
log('utxo-output', `🔗 Raw transaction: ${tx.toString().substring(0, 100)}...`, 'info');
|
|
1048
|
-
|
|
1049
|
-
} catch (error) {
|
|
1050
|
-
log('utxo-output', `❌ Spending transaction failed: ${error.message}`, 'error');
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
function showUTXODetails() {
|
|
1055
|
-
if (!currentUTXO) {
|
|
1056
|
-
log('utxo-output', '❌ No UTXO available. Please generate a UTXO first.', 'error');
|
|
1057
|
-
return;
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
log('utxo-output', '📋 Detailed UTXO Information:', 'info');
|
|
1061
|
-
log('utxo-output', `<pre>
|
|
1062
|
-
UTXO Details:
|
|
1063
|
-
============
|
|
1064
|
-
Transaction ID: ${currentUTXO.txId}
|
|
1065
|
-
Output Index: ${currentUTXO.outputIndex}
|
|
1066
|
-
Address: ${currentUTXO.address}
|
|
1067
|
-
Value: ${currentUTXO.satoshis} satoshis (${(currentUTXO.satoshis / 100000000).toFixed(8)} BSV)
|
|
1068
|
-
Network: ${currentUTXO.network}
|
|
1069
|
-
|
|
1070
|
-
Script Details:
|
|
1071
|
-
==============
|
|
1072
|
-
Script ASM: ${currentUTXO.script}
|
|
1073
|
-
Script Size: ${Buffer.from(currentUTXO.script, 'hex').length} bytes
|
|
1074
|
-
|
|
1075
|
-
Private Key:
|
|
1076
|
-
===========
|
|
1077
|
-
WIF: ${currentUTXO.privateKey.toWIF()}
|
|
1078
|
-
Hex: ${currentUTXO.privateKey.toString()}
|
|
1079
|
-
Compressed: ${currentUTXO.privateKey.compressed}
|
|
1080
|
-
|
|
1081
|
-
Address Details:
|
|
1082
|
-
===============
|
|
1083
|
-
Hash160: ${bsv.Address.fromString(currentUTXO.address).hashBuffer.toString('hex')}
|
|
1084
|
-
Version: ${bsv.Address.fromString(currentUTXO.address).network.pubkeyhash}
|
|
1085
|
-
</pre>`, 'success');
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
// Script Tools Functions
|
|
1089
|
-
function buildScript() {
|
|
1090
|
-
clearOutput('scripts-output');
|
|
1091
|
-
log('scripts-output', '🏗️ Building Script...', 'info');
|
|
1092
|
-
|
|
1093
|
-
try {
|
|
1094
|
-
const asmCode = document.getElementById('script-asm').value.trim();
|
|
1095
|
-
const scriptType = document.getElementById('script-type').value;
|
|
1096
|
-
|
|
1097
|
-
if (!asmCode) {
|
|
1098
|
-
throw new Error('Please provide script ASM code');
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
const script = bsv.Script.fromASM(asmCode);
|
|
1102
|
-
|
|
1103
|
-
log('scripts-output', `✅ Script built successfully!`, 'success');
|
|
1104
|
-
log('scripts-output', `📝 Script type: ${scriptType}`, 'info');
|
|
1105
|
-
log('scripts-output', `📏 Script size: ${script.toBuffer().length} bytes`, 'info');
|
|
1106
|
-
log('scripts-output', `🔢 Script hex: ${script.toBuffer().toString('hex')}`, 'info');
|
|
1107
|
-
log('scripts-output', `📜 Script ASM: ${script.toString()}`, 'info');
|
|
1108
|
-
|
|
1109
|
-
// Analyze script opcodes
|
|
1110
|
-
const opcodes = script.chunks.map(chunk => {
|
|
1111
|
-
if (chunk.opcodenum !== undefined) {
|
|
1112
|
-
return `OP_${bsv.Opcode.reverseMap[chunk.opcodenum] || chunk.opcodenum}`;
|
|
1113
|
-
} else if (chunk.buf) {
|
|
1114
|
-
return `DATA(${chunk.buf.length} bytes)`;
|
|
1115
|
-
}
|
|
1116
|
-
return 'UNKNOWN';
|
|
1117
|
-
});
|
|
1118
|
-
|
|
1119
|
-
log('scripts-output', `🔍 Opcodes: ${opcodes.join(', ')}`, 'info');
|
|
1120
|
-
|
|
1121
|
-
} catch (error) {
|
|
1122
|
-
log('scripts-output', `❌ Script building failed: ${error.message}`, 'error');
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
function analyzeScript() {
|
|
1127
|
-
const asmCode = document.getElementById('script-asm').value.trim();
|
|
1128
|
-
if (!asmCode) {
|
|
1129
|
-
log('scripts-output', '❌ Please provide script ASM code first.', 'error');
|
|
1130
|
-
return;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
log('scripts-output', '🔍 Analyzing Script...', 'info');
|
|
1134
|
-
|
|
1135
|
-
try {
|
|
1136
|
-
const script = bsv.Script.fromASM(asmCode);
|
|
1137
|
-
|
|
1138
|
-
// Script analysis
|
|
1139
|
-
const analysis = {
|
|
1140
|
-
size: script.toBuffer().length,
|
|
1141
|
-
chunks: script.chunks.length,
|
|
1142
|
-
isPushOnly: script.isPushOnly(),
|
|
1143
|
-
isStandard: true, // Simplified check
|
|
1144
|
-
hasTimelock: asmCode.includes('CHECKLOCKTIMEVERIFY') || asmCode.includes('CHECKSEQUENCEVERIFY'),
|
|
1145
|
-
hasMultisig: asmCode.includes('CHECKMULTISIG'),
|
|
1146
|
-
hasHash: asmCode.includes('HASH160') || asmCode.includes('HASH256'),
|
|
1147
|
-
complexity: 'Medium' // Simplified assessment
|
|
1148
|
-
};
|
|
1149
|
-
|
|
1150
|
-
log('scripts-output', '📊 Script Analysis Results:', 'success');
|
|
1151
|
-
log('scripts-output', `📏 Size: ${analysis.size} bytes`, 'info');
|
|
1152
|
-
log('scripts-output', `🧩 Chunks: ${analysis.chunks}`, 'info');
|
|
1153
|
-
log('scripts-output', `📌 Push-only: ${analysis.isPushOnly ? 'Yes' : 'No'}`, 'info');
|
|
1154
|
-
log('scripts-output', `✅ Standard: ${analysis.isStandard ? 'Yes' : 'No'}`, 'info');
|
|
1155
|
-
log('scripts-output', `⏰ Has timelock: ${analysis.hasTimelock ? 'Yes' : 'No'}`, 'info');
|
|
1156
|
-
log('scripts-output', `👥 Has multisig: ${analysis.hasMultisig ? 'Yes' : 'No'}`, 'info');
|
|
1157
|
-
log('scripts-output', `🔐 Has hash ops: ${analysis.hasHash ? 'Yes' : 'No'}`, 'info');
|
|
1158
|
-
log('scripts-output', `🎯 Complexity: ${analysis.complexity}`, 'info');
|
|
1159
|
-
|
|
1160
|
-
// Fee estimation
|
|
1161
|
-
const feePerByte = 1; // satoshis per byte
|
|
1162
|
-
const estimatedFee = analysis.size * feePerByte;
|
|
1163
|
-
log('scripts-output', `💰 Estimated fee: ${estimatedFee} satoshis (at ${feePerByte} sat/byte)`, 'info');
|
|
1164
|
-
|
|
1165
|
-
} catch (error) {
|
|
1166
|
-
log('scripts-output', `❌ Script analysis failed: ${error.message}`, 'error');
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
function debugScript() {
|
|
1171
|
-
const asmCode = document.getElementById('script-asm').value.trim();
|
|
1172
|
-
if (!asmCode) {
|
|
1173
|
-
log('scripts-output', '❌ Please provide script ASM code first.', 'error');
|
|
1174
|
-
return;
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
log('scripts-output', '🐛 Debug Mode: Step-by-step execution', 'info');
|
|
1178
|
-
|
|
1179
|
-
try {
|
|
1180
|
-
const script = bsv.Script.fromASM(asmCode);
|
|
1181
|
-
|
|
1182
|
-
log('scripts-output', '🔍 Script Debug Information:', 'success');
|
|
1183
|
-
log('scripts-output', '📋 Execution Steps:', 'info');
|
|
1184
|
-
|
|
1185
|
-
script.chunks.forEach((chunk, index) => {
|
|
1186
|
-
if (chunk.opcodenum !== undefined) {
|
|
1187
|
-
const opname = bsv.Opcode.reverseMap[chunk.opcodenum] || `OP_${chunk.opcodenum}`;
|
|
1188
|
-
log('scripts-output', ` Step ${index + 1}: Execute ${opname}`, 'info');
|
|
1189
|
-
} else if (chunk.buf) {
|
|
1190
|
-
log('scripts-output', ` Step ${index + 1}: Push data (${chunk.buf.length} bytes): ${chunk.buf.toString('hex')}`, 'info');
|
|
1191
|
-
}
|
|
1192
|
-
});
|
|
1193
|
-
|
|
1194
|
-
log('scripts-output', '💡 Debug complete! For full verification, create a transaction and use bsv.Script.Interpreter', 'success');
|
|
1195
|
-
|
|
1196
|
-
} catch (error) {
|
|
1197
|
-
log('scripts-output', `❌ Script debugging failed: ${error.message}`, 'error');
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
function optimizeScript() {
|
|
1202
|
-
const asmCode = document.getElementById('script-asm').value.trim();
|
|
1203
|
-
if (!asmCode) {
|
|
1204
|
-
log('scripts-output', '❌ Please provide script ASM code first.', 'error');
|
|
1205
|
-
return;
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
log('scripts-output', '⚡ Optimizing Script...', 'info');
|
|
1209
|
-
|
|
1210
|
-
try {
|
|
1211
|
-
const script = bsv.Script.fromASM(asmCode);
|
|
1212
|
-
const originalSize = script.toBuffer().length;
|
|
1213
|
-
|
|
1214
|
-
// Simple optimization suggestions
|
|
1215
|
-
const optimizations = [];
|
|
1216
|
-
|
|
1217
|
-
if (asmCode.includes('OP_1 OP_ADD')) {
|
|
1218
|
-
optimizations.push('Replace "OP_1 OP_ADD" with "OP_1ADD" (saves 1 byte)');
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
if (asmCode.includes('OP_0')) {
|
|
1222
|
-
optimizations.push('OP_0 is efficiently encoded');
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
if (asmCode.includes('OP_1') && !asmCode.includes('OP_1ADD')) {
|
|
1226
|
-
optimizations.push('OP_1-OP_16 are more efficient than pushing the number');
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
const redundantOps = asmCode.match(/OP_DUP OP_DROP/g);
|
|
1230
|
-
if (redundantOps) {
|
|
1231
|
-
optimizations.push(`Remove redundant OP_DUP OP_DROP sequences (${redundantOps.length} found)`);
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
log('scripts-output', `📊 Original size: ${originalSize} bytes`, 'info');
|
|
1235
|
-
|
|
1236
|
-
if (optimizations.length > 0) {
|
|
1237
|
-
log('scripts-output', '💡 Optimization suggestions:', 'success');
|
|
1238
|
-
optimizations.forEach(opt => {
|
|
1239
|
-
log('scripts-output', ` • ${opt}`, 'info');
|
|
1240
|
-
});
|
|
1241
|
-
} else {
|
|
1242
|
-
log('scripts-output', '✅ Script appears to be well optimized!', 'success');
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
log('scripts-output', '🎯 General optimization tips:', 'info');
|
|
1246
|
-
log('scripts-output', ' • Use OP_1-OP_16 instead of pushing small numbers', 'info');
|
|
1247
|
-
log('scripts-output', ' • Minimize stack operations', 'info');
|
|
1248
|
-
log('scripts-output', ' • Avoid redundant DUP/DROP sequences', 'info');
|
|
1249
|
-
log('scripts-output', ' • Use more efficient opcodes when available', 'info');
|
|
1250
|
-
|
|
1251
|
-
} catch (error) {
|
|
1252
|
-
log('scripts-output', `❌ Script optimization failed: ${error.message}`, 'error');
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
// Use Case Examples
|
|
1257
|
-
function showEscrowExample() {
|
|
1258
|
-
alert(`🏦 Escrow Contract Example:
|
|
1259
|
-
|
|
1260
|
-
A 2-of-3 escrow where buyer, seller, and arbiter each hold a key.
|
|
1261
|
-
- Buyer and seller can complete transaction normally
|
|
1262
|
-
- If dispute, buyer+arbiter or seller+arbiter can resolve
|
|
1263
|
-
- Includes timeout clause for refund after 30 days
|
|
1264
|
-
|
|
1265
|
-
Script structure:
|
|
1266
|
-
IF
|
|
1267
|
-
2 <buyer_pubkey> <seller_pubkey> <arbiter_pubkey> 3 CHECKMULTISIG
|
|
1268
|
-
ELSE
|
|
1269
|
-
<30_days> CHECKLOCKTIMEVERIFY DROP
|
|
1270
|
-
<buyer_pubkey> CHECKSIG
|
|
1271
|
-
ENDIF
|
|
1272
|
-
|
|
1273
|
-
Click "Covenant Builder" tab to create your own!`);
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
function showTimelockExample() {
|
|
1277
|
-
alert(`⏰ SmartLedger-BSV Timelock Covenant:
|
|
1278
|
-
|
|
1279
|
-
Uses preimage validation instead of OP_CHECKLOCKTIMEVERIFY.
|
|
1280
|
-
The covenant validates nLockTime field from BIP-143 preimage.
|
|
1281
|
-
|
|
1282
|
-
SmartLedger-BSV Script Structure:
|
|
1283
|
-
DUP # Duplicate preimage
|
|
1284
|
-
36 4 OP_SUBSTR # Extract nLockTime (bytes 36-40)
|
|
1285
|
-
OP_BIN2NUM # Convert to number
|
|
1286
|
-
<block_height> # Required minimum block
|
|
1287
|
-
OP_GREATERTHANOREQUAL # Check if time passed
|
|
1288
|
-
OP_VERIFY # Enforce constraint
|
|
1289
|
-
OP_HASH256 # Hash preimage
|
|
1290
|
-
<preimage_hash> # Expected hash
|
|
1291
|
-
OP_EQUALVERIFY # Validate preimage
|
|
1292
|
-
OP_DROP # Clean stack
|
|
1293
|
-
<pubkey> OP_CHECKSIG # Signature check
|
|
1294
|
-
|
|
1295
|
-
This uses OP_PUSH_TX methods and preimage parsing!
|
|
1296
|
-
|
|
1297
|
-
Try the "Covenant Builder" to see real implementation!`);
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
function showRecurringExample() {
|
|
1301
|
-
alert(`🔄 Recurring Payment Example:
|
|
1302
|
-
|
|
1303
|
-
Automated payments that renew themselves on-chain.
|
|
1304
|
-
Each payment creates a new UTXO for the next payment.
|
|
1305
|
-
|
|
1306
|
-
Key features:
|
|
1307
|
-
- Self-perpetuating contract
|
|
1308
|
-
- Fixed payment amounts and intervals
|
|
1309
|
-
- Automatic recipient payment
|
|
1310
|
-
- Remaining balance rolls over
|
|
1311
|
-
|
|
1312
|
-
Implementation requires covenant logic to:
|
|
1313
|
-
1. Send payment to recipient
|
|
1314
|
-
2. Create new UTXO with remaining funds
|
|
1315
|
-
3. Enforce timing constraints
|
|
1316
|
-
|
|
1317
|
-
Explore covenant building for implementation!`);
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
function showGamingExample() {
|
|
1321
|
-
alert(`🎲 Gaming Contract Example:
|
|
1322
|
-
|
|
1323
|
-
Provably fair games using on-chain randomness and covenants.
|
|
1324
|
-
|
|
1325
|
-
Features:
|
|
1326
|
-
- Commit-reveal schemes for fairness
|
|
1327
|
-
- Automatic payout based on results
|
|
1328
|
-
- Time limits for player actions
|
|
1329
|
-
- House edge enforcement
|
|
1330
|
-
|
|
1331
|
-
Example: Coin Flip
|
|
1332
|
-
1. Player commits hash(choice + nonce)
|
|
1333
|
-
2. House commits hash(choice + nonce)
|
|
1334
|
-
3. Both reveal - contract determines winner
|
|
1335
|
-
4. Automatic payout to winner
|
|
1336
|
-
|
|
1337
|
-
Perfect for trustless gambling and games!`);
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
// Initialize demo on page load
|
|
1341
|
-
window.onload = function() {
|
|
1342
|
-
log('basics-output', '🌟 Welcome to BSV Smart Contract Demo!', 'info');
|
|
1343
|
-
log('basics-output', '👆 Click "Load BSV Smart Contract Library" to begin', 'info');
|
|
1344
|
-
};
|
|
1345
|
-
</script>
|
|
1346
|
-
</body>
|
|
1347
|
-
</html>
|