smartledger-bsv 3.3.2 → 3.3.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 +220 -79
- package/README.md +283 -71
- package/bsv-covenant.min.js +26 -3
- package/bsv-gdaf.min.js +11 -9
- package/bsv-ltp.min.js +10 -8
- package/bsv-mnemonic.min.js +4 -4
- package/bsv-script-helper.min.js +2 -2
- package/bsv-security.min.js +3 -24
- package/bsv-shamir.min.js +2 -2
- package/bsv-smartcontract.min.js +10 -8
- package/bsv.bundle.js +9 -9
- package/bsv.min.js +10 -8
- package/build/webpack.bundle.config.js +2 -2
- package/build/webpack.config.js +2 -2
- package/build/webpack.covenant.config.js +2 -2
- package/build/webpack.gdaf.config.js +6 -43
- package/build/webpack.script-helper.config.js +2 -2
- package/build/webpack.security.config.js +2 -2
- package/build/webpack.smartcontract.config.js +2 -2
- package/bundle-entry.js +1 -341
- package/covenant-entry.js +1 -44
- package/demos/README.md +188 -0
- package/{architecture_demo.js → demos/architecture_demo.js} +2 -2
- package/demos/bsv_wallet_demo.js +242 -0
- package/{complete_ltp_demo.js → demos/complete_ltp_demo.js} +1 -1
- package/demos/debug_tools_demo.js +87 -0
- package/demos/demo_features.js +123 -0
- package/demos/easy_interface_demo.js +109 -0
- package/demos/ecies_demo.js +182 -0
- package/demos/gdaf_core_test.js +131 -0
- package/demos/gdaf_demo.js +237 -0
- package/demos/ltp_demo.js +361 -0
- package/demos/ltp_primitives_demo.js +403 -0
- package/demos/message_demo.js +209 -0
- package/demos/preimage_separation_demo.js +383 -0
- package/demos/script_helper_demo.js +289 -0
- package/demos/security_demo.js +287 -0
- package/{shamir_demo.js → demos/shamir_demo.js} +1 -1
- package/{simple_demo.js → demos/simple_demo.js} +1 -1
- package/demos/simple_p2pkh_demo.js +169 -0
- package/demos/simple_utxo_preimage_demo.js +196 -0
- package/demos/smart_contract_demo.html +1347 -0
- package/demos/smart_contract_demo.js +910 -0
- package/demos/utxo_generator_demo.js +244 -0
- package/demos/validation_pipeline_demo.js +155 -0
- package/demos/web3keys.html +740 -0
- package/docs/BUNDLE_UPDATE_SUMMARY.md +40 -0
- package/docs/DOCUMENTATION_REVIEW_REPORT.md +295 -0
- package/docs/FIX_CREATEHMAC_ISSUE.md +91 -0
- package/docs/MODULE_REFERENCE_COMPLETE.md +330 -0
- package/docs/README.md +107 -79
- package/docs/SMARTLEDGER_BSV_USAGE_ANSWERS.md +477 -0
- package/docs/SMARTLEDGER_BSV_USAGE_EXAMPLES.js +372 -0
- package/docs/SMARTLEDGER_BSV_USAGE_GUIDE.md +555 -0
- package/docs/SMART_CONTRACT_DEVELOPMENT_GUIDE.md +1459 -0
- package/docs/advanced/LEGAL_TOKEN_PROTOCOL.md +411 -0
- package/docs/advanced/SMART_CONTRACT_GUIDE.md +1255 -0
- package/docs/advanced/UTXO_MANAGER_GUIDE.md +851 -0
- package/docs/api/LTP.md +334 -0
- package/docs/getting-started/INSTALLATION.md +410 -0
- package/docs/getting-started/QUICK_START.md +180 -0
- package/docs/migration/FROM_BSV_1_5_6.md +260 -0
- package/docs/technical/GDAF_DEVELOPER_INTERFACE.md +187 -0
- package/docs/technical/GDAF_IMPLEMENTATION_COMPLETE.md +190 -0
- package/docs/technical/SHAMIR_INTEGRATION_SUMMARY.md +165 -0
- package/docs/technical/roadmap.md +1250 -0
- package/docs/technical/trust_law.md +142 -0
- package/examples/complete_workflow_demo.js +783 -0
- package/examples/definitive_working_demo.js +261 -0
- package/examples/final_working_contracts.js +338 -0
- package/examples/smart_contract_templates.js +718 -0
- package/examples/working_smart_contracts.js +348 -0
- package/gdaf-entry.js +2 -54
- package/index.js +32 -0
- package/lib/mnemonic/pbkdf2.browser.js +69 -0
- package/lib/mnemonic/pbkdf2.js +2 -68
- package/lib/mnemonic/pbkdf2.node.js +68 -0
- package/ltp-entry.js +2 -92
- package/package.json +21 -8
- package/script-helper-entry.js +1 -49
- package/security-entry.js +1 -70
- package/shamir-entry.js +1 -173
- package/smartcontract-entry.js +1 -133
- package/tests/browser-compatibility/README.md +35 -0
- package/tests/browser-compatibility/test-cdn-vs-local.html +186 -0
- package/tests/browser-compatibility/test-pbkdf2.html +51 -0
- package/tests/test_builtin_verify.js +117 -0
- package/tests/test_debug_integration.js +71 -0
- package/tests/test_ecdsa_little.js +70 -0
- package/tests/test_smartverify_der.js +110 -0
- package/utilities/blockchain-state.js +155 -155
- package/utilities/blockchain-state.json +103293 -5244
- package/utilities/miner-simulator.js +354 -358
- package/utilities/mock-utxo-generator.js +54 -54
- package/utilities/raw-tx-examples.js +120 -122
- package/utilities/success-demo.js +104 -105
- package/utilities/transaction-examples.js +188 -188
- package/utilities/utxo-manager.js +91 -91
- package/utilities/wallet-setup.js +79 -80
- package/utilities/working-signature-demo.js +108 -110
- package/SECURITY.md +0 -75
- package/build/bsv-covenant.min.js +0 -10
- package/build/bsv-script-helper.min.js +0 -10
- package/build/bsv-security.min.js +0 -31
- package/build/bsv-smartcontract.min.js +0 -39
- package/build/bsv.bundle.js +0 -39
- package/build/bsv.min.js +0 -39
- package/validation_test.js +0 -97
- /package/docs/{ADVANCED_COVENANT_DEVELOPMENT.md → advanced/ADVANCED_COVENANT_DEVELOPMENT.md} +0 -0
- /package/docs/{CUSTOM_SCRIPT_DEVELOPMENT.md → advanced/CUSTOM_SCRIPT_DEVELOPMENT.md} +0 -0
- /package/docs/{block.md → api/BLOCKS.md} +0 -0
- /package/docs/{ecies.md → api/ECIES.md} +0 -0
- /package/docs/{networks.md → api/NETWORKS.md} +0 -0
- /package/docs/{script.md → api/SCRIPTS.md} +0 -0
- /package/docs/{transaction.md → api/TRANSACTIONS.md} +0 -0
- /package/docs/{unspentoutput.md → api/UTXO.md} +0 -0
- /package/{test_shamir.js → tests/test_shamir.js} +0 -0
- /package/{test_standalone_shamir.html → tests/test_standalone_shamir.html} +0 -0
|
@@ -0,0 +1,910 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* SmartLedger-BSV Smart Contract Demo (Node.js Version)
|
|
4
|
+
* ====================================================
|
|
5
|
+
*
|
|
6
|
+
* Interactive command-line demo showcasing the powerful smart contract
|
|
7
|
+
* capabilities of the SmartLedger BSV library. This is the Node.js equivalent
|
|
8
|
+
* of the HTML demo, perfect for developers and automated testing.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node smart_contract_demo.js
|
|
12
|
+
* node smart_contract_demo.js --help
|
|
13
|
+
* node smart_contract_demo.js --feature covenant
|
|
14
|
+
* node smart_contract_demo.js --feature preimage
|
|
15
|
+
* node smart_contract_demo.js --feature utxo
|
|
16
|
+
* node smart_contract_demo.js --feature scripts
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const bsv = require('../index');
|
|
20
|
+
const readline = require('readline');
|
|
21
|
+
|
|
22
|
+
// Try to load chalk for colored output, fallback to plain text
|
|
23
|
+
let chalk;
|
|
24
|
+
try {
|
|
25
|
+
chalk = require('chalk');
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// Fallback for systems without chalk
|
|
28
|
+
chalk = {
|
|
29
|
+
cyan: (str) => str,
|
|
30
|
+
green: (str) => str,
|
|
31
|
+
red: (str) => str,
|
|
32
|
+
yellow: (str) => str,
|
|
33
|
+
blue: (str) => str,
|
|
34
|
+
magenta: (str) => str,
|
|
35
|
+
white: (str) => str,
|
|
36
|
+
gray: (str) => str,
|
|
37
|
+
bold: (str) => str
|
|
38
|
+
};
|
|
39
|
+
// Chain methods
|
|
40
|
+
Object.keys(chalk).forEach(color => {
|
|
41
|
+
chalk[color].bold = chalk[color];
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ASCII Art Header
|
|
46
|
+
const HEADER = `
|
|
47
|
+
╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
48
|
+
║ ║
|
|
49
|
+
║ 🚀 SmartLedger-BSV Smart Contract Framework Demo (Node.js) ║
|
|
50
|
+
║ ║
|
|
51
|
+
║ Explore covenant creation, preimage parsing, script building, ║
|
|
52
|
+
║ and UTXO management with real Bitcoin SV functionality. ║
|
|
53
|
+
║ ║
|
|
54
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
// Global state
|
|
58
|
+
let currentUTXO = null;
|
|
59
|
+
let currentCovenant = null;
|
|
60
|
+
let SmartContract = null;
|
|
61
|
+
|
|
62
|
+
// CLI Interface
|
|
63
|
+
const rl = readline.createInterface({
|
|
64
|
+
input: process.stdin,
|
|
65
|
+
output: process.stdout,
|
|
66
|
+
prompt: chalk.cyan('smartledger-bsv> ')
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Utility Functions
|
|
71
|
+
*/
|
|
72
|
+
function log(message, type = 'info') {
|
|
73
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
74
|
+
const prefix = `[${timestamp}]`;
|
|
75
|
+
|
|
76
|
+
switch (type) {
|
|
77
|
+
case 'success':
|
|
78
|
+
console.log(chalk.green(`${prefix} ✅ ${message}`));
|
|
79
|
+
break;
|
|
80
|
+
case 'error':
|
|
81
|
+
console.log(chalk.red(`${prefix} ❌ ${message}`));
|
|
82
|
+
break;
|
|
83
|
+
case 'warning':
|
|
84
|
+
console.log(chalk.yellow(`${prefix} ⚠️ ${message}`));
|
|
85
|
+
break;
|
|
86
|
+
case 'info':
|
|
87
|
+
default:
|
|
88
|
+
console.log(chalk.blue(`${prefix} ℹ️ ${message}`));
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function logHeader(title) {
|
|
94
|
+
console.log('\n' + chalk.cyan('═'.repeat(80)));
|
|
95
|
+
console.log(chalk.cyan.bold(`🔹 ${title}`));
|
|
96
|
+
console.log(chalk.cyan('═'.repeat(80)));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function logSubHeader(title) {
|
|
100
|
+
console.log('\n' + chalk.magenta('─'.repeat(60)));
|
|
101
|
+
console.log(chalk.magenta.bold(`📌 ${title}`));
|
|
102
|
+
console.log(chalk.magenta('─'.repeat(60)));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Feature 1: BSV Library Basics
|
|
107
|
+
*/
|
|
108
|
+
function loadLibrary() {
|
|
109
|
+
logHeader('Loading BSV Smart Contract Library');
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
// Check if BSV library is available
|
|
113
|
+
if (typeof bsv === 'undefined') {
|
|
114
|
+
throw new Error('BSV library not loaded. Please ensure the module is properly installed.');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
log('BSV library loaded successfully!', 'success');
|
|
118
|
+
log(`BSV version: ${bsv.version || 'v3.3.3'}`, 'info');
|
|
119
|
+
|
|
120
|
+
// Check available SmartLedger modules
|
|
121
|
+
const availableModules = [];
|
|
122
|
+
if (bsv.SmartContract) availableModules.push('SmartContract');
|
|
123
|
+
if (bsv.LTP) availableModules.push('LTP');
|
|
124
|
+
if (bsv.Security) availableModules.push('Security');
|
|
125
|
+
if (bsv.GDAF) availableModules.push('GDAF');
|
|
126
|
+
if (bsv.Shamir) availableModules.push('Shamir');
|
|
127
|
+
|
|
128
|
+
log(`Available modules: ${availableModules.join(', ')}`, 'info');
|
|
129
|
+
log('Core BSV classes: Transaction, Script, PrivateKey, Address', 'info');
|
|
130
|
+
|
|
131
|
+
// Initialize SmartContract reference
|
|
132
|
+
if (bsv.SmartContract) {
|
|
133
|
+
SmartContract = bsv.SmartContract;
|
|
134
|
+
log('SmartContract module ready!', 'success');
|
|
135
|
+
} else {
|
|
136
|
+
log('SmartContract module not found in bundle', 'warning');
|
|
137
|
+
SmartContract = null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
log('Ready for smart contract development!', 'success');
|
|
141
|
+
|
|
142
|
+
} catch (error) {
|
|
143
|
+
log(`Error loading library: ${error.message}`, 'error');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function showFeatures() {
|
|
148
|
+
logHeader('BSV Smart Contract Features');
|
|
149
|
+
|
|
150
|
+
const features = [
|
|
151
|
+
'🔒 Covenant Builder - Create complex spending conditions',
|
|
152
|
+
'🧾 Preimage Parser - Extract BIP-143 transaction fields',
|
|
153
|
+
'🛠️ Script Tools - Build and debug Bitcoin Scripts',
|
|
154
|
+
'💎 UTXO Generator - Create test UTXOs for development',
|
|
155
|
+
'📊 SIGHASH Analysis - Understand signature hash types',
|
|
156
|
+
'🏗️ ASM Generator - Convert JavaScript to Bitcoin Script',
|
|
157
|
+
'🔍 Script Debugger - Step-through script execution',
|
|
158
|
+
'⚡ Script Optimizer - Minimize script size and cost',
|
|
159
|
+
'🧪 Local Testing - Verify scripts without blockchain',
|
|
160
|
+
'📦 Production Ready - Deploy to BSV mainnet'
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
features.forEach(feature => {
|
|
164
|
+
log(feature, 'success');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
log('All features available in @smartledger/bsv package!', 'info');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function runBasicTests() {
|
|
171
|
+
logHeader('Running Basic Smart Contract Tests');
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
// Test 1: Private Key Generation
|
|
175
|
+
logSubHeader('Test 1: Private Key Generation');
|
|
176
|
+
const privateKey = new bsv.PrivateKey();
|
|
177
|
+
const address = privateKey.toAddress();
|
|
178
|
+
log(`Generated address: ${address.toString()}`, 'success');
|
|
179
|
+
|
|
180
|
+
// Test 2: Transaction Creation
|
|
181
|
+
logSubHeader('Test 2: Transaction Creation');
|
|
182
|
+
const tx = new bsv.Transaction();
|
|
183
|
+
log(`Created transaction: ${tx.id || 'empty transaction'}`, 'success');
|
|
184
|
+
|
|
185
|
+
// Test 3: Script Building
|
|
186
|
+
logSubHeader('Test 3: Script Building');
|
|
187
|
+
const script = bsv.Script.buildPublicKeyHashOut(address);
|
|
188
|
+
log(`Built P2PKH script: ${script.toString().substring(0, 50)}...`, 'success');
|
|
189
|
+
|
|
190
|
+
// Test 4: Mock UTXO
|
|
191
|
+
logSubHeader('Test 4: Mock UTXO Creation');
|
|
192
|
+
const utxo = {
|
|
193
|
+
txId: 'mock_' + Date.now(),
|
|
194
|
+
outputIndex: 0,
|
|
195
|
+
address: address.toString(),
|
|
196
|
+
script: script.toString(),
|
|
197
|
+
satoshis: 100000
|
|
198
|
+
};
|
|
199
|
+
log(`Created mock UTXO: ${utxo.satoshis} satoshis`, 'success');
|
|
200
|
+
|
|
201
|
+
log('All basic tests passed! Smart contract functionality ready.', 'success');
|
|
202
|
+
|
|
203
|
+
} catch (error) {
|
|
204
|
+
log(`Test failed: ${error.message}`, 'error');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Feature 2: Covenant Builder
|
|
210
|
+
*/
|
|
211
|
+
function generateCovenant(type = 'simple', amount = 100000, address = null) {
|
|
212
|
+
logHeader('Generating Covenant');
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
// Generate keys for covenant
|
|
216
|
+
const covenantKey = new bsv.PrivateKey();
|
|
217
|
+
const covenantAddress = covenantKey.toAddress();
|
|
218
|
+
|
|
219
|
+
log(`Covenant Type: ${type}`, 'info');
|
|
220
|
+
log(`Amount: ${amount} satoshis`, 'info');
|
|
221
|
+
log(`Covenant Address: ${covenantAddress.toString()}`, 'info');
|
|
222
|
+
|
|
223
|
+
// Build covenant script based on type
|
|
224
|
+
let script;
|
|
225
|
+
switch (type) {
|
|
226
|
+
case 'simple':
|
|
227
|
+
script = buildSimpleCovenant(amount, address);
|
|
228
|
+
break;
|
|
229
|
+
case 'timelock':
|
|
230
|
+
script = buildTimelockCovenant(amount, address, 144); // 144 blocks ≈ 24 hours
|
|
231
|
+
break;
|
|
232
|
+
case 'multisig':
|
|
233
|
+
script = buildMultisigCovenant(amount, address, 2, 3); // 2-of-3 multisig
|
|
234
|
+
break;
|
|
235
|
+
case 'conditional':
|
|
236
|
+
script = buildConditionalCovenant(amount, address);
|
|
237
|
+
break;
|
|
238
|
+
default:
|
|
239
|
+
throw new Error('Unknown covenant type');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
currentCovenant = {
|
|
243
|
+
type: type,
|
|
244
|
+
amount: amount,
|
|
245
|
+
address: address,
|
|
246
|
+
script: script,
|
|
247
|
+
covenantKey: covenantKey,
|
|
248
|
+
covenantAddress: covenantAddress
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
log('Covenant generated successfully!', 'success');
|
|
252
|
+
log(`Script length: ${script.toBuffer().length} bytes`, 'info');
|
|
253
|
+
|
|
254
|
+
return currentCovenant;
|
|
255
|
+
|
|
256
|
+
} catch (error) {
|
|
257
|
+
log(`Covenant generation failed: ${error.message}`, 'error');
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function buildSimpleCovenant(amount, recipientAddress) {
|
|
263
|
+
// Simple covenant: can only be spent to specific address with exact amount
|
|
264
|
+
const script = new bsv.Script();
|
|
265
|
+
|
|
266
|
+
// Add covenant logic (simplified for demo)
|
|
267
|
+
script.add(bsv.Opcode.OP_DUP)
|
|
268
|
+
.add(bsv.Opcode.OP_HASH160)
|
|
269
|
+
.add(bsv.Address.fromString(recipientAddress || '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa').hashBuffer)
|
|
270
|
+
.add(bsv.Opcode.OP_EQUALVERIFY)
|
|
271
|
+
.add(bsv.Opcode.OP_CHECKSIG);
|
|
272
|
+
|
|
273
|
+
return script;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function buildTimelockCovenant(amount, recipientAddress, blocks) {
|
|
277
|
+
// SmartLedger-BSV timelock using preimage validation
|
|
278
|
+
const script = new bsv.Script();
|
|
279
|
+
|
|
280
|
+
// Preimage-based timelock logic (SmartLedger-BSV method)
|
|
281
|
+
script.add(bsv.Opcode.OP_DUP)
|
|
282
|
+
.add(36) // Start position for nLockTime
|
|
283
|
+
.add(4) // Length of nLockTime field
|
|
284
|
+
.add(bsv.Opcode.OP_SUBSTR)
|
|
285
|
+
.add(bsv.Opcode.OP_BIN2NUM)
|
|
286
|
+
.add(blocks) // Required block height
|
|
287
|
+
.add(bsv.Opcode.OP_GREATERTHANOREQUAL)
|
|
288
|
+
.add(bsv.Opcode.OP_VERIFY)
|
|
289
|
+
.add(bsv.Opcode.OP_HASH256)
|
|
290
|
+
.add('placeholder_preimage_hash')
|
|
291
|
+
.add(bsv.Opcode.OP_EQUALVERIFY)
|
|
292
|
+
.add(bsv.Opcode.OP_DROP)
|
|
293
|
+
.add(bsv.Address.fromString(recipientAddress || '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa').hashBuffer)
|
|
294
|
+
.add(bsv.Opcode.OP_CHECKSIG);
|
|
295
|
+
|
|
296
|
+
return script;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function buildMultisigCovenant(amount, recipientAddress, m, n) {
|
|
300
|
+
// Multisig covenant: requires m-of-n signatures
|
|
301
|
+
const script = new bsv.Script();
|
|
302
|
+
|
|
303
|
+
// Generate dummy public keys for demo
|
|
304
|
+
const pubkeys = [];
|
|
305
|
+
for (let i = 0; i < n; i++) {
|
|
306
|
+
pubkeys.push(new bsv.PrivateKey().publicKey);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
script.add(bsv.Opcode.OP_0); // Bug in CHECKMULTISIG requires extra value
|
|
310
|
+
for (let i = 0; i < m; i++) {
|
|
311
|
+
script.add(bsv.Opcode.OP_0); // Placeholder for signatures
|
|
312
|
+
}
|
|
313
|
+
script.add(m);
|
|
314
|
+
pubkeys.forEach(pubkey => script.add(pubkey.toBuffer()));
|
|
315
|
+
script.add(n);
|
|
316
|
+
script.add(bsv.Opcode.OP_CHECKMULTISIG);
|
|
317
|
+
|
|
318
|
+
return script;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function buildConditionalCovenant(amount, recipientAddress) {
|
|
322
|
+
// SmartLedger-BSV conditional covenant using preimage validation
|
|
323
|
+
const script = new bsv.Script();
|
|
324
|
+
|
|
325
|
+
script.add(bsv.Opcode.OP_IF)
|
|
326
|
+
.add(bsv.Opcode.OP_DUP)
|
|
327
|
+
.add(bsv.Opcode.OP_HASH256)
|
|
328
|
+
.add('placeholder_preimage_hash_1')
|
|
329
|
+
.add(bsv.Opcode.OP_EQUALVERIFY)
|
|
330
|
+
.add(bsv.Opcode.OP_DROP)
|
|
331
|
+
.add(bsv.Address.fromString(recipientAddress || '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa').hashBuffer)
|
|
332
|
+
.add(bsv.Opcode.OP_CHECKSIG)
|
|
333
|
+
.add(bsv.Opcode.OP_ELSE)
|
|
334
|
+
.add(bsv.Opcode.OP_DUP)
|
|
335
|
+
.add(bsv.Opcode.OP_HASH256)
|
|
336
|
+
.add('placeholder_preimage_hash_2')
|
|
337
|
+
.add(bsv.Opcode.OP_EQUALVERIFY)
|
|
338
|
+
.add(bsv.Opcode.OP_DROP)
|
|
339
|
+
.add(bsv.Address.fromString(recipientAddress || '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa').hashBuffer)
|
|
340
|
+
.add(bsv.Opcode.OP_CHECKSIG)
|
|
341
|
+
.add(bsv.Opcode.OP_ENDIF);
|
|
342
|
+
|
|
343
|
+
return script;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function testCovenant() {
|
|
347
|
+
if (!currentCovenant) {
|
|
348
|
+
log('No covenant generated. Please generate a covenant first.', 'error');
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
logHeader('Testing Covenant');
|
|
353
|
+
|
|
354
|
+
try {
|
|
355
|
+
// Create a test transaction
|
|
356
|
+
const tx = new bsv.Transaction();
|
|
357
|
+
|
|
358
|
+
// Add input (mock UTXO)
|
|
359
|
+
tx.from({
|
|
360
|
+
txId: 'mock_covenant_input_' + Date.now(),
|
|
361
|
+
outputIndex: 0,
|
|
362
|
+
script: currentCovenant.script.toString(),
|
|
363
|
+
satoshis: currentCovenant.amount
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// Add output
|
|
367
|
+
tx.to(currentCovenant.address || currentCovenant.covenantAddress.toString(), currentCovenant.amount - 1000);
|
|
368
|
+
|
|
369
|
+
log('Test transaction created successfully!', 'success');
|
|
370
|
+
log(`Transaction ID: ${tx.id}`, 'info');
|
|
371
|
+
log(`Input amount: ${currentCovenant.amount} satoshis`, 'info');
|
|
372
|
+
log(`Output amount: ${currentCovenant.amount - 1000} satoshis`, 'info');
|
|
373
|
+
log('Fee: 1000 satoshis', 'info');
|
|
374
|
+
|
|
375
|
+
} catch (error) {
|
|
376
|
+
log(`Covenant test failed: ${error.message}`, 'error');
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function showCovenantScript() {
|
|
381
|
+
if (!currentCovenant) {
|
|
382
|
+
log('No covenant generated. Please generate a covenant first.', 'error');
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
logHeader('Covenant Script ASM');
|
|
387
|
+
|
|
388
|
+
console.log(chalk.green('\nScript ASM:'));
|
|
389
|
+
console.log(chalk.white(currentCovenant.script.toString()));
|
|
390
|
+
|
|
391
|
+
log(`Script size: ${currentCovenant.script.toBuffer().length} bytes`, 'info');
|
|
392
|
+
log(`Script hex: ${currentCovenant.script.toBuffer().toString('hex')}`, 'info');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Feature 3: Preimage Parser
|
|
397
|
+
*/
|
|
398
|
+
function generateSampleTx() {
|
|
399
|
+
logHeader('Generating Sample Transaction');
|
|
400
|
+
|
|
401
|
+
try {
|
|
402
|
+
const privateKey = new bsv.PrivateKey();
|
|
403
|
+
const address = privateKey.toAddress();
|
|
404
|
+
|
|
405
|
+
const tx = new bsv.Transaction()
|
|
406
|
+
.from({
|
|
407
|
+
txId: 'sample_' + Date.now(),
|
|
408
|
+
outputIndex: 0,
|
|
409
|
+
script: bsv.Script.buildPublicKeyHashOut(address).toString(),
|
|
410
|
+
satoshis: 100000
|
|
411
|
+
})
|
|
412
|
+
.to('1BitcoinEaterAddressDontSendf59kuE', 50000)
|
|
413
|
+
.change(address)
|
|
414
|
+
.sign(privateKey);
|
|
415
|
+
|
|
416
|
+
log('Sample transaction generated!', 'success');
|
|
417
|
+
log(`Transaction ID: ${tx.id}`, 'info');
|
|
418
|
+
log(`Transaction size: ${tx.toString().length / 2} bytes`, 'info');
|
|
419
|
+
|
|
420
|
+
console.log(chalk.green('\nTransaction Hex:'));
|
|
421
|
+
console.log(chalk.white(tx.toString()));
|
|
422
|
+
|
|
423
|
+
return tx.toString();
|
|
424
|
+
|
|
425
|
+
} catch (error) {
|
|
426
|
+
log(`Failed to generate sample: ${error.message}`, 'error');
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function parsePreimage(txHex) {
|
|
432
|
+
if (!txHex) {
|
|
433
|
+
log('Please provide transaction hex or generate a sample first.', 'error');
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
logHeader('Parsing Preimage');
|
|
438
|
+
|
|
439
|
+
try {
|
|
440
|
+
const tx = new bsv.Transaction(txHex);
|
|
441
|
+
|
|
442
|
+
// Extract preimage components (BIP-143)
|
|
443
|
+
logSubHeader('BIP-143 Preimage Components');
|
|
444
|
+
log(`Version: ${tx.version}`, 'success');
|
|
445
|
+
log(`Input Count: ${tx.inputs.length}`, 'success');
|
|
446
|
+
log(`Output Count: ${tx.outputs.length}`, 'success');
|
|
447
|
+
log(`Lock Time: ${tx.nLockTime}`, 'success');
|
|
448
|
+
|
|
449
|
+
// Show input details
|
|
450
|
+
logSubHeader('Input Details');
|
|
451
|
+
tx.inputs.forEach((input, index) => {
|
|
452
|
+
log(`Input ${index}: ${input.prevTxId}:${input.outputIndex}`, 'info');
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// Show output details
|
|
456
|
+
logSubHeader('Output Details');
|
|
457
|
+
tx.outputs.forEach((output, index) => {
|
|
458
|
+
log(`Output ${index}: ${output.satoshis} sats to ${output.script.toString().substring(0, 50)}...`, 'info');
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
} catch (error) {
|
|
462
|
+
log(`Preimage parsing failed: ${error.message}`, 'error');
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function extractSighash() {
|
|
467
|
+
logHeader('SIGHASH Information');
|
|
468
|
+
|
|
469
|
+
// SIGHASH flags
|
|
470
|
+
const sighashTypes = {
|
|
471
|
+
0x01: 'SIGHASH_ALL',
|
|
472
|
+
0x02: 'SIGHASH_NONE',
|
|
473
|
+
0x03: 'SIGHASH_SINGLE',
|
|
474
|
+
0x81: 'SIGHASH_ALL | ANYONECANPAY',
|
|
475
|
+
0x82: 'SIGHASH_NONE | ANYONECANPAY',
|
|
476
|
+
0x83: 'SIGHASH_SINGLE | ANYONECANPAY'
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
logSubHeader('Available SIGHASH Types');
|
|
480
|
+
|
|
481
|
+
Object.entries(sighashTypes).forEach(([flag, name]) => {
|
|
482
|
+
log(`${flag}: ${name}`, 'info');
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
log('Most common: SIGHASH_ALL (0x01) - signs all inputs and outputs', 'success');
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Feature 4: UTXO Generator
|
|
490
|
+
*/
|
|
491
|
+
function generateUTXO(wif = null, amount = 100000, network = 'livenet') {
|
|
492
|
+
logHeader('Generating Mock UTXO');
|
|
493
|
+
|
|
494
|
+
try {
|
|
495
|
+
// Generate or use provided private key
|
|
496
|
+
let privateKey;
|
|
497
|
+
if (wif) {
|
|
498
|
+
privateKey = bsv.PrivateKey.fromWIF(wif);
|
|
499
|
+
log('Using provided private key', 'info');
|
|
500
|
+
} else {
|
|
501
|
+
privateKey = new bsv.PrivateKey(undefined, network);
|
|
502
|
+
log('Generated new random private key', 'info');
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const address = privateKey.toAddress(network);
|
|
506
|
+
const script = bsv.Script.buildPublicKeyHashOut(address);
|
|
507
|
+
|
|
508
|
+
// Create mock UTXO
|
|
509
|
+
currentUTXO = {
|
|
510
|
+
txId: 'mock_utxo_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9),
|
|
511
|
+
outputIndex: 0,
|
|
512
|
+
address: address.toString(),
|
|
513
|
+
script: script.toString(),
|
|
514
|
+
satoshis: amount,
|
|
515
|
+
privateKey: privateKey,
|
|
516
|
+
network: network
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
log('Mock UTXO generated successfully!', 'success');
|
|
520
|
+
log(`UTXO ID: ${currentUTXO.txId}:${currentUTXO.outputIndex}`, 'info');
|
|
521
|
+
log(`Address: ${currentUTXO.address}`, 'info');
|
|
522
|
+
log(`Value: ${currentUTXO.satoshis} satoshis`, 'info');
|
|
523
|
+
log(`Network: ${currentUTXO.network}`, 'info');
|
|
524
|
+
log(`Private Key (WIF): ${currentUTXO.privateKey.toWIF()}`, 'info');
|
|
525
|
+
|
|
526
|
+
return currentUTXO;
|
|
527
|
+
|
|
528
|
+
} catch (error) {
|
|
529
|
+
log(`UTXO generation failed: ${error.message}`, 'error');
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function createSpendingTx() {
|
|
535
|
+
if (!currentUTXO) {
|
|
536
|
+
log('No UTXO available. Please generate a UTXO first.', 'error');
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
logHeader('Creating Spending Transaction');
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
const recipientAddress = '1BitcoinEaterAddressDontSendf59kuE'; // Burn address for demo
|
|
544
|
+
const fee = 1000;
|
|
545
|
+
const outputAmount = currentUTXO.satoshis - fee;
|
|
546
|
+
|
|
547
|
+
if (outputAmount <= 0) {
|
|
548
|
+
throw new Error('Insufficient funds for transaction fee');
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const tx = new bsv.Transaction()
|
|
552
|
+
.from(currentUTXO)
|
|
553
|
+
.to(recipientAddress, outputAmount)
|
|
554
|
+
.sign(currentUTXO.privateKey);
|
|
555
|
+
|
|
556
|
+
log('Spending transaction created!', 'success');
|
|
557
|
+
log(`Transaction ID: ${tx.id}`, 'info');
|
|
558
|
+
log(`Input: ${currentUTXO.satoshis} satoshis`, 'info');
|
|
559
|
+
log(`Output: ${outputAmount} satoshis`, 'info');
|
|
560
|
+
log(`Fee: ${fee} satoshis`, 'info');
|
|
561
|
+
log(`Transaction size: ${tx.toString().length / 2} bytes`, 'info');
|
|
562
|
+
|
|
563
|
+
console.log(chalk.green('\nRaw Transaction:'));
|
|
564
|
+
console.log(chalk.white(tx.toString().substring(0, 100) + '...'));
|
|
565
|
+
|
|
566
|
+
return tx;
|
|
567
|
+
|
|
568
|
+
} catch (error) {
|
|
569
|
+
log(`Spending transaction failed: ${error.message}`, 'error');
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function showUTXODetails() {
|
|
575
|
+
if (!currentUTXO) {
|
|
576
|
+
log('No UTXO available. Please generate a UTXO first.', 'error');
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
logHeader('Detailed UTXO Information');
|
|
581
|
+
|
|
582
|
+
console.log(chalk.green('\nUTXO Details:'));
|
|
583
|
+
console.log(chalk.white(`Transaction ID: ${currentUTXO.txId}`));
|
|
584
|
+
console.log(chalk.white(`Output Index: ${currentUTXO.outputIndex}`));
|
|
585
|
+
console.log(chalk.white(`Address: ${currentUTXO.address}`));
|
|
586
|
+
console.log(chalk.white(`Value: ${currentUTXO.satoshis} satoshis (${(currentUTXO.satoshis / 100000000).toFixed(8)} BSV)`));
|
|
587
|
+
console.log(chalk.white(`Network: ${currentUTXO.network}`));
|
|
588
|
+
|
|
589
|
+
console.log(chalk.green('\nScript Details:'));
|
|
590
|
+
console.log(chalk.white(`Script ASM: ${currentUTXO.script}`));
|
|
591
|
+
console.log(chalk.white(`Script Size: ${Buffer.from(currentUTXO.script, 'hex').length} bytes`));
|
|
592
|
+
|
|
593
|
+
console.log(chalk.green('\nPrivate Key:'));
|
|
594
|
+
console.log(chalk.white(`WIF: ${currentUTXO.privateKey.toWIF()}`));
|
|
595
|
+
console.log(chalk.white(`Hex: ${currentUTXO.privateKey.toString()}`));
|
|
596
|
+
console.log(chalk.white(`Compressed: ${currentUTXO.privateKey.compressed}`));
|
|
597
|
+
|
|
598
|
+
console.log(chalk.green('\nAddress Details:'));
|
|
599
|
+
console.log(chalk.white(`Hash160: ${bsv.Address.fromString(currentUTXO.address).hashBuffer.toString('hex')}`));
|
|
600
|
+
console.log(chalk.white(`Version: ${bsv.Address.fromString(currentUTXO.address).network.pubkeyhash}`));
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Feature 5: Script Tools
|
|
605
|
+
*/
|
|
606
|
+
function buildScript(asmCode, scriptType = 'custom') {
|
|
607
|
+
logHeader('Building Script');
|
|
608
|
+
|
|
609
|
+
try {
|
|
610
|
+
if (!asmCode) {
|
|
611
|
+
throw new Error('Please provide script ASM code');
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
const script = bsv.Script.fromASM(asmCode);
|
|
615
|
+
|
|
616
|
+
log('Script built successfully!', 'success');
|
|
617
|
+
log(`Script type: ${scriptType}`, 'info');
|
|
618
|
+
log(`Script size: ${script.toBuffer().length} bytes`, 'info');
|
|
619
|
+
log(`Script hex: ${script.toBuffer().toString('hex')}`, 'info');
|
|
620
|
+
|
|
621
|
+
console.log(chalk.green('\nScript ASM:'));
|
|
622
|
+
console.log(chalk.white(script.toString()));
|
|
623
|
+
|
|
624
|
+
// Analyze script opcodes
|
|
625
|
+
const opcodes = script.chunks.map(chunk => {
|
|
626
|
+
if (chunk.opcodenum !== undefined) {
|
|
627
|
+
return `OP_${bsv.Opcode.reverseMap[chunk.opcodenum] || chunk.opcodenum}`;
|
|
628
|
+
} else if (chunk.buf) {
|
|
629
|
+
return `DATA(${chunk.buf.length} bytes)`;
|
|
630
|
+
}
|
|
631
|
+
return 'UNKNOWN';
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
log(`Opcodes: ${opcodes.join(', ')}`, 'info');
|
|
635
|
+
|
|
636
|
+
return script;
|
|
637
|
+
|
|
638
|
+
} catch (error) {
|
|
639
|
+
log(`Script building failed: ${error.message}`, 'error');
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function analyzeScript(asmCode) {
|
|
645
|
+
if (!asmCode) {
|
|
646
|
+
log('Please provide script ASM code first.', 'error');
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
logHeader('Analyzing Script');
|
|
651
|
+
|
|
652
|
+
try {
|
|
653
|
+
const script = bsv.Script.fromASM(asmCode);
|
|
654
|
+
|
|
655
|
+
// Script analysis
|
|
656
|
+
const analysis = {
|
|
657
|
+
size: script.toBuffer().length,
|
|
658
|
+
chunks: script.chunks.length,
|
|
659
|
+
isPushOnly: script.isPushOnly(),
|
|
660
|
+
isStandard: true, // Simplified check
|
|
661
|
+
hasTimelock: asmCode.includes('CHECKLOCKTIMEVERIFY') || asmCode.includes('CHECKSEQUENCEVERIFY'),
|
|
662
|
+
hasMultisig: asmCode.includes('CHECKMULTISIG'),
|
|
663
|
+
hasHash: asmCode.includes('HASH160') || asmCode.includes('HASH256'),
|
|
664
|
+
complexity: 'Medium' // Simplified assessment
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
logSubHeader('Script Analysis Results');
|
|
668
|
+
log(`Size: ${analysis.size} bytes`, 'info');
|
|
669
|
+
log(`Chunks: ${analysis.chunks}`, 'info');
|
|
670
|
+
log(`Push-only: ${analysis.isPushOnly ? 'Yes' : 'No'}`, 'info');
|
|
671
|
+
log(`Standard: ${analysis.isStandard ? 'Yes' : 'No'}`, 'info');
|
|
672
|
+
log(`Has timelock: ${analysis.hasTimelock ? 'Yes' : 'No'}`, 'info');
|
|
673
|
+
log(`Has multisig: ${analysis.hasMultisig ? 'Yes' : 'No'}`, 'info');
|
|
674
|
+
log(`Has hash ops: ${analysis.hasHash ? 'Yes' : 'No'}`, 'info');
|
|
675
|
+
log(`Complexity: ${analysis.complexity}`, 'info');
|
|
676
|
+
|
|
677
|
+
// Fee estimation
|
|
678
|
+
const feePerByte = 1; // satoshis per byte
|
|
679
|
+
const estimatedFee = analysis.size * feePerByte;
|
|
680
|
+
log(`Estimated fee: ${estimatedFee} satoshis (at ${feePerByte} sat/byte)`, 'info');
|
|
681
|
+
|
|
682
|
+
return analysis;
|
|
683
|
+
|
|
684
|
+
} catch (error) {
|
|
685
|
+
log(`Script analysis failed: ${error.message}`, 'error');
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Interactive CLI Functions
|
|
692
|
+
*/
|
|
693
|
+
function showMainMenu() {
|
|
694
|
+
console.log(chalk.cyan('\n📋 Available Commands:'));
|
|
695
|
+
console.log(chalk.white(' basics - Load library and run basic tests'));
|
|
696
|
+
console.log(chalk.white(' covenant - Covenant builder demo'));
|
|
697
|
+
console.log(chalk.white(' preimage - Preimage parser demo'));
|
|
698
|
+
console.log(chalk.white(' utxo - UTXO generator demo'));
|
|
699
|
+
console.log(chalk.white(' scripts - Script tools demo'));
|
|
700
|
+
console.log(chalk.white(' examples - Show real-world use cases'));
|
|
701
|
+
console.log(chalk.white(' help - Show this help menu'));
|
|
702
|
+
console.log(chalk.white(' exit - Exit the demo'));
|
|
703
|
+
console.log(chalk.cyan('─'.repeat(60)));
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function showExamples() {
|
|
707
|
+
logHeader('Real-World Use Cases');
|
|
708
|
+
|
|
709
|
+
console.log(chalk.green('\n🏦 Escrow Contracts'));
|
|
710
|
+
console.log(chalk.white('Multi-party escrow with timeout conditions'));
|
|
711
|
+
console.log(chalk.gray('- Buyer and seller can complete transaction normally'));
|
|
712
|
+
console.log(chalk.gray('- If dispute, buyer+arbiter or seller+arbiter can resolve'));
|
|
713
|
+
console.log(chalk.gray('- Includes timeout clause for refund after 30 days'));
|
|
714
|
+
|
|
715
|
+
console.log(chalk.green('\n⏰ Time-locked Payments'));
|
|
716
|
+
console.log(chalk.white('Payments that unlock after specific time'));
|
|
717
|
+
console.log(chalk.gray('- Uses preimage validation instead of OP_CHECKLOCKTIMEVERIFY'));
|
|
718
|
+
console.log(chalk.gray('- Validates nLockTime field from BIP-143 preimage'));
|
|
719
|
+
console.log(chalk.gray('- SmartLedger-BSV OP_PUSH_TX methods'));
|
|
720
|
+
|
|
721
|
+
console.log(chalk.green('\n🔄 Recurring Payments'));
|
|
722
|
+
console.log(chalk.white('Automated recurring payment covenants'));
|
|
723
|
+
console.log(chalk.gray('- Self-perpetuating contract'));
|
|
724
|
+
console.log(chalk.gray('- Fixed payment amounts and intervals'));
|
|
725
|
+
console.log(chalk.gray('- Automatic recipient payment'));
|
|
726
|
+
|
|
727
|
+
console.log(chalk.green('\n🎲 Gaming Contracts'));
|
|
728
|
+
console.log(chalk.white('Provably fair gaming and betting'));
|
|
729
|
+
console.log(chalk.gray('- Commit-reveal schemes for fairness'));
|
|
730
|
+
console.log(chalk.gray('- Automatic payout based on results'));
|
|
731
|
+
console.log(chalk.gray('- Time limits for player actions'));
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
function processCommand(command) {
|
|
735
|
+
const cmd = command.trim().toLowerCase();
|
|
736
|
+
const args = cmd.split(' ');
|
|
737
|
+
|
|
738
|
+
switch (args[0]) {
|
|
739
|
+
case 'basics':
|
|
740
|
+
loadLibrary();
|
|
741
|
+
showFeatures();
|
|
742
|
+
runBasicTests();
|
|
743
|
+
break;
|
|
744
|
+
|
|
745
|
+
case 'covenant':
|
|
746
|
+
if (args[1] === 'generate') {
|
|
747
|
+
const type = args[2] || 'simple';
|
|
748
|
+
const amount = parseInt(args[3]) || 100000;
|
|
749
|
+
generateCovenant(type, amount);
|
|
750
|
+
} else if (args[1] === 'test') {
|
|
751
|
+
testCovenant();
|
|
752
|
+
} else if (args[1] === 'show') {
|
|
753
|
+
showCovenantScript();
|
|
754
|
+
} else {
|
|
755
|
+
console.log(chalk.cyan('\nCovenant Commands:'));
|
|
756
|
+
console.log(chalk.white(' covenant generate [type] [amount] - Generate covenant (simple/timelock/multisig/conditional)'));
|
|
757
|
+
console.log(chalk.white(' covenant test - Test current covenant'));
|
|
758
|
+
console.log(chalk.white(' covenant show - Show covenant script'));
|
|
759
|
+
}
|
|
760
|
+
break;
|
|
761
|
+
|
|
762
|
+
case 'preimage':
|
|
763
|
+
if (args[1] === 'sample') {
|
|
764
|
+
generateSampleTx();
|
|
765
|
+
} else if (args[1] === 'parse') {
|
|
766
|
+
// Would need tx hex input in real scenario
|
|
767
|
+
log('Use: preimage sample first to generate a transaction', 'info');
|
|
768
|
+
} else if (args[1] === 'sighash') {
|
|
769
|
+
extractSighash();
|
|
770
|
+
} else {
|
|
771
|
+
console.log(chalk.cyan('\nPreimage Commands:'));
|
|
772
|
+
console.log(chalk.white(' preimage sample - Generate sample transaction'));
|
|
773
|
+
console.log(chalk.white(' preimage sighash - Show SIGHASH information'));
|
|
774
|
+
}
|
|
775
|
+
break;
|
|
776
|
+
|
|
777
|
+
case 'utxo':
|
|
778
|
+
if (args[1] === 'generate') {
|
|
779
|
+
const amount = parseInt(args[2]) || 100000;
|
|
780
|
+
generateUTXO(null, amount);
|
|
781
|
+
} else if (args[1] === 'spend') {
|
|
782
|
+
createSpendingTx();
|
|
783
|
+
} else if (args[1] === 'show') {
|
|
784
|
+
showUTXODetails();
|
|
785
|
+
} else {
|
|
786
|
+
console.log(chalk.cyan('\nUTXO Commands:'));
|
|
787
|
+
console.log(chalk.white(' utxo generate [amount] - Generate mock UTXO'));
|
|
788
|
+
console.log(chalk.white(' utxo spend - Create spending transaction'));
|
|
789
|
+
console.log(chalk.white(' utxo show - Show UTXO details'));
|
|
790
|
+
}
|
|
791
|
+
break;
|
|
792
|
+
|
|
793
|
+
case 'scripts':
|
|
794
|
+
if (args[1] === 'build') {
|
|
795
|
+
const defaultASM = 'OP_DUP OP_HASH160 OP_PUSHDATA1 0x14 0x1234567890123456789012345678901234567890 OP_EQUALVERIFY OP_CHECKSIG';
|
|
796
|
+
buildScript(defaultASM);
|
|
797
|
+
} else if (args[1] === 'analyze') {
|
|
798
|
+
const defaultASM = 'OP_DUP OP_HASH160 OP_PUSHDATA1 0x14 0x1234567890123456789012345678901234567890 OP_EQUALVERIFY OP_CHECKSIG';
|
|
799
|
+
analyzeScript(defaultASM);
|
|
800
|
+
} else {
|
|
801
|
+
console.log(chalk.cyan('\nScript Commands:'));
|
|
802
|
+
console.log(chalk.white(' scripts build - Build sample P2PKH script'));
|
|
803
|
+
console.log(chalk.white(' scripts analyze - Analyze sample P2PKH script'));
|
|
804
|
+
}
|
|
805
|
+
break;
|
|
806
|
+
|
|
807
|
+
case 'examples':
|
|
808
|
+
showExamples();
|
|
809
|
+
break;
|
|
810
|
+
|
|
811
|
+
case 'help':
|
|
812
|
+
showMainMenu();
|
|
813
|
+
break;
|
|
814
|
+
|
|
815
|
+
case 'exit':
|
|
816
|
+
case 'quit':
|
|
817
|
+
console.log(chalk.green('\n👋 Thanks for using SmartLedger-BSV! Happy coding!'));
|
|
818
|
+
process.exit(0);
|
|
819
|
+
break;
|
|
820
|
+
|
|
821
|
+
case '':
|
|
822
|
+
// Empty command, do nothing
|
|
823
|
+
break;
|
|
824
|
+
|
|
825
|
+
default:
|
|
826
|
+
log(`Unknown command: ${args[0]}. Type 'help' for available commands.`, 'warning');
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Main Function
|
|
833
|
+
*/
|
|
834
|
+
function main() {
|
|
835
|
+
// Check for command line arguments
|
|
836
|
+
const args = process.argv.slice(2);
|
|
837
|
+
|
|
838
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
839
|
+
console.log(chalk.cyan('\nSmartLedger-BSV Smart Contract Demo (Node.js)\n'));
|
|
840
|
+
console.log(chalk.white('Usage:'));
|
|
841
|
+
console.log(chalk.white(' node smart_contract_demo.js - Interactive mode'));
|
|
842
|
+
console.log(chalk.white(' node smart_contract_demo.js --feature basics - Run basics demo'));
|
|
843
|
+
console.log(chalk.white(' node smart_contract_demo.js --feature covenant - Run covenant demo'));
|
|
844
|
+
console.log(chalk.white(' node smart_contract_demo.js --feature preimage - Run preimage demo'));
|
|
845
|
+
console.log(chalk.white(' node smart_contract_demo.js --feature utxo - Run UTXO demo'));
|
|
846
|
+
console.log(chalk.white(' node smart_contract_demo.js --feature scripts - Run scripts demo'));
|
|
847
|
+
console.log(chalk.white(' node smart_contract_demo.js --help - Show this help'));
|
|
848
|
+
process.exit(0);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Check for specific feature demo
|
|
852
|
+
const featureIndex = args.indexOf('--feature');
|
|
853
|
+
if (featureIndex !== -1 && args[featureIndex + 1]) {
|
|
854
|
+
const feature = args[featureIndex + 1];
|
|
855
|
+
console.log(HEADER);
|
|
856
|
+
processCommand(feature);
|
|
857
|
+
process.exit(0);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// Interactive mode
|
|
861
|
+
console.log(HEADER);
|
|
862
|
+
log('Welcome to SmartLedger-BSV Smart Contract Demo!', 'success');
|
|
863
|
+
log('Type "help" to see available commands or "basics" to start.', 'info');
|
|
864
|
+
|
|
865
|
+
showMainMenu();
|
|
866
|
+
|
|
867
|
+
rl.prompt();
|
|
868
|
+
|
|
869
|
+
rl.on('line', (input) => {
|
|
870
|
+
processCommand(input);
|
|
871
|
+
rl.prompt();
|
|
872
|
+
}).on('close', () => {
|
|
873
|
+
console.log(chalk.green('\n👋 Thanks for using SmartLedger-BSV! Happy coding!'));
|
|
874
|
+
process.exit(0);
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// Handle errors gracefully
|
|
879
|
+
process.on('uncaughtException', (error) => {
|
|
880
|
+
log(`Uncaught exception: ${error.message}`, 'error');
|
|
881
|
+
process.exit(1);
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
885
|
+
log(`Unhandled rejection at ${promise}: ${reason}`, 'error');
|
|
886
|
+
process.exit(1);
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
// Run the demo
|
|
890
|
+
if (require.main === module) {
|
|
891
|
+
main();
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
module.exports = {
|
|
895
|
+
loadLibrary,
|
|
896
|
+
showFeatures,
|
|
897
|
+
runBasicTests,
|
|
898
|
+
generateCovenant,
|
|
899
|
+
testCovenant,
|
|
900
|
+
showCovenantScript,
|
|
901
|
+
generateSampleTx,
|
|
902
|
+
parsePreimage,
|
|
903
|
+
extractSighash,
|
|
904
|
+
generateUTXO,
|
|
905
|
+
createSpendingTx,
|
|
906
|
+
showUTXODetails,
|
|
907
|
+
buildScript,
|
|
908
|
+
analyzeScript,
|
|
909
|
+
showExamples
|
|
910
|
+
};
|