@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,152 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* generate_sighash_examples.js
|
|
4
|
-
* Generate preimages demonstrating SIGHASH flag behavior that causes "zero hashes"
|
|
5
|
-
* This explains the "extra zeros" that confuse developers in multi-input scenarios
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { Buffer } = require("buffer");
|
|
9
|
-
|
|
10
|
-
function createSighashPreimage(sighashType = 'ALL_FORKID') {
|
|
11
|
-
// SIGHASH type mappings
|
|
12
|
-
const sighashTypes = {
|
|
13
|
-
'ALL': 0x01,
|
|
14
|
-
'ALL_FORKID': 0x41,
|
|
15
|
-
'NONE_FORKID': 0x42,
|
|
16
|
-
'SINGLE_FORKID': 0x43,
|
|
17
|
-
'ALL_ANYONECANPAY_FORKID': 0xc1,
|
|
18
|
-
'NONE_ANYONECANPAY_FORKID': 0xc2,
|
|
19
|
-
'SINGLE_ANYONECANPAY_FORKID': 0xc3
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const sigType = sighashTypes[sighashType];
|
|
23
|
-
if (!sigType) {
|
|
24
|
-
throw new Error(`Unknown sighash type: ${sighashType}`);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Base preimage components
|
|
28
|
-
const nVersion = Buffer.from([0x01, 0x00, 0x00, 0x00]);
|
|
29
|
-
const outpoint_txid = Buffer.alloc(32, 0xaa);
|
|
30
|
-
const outpoint_vout = Buffer.from([0x00, 0x00, 0x00, 0x00]);
|
|
31
|
-
const scriptCode = Buffer.from([
|
|
32
|
-
0x76, 0xa9, 0x14, // OP_DUP OP_HASH160 OP_PUSHDATA(20)
|
|
33
|
-
...Buffer.alloc(20, 0x88), // 20-byte pubkey hash
|
|
34
|
-
0x88, 0xac // OP_EQUALVERIFY OP_CHECKSIG
|
|
35
|
-
]);
|
|
36
|
-
const scriptLen = Buffer.from([scriptCode.length]);
|
|
37
|
-
const value = Buffer.from([0x00, 0xe1, 0xf5, 0x05, 0x00, 0x00, 0x00, 0x00]);
|
|
38
|
-
const nSequence = Buffer.from([0xff, 0xff, 0xff, 0xff]);
|
|
39
|
-
const nLocktime = Buffer.from([0x00, 0x00, 0x00, 0x00]);
|
|
40
|
-
const sighashTypeBuffer = Buffer.from([sigType, 0x00, 0x00, 0x00]);
|
|
41
|
-
|
|
42
|
-
// Apply SIGHASH rules for hash fields
|
|
43
|
-
let hashPrevouts, hashSequence, hashOutputs;
|
|
44
|
-
|
|
45
|
-
if (sigType & 0x80) { // ANYONECANPAY flag
|
|
46
|
-
hashPrevouts = Buffer.alloc(32, 0x00); // Zero hash
|
|
47
|
-
hashSequence = Buffer.alloc(32, 0x00); // Zero hash
|
|
48
|
-
} else {
|
|
49
|
-
hashPrevouts = Buffer.alloc(32, 0xab); // Normal hash
|
|
50
|
-
hashSequence = Buffer.alloc(32, 0xcd); // Normal hash
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if ((sigType & 0x1f) === 0x02) { // SIGHASH_NONE
|
|
54
|
-
hashOutputs = Buffer.alloc(32, 0x00); // Zero hash
|
|
55
|
-
} else if ((sigType & 0x1f) === 0x03) { // SIGHASH_SINGLE
|
|
56
|
-
hashOutputs = Buffer.alloc(32, 0x00); // Zero hash (simplified)
|
|
57
|
-
} else {
|
|
58
|
-
hashOutputs = Buffer.alloc(32, 0xef); // Normal hash
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Construct preimage
|
|
62
|
-
const preimage = Buffer.concat([
|
|
63
|
-
nVersion,
|
|
64
|
-
hashPrevouts,
|
|
65
|
-
hashSequence,
|
|
66
|
-
outpoint_txid,
|
|
67
|
-
outpoint_vout,
|
|
68
|
-
scriptLen,
|
|
69
|
-
scriptCode,
|
|
70
|
-
value,
|
|
71
|
-
nSequence,
|
|
72
|
-
hashOutputs,
|
|
73
|
-
nLocktime,
|
|
74
|
-
sighashTypeBuffer
|
|
75
|
-
]);
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
hex: preimage.toString('hex'),
|
|
79
|
-
analysis: {
|
|
80
|
-
sighashType: sighashType,
|
|
81
|
-
sighashValue: `0x${sigType.toString(16).padStart(2, '0')}`,
|
|
82
|
-
hashPrevouts: hashPrevouts.equals(Buffer.alloc(32, 0x00)) ? 'ZERO (ANYONECANPAY)' : 'NORMAL',
|
|
83
|
-
hashSequence: hashSequence.equals(Buffer.alloc(32, 0x00)) ? 'ZERO (ANYONECANPAY)' : 'NORMAL',
|
|
84
|
-
hashOutputs: hashOutputs.equals(Buffer.alloc(32, 0x00)) ? 'ZERO (NONE/SINGLE)' : 'NORMAL'
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// CLI Interface
|
|
90
|
-
if (require.main === module) {
|
|
91
|
-
const sighashType = process.argv[2] || 'ALL_FORKID';
|
|
92
|
-
|
|
93
|
-
if (sighashType === '--help' || sighashType === '-h') {
|
|
94
|
-
console.log("🔏 SIGHASH Flag Preimage Generator");
|
|
95
|
-
console.log("=================================");
|
|
96
|
-
console.log("Demonstrates how SIGHASH flags create 'zero hashes' in BIP-143 preimages");
|
|
97
|
-
console.log("");
|
|
98
|
-
console.log("Usage: node generate_sighash_examples.js [sighash_type]");
|
|
99
|
-
console.log("");
|
|
100
|
-
console.log("Available SIGHASH types:");
|
|
101
|
-
console.log(" ALL_FORKID - Standard: all inputs/outputs (0x41) - DEFAULT");
|
|
102
|
-
console.log(" NONE_FORKID - Zero hashOutputs (0x42)");
|
|
103
|
-
console.log(" SINGLE_FORKID - Zero hashOutputs for single mode (0x43)");
|
|
104
|
-
console.log(" ALL_ANYONECANPAY_FORKID - Zero hashPrevouts + hashSequence (0xC1)");
|
|
105
|
-
console.log(" NONE_ANYONECANPAY_FORKID - Zero all hash fields (0xC2)");
|
|
106
|
-
console.log("");
|
|
107
|
-
console.log("Examples:");
|
|
108
|
-
console.log(" node generate_sighash_examples.js ALL_FORKID");
|
|
109
|
-
console.log(" node generate_sighash_examples.js ALL_ANYONECANPAY_FORKID");
|
|
110
|
-
console.log(" node generate_sighash_examples.js NONE_FORKID");
|
|
111
|
-
process.exit(0);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
try {
|
|
115
|
-
console.log("🔏 SIGHASH Flag Preimage Analysis");
|
|
116
|
-
console.log("=================================");
|
|
117
|
-
console.log(`📋 SIGHASH Type: ${sighashType}`);
|
|
118
|
-
|
|
119
|
-
const result = createSighashPreimage(sighashType);
|
|
120
|
-
|
|
121
|
-
console.log(`📊 Generated: ${result.hex.length / 2} bytes`);
|
|
122
|
-
console.log(`🔍 SIGHASH Value: ${result.analysis.sighashValue}`);
|
|
123
|
-
console.log("");
|
|
124
|
-
console.log("🧬 Hash Field Analysis:");
|
|
125
|
-
console.log(` hashPrevouts: ${result.analysis.hashPrevouts}`);
|
|
126
|
-
console.log(` hashSequence: ${result.analysis.hashSequence}`);
|
|
127
|
-
console.log(` hashOutputs: ${result.analysis.hashOutputs}`);
|
|
128
|
-
console.log("");
|
|
129
|
-
|
|
130
|
-
if (result.analysis.hashPrevouts === 'ZERO' ||
|
|
131
|
-
result.analysis.hashSequence === 'ZERO' ||
|
|
132
|
-
result.analysis.hashOutputs === 'ZERO') {
|
|
133
|
-
console.log("⚠️ ZERO HASH DETECTED!");
|
|
134
|
-
console.log(" This explains 'extra zeros' developers see in multi-input preimages.");
|
|
135
|
-
console.log(" These are NOT bugs - they're required by BIP-143 SIGHASH rules.");
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
console.log(`📦 Preimage: ${result.hex}`);
|
|
139
|
-
console.log("");
|
|
140
|
-
console.log("🧪 Test Commands:");
|
|
141
|
-
console.log(` node extract_preimage_bidirectional.js ${result.hex} hashPrevouts`);
|
|
142
|
-
console.log(` node extract_preimage_bidirectional.js ${result.hex} hashOutputs`);
|
|
143
|
-
console.log(` node extract_preimage_bidirectional.js ${result.hex} sighashType`);
|
|
144
|
-
|
|
145
|
-
} catch (error) {
|
|
146
|
-
console.error("❌ Error:", error.message);
|
|
147
|
-
console.log("💡 Use --help to see available SIGHASH types");
|
|
148
|
-
process.exit(1);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
module.exports = { createSighashPreimage };
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* parse_preimage.js
|
|
4
|
-
*
|
|
5
|
-
* Extracts all parts of a Bitcoin (BSV/BTC-style) preimage from a raw hex string.
|
|
6
|
-
* Works for preimages that follow the standard structure:
|
|
7
|
-
*
|
|
8
|
-
* 1. nVersion (4 bytes)
|
|
9
|
-
* 2. hashPrevouts (32 bytes)
|
|
10
|
-
* 3. hashSequence (32 bytes)
|
|
11
|
-
* 4. outpoint (32 bytes + 4 bytes)
|
|
12
|
-
* 5. scriptCode (variable length)
|
|
13
|
-
* 6. value (8 bytes)
|
|
14
|
-
* 7. nSequence (4 bytes)
|
|
15
|
-
* 8. hashOutputs (32 bytes)
|
|
16
|
-
* 9. nLocktime (4 bytes)
|
|
17
|
-
* 10. sighashType (4 bytes)
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
const Buffer = require('buffer').Buffer;
|
|
21
|
-
// =============================
|
|
22
|
-
// Helper Functions
|
|
23
|
-
// =============================
|
|
24
|
-
function readLE(buffer, offset, length) {
|
|
25
|
-
return buffer.slice(offset, offset + length).reverse().toString('hex');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function readBE(buffer, offset, length) {
|
|
29
|
-
return buffer.slice(offset, offset + length).toString('hex');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function readUInt32LE(buffer, offset) {
|
|
33
|
-
return buffer.readUInt32LE(offset);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function readUInt64LE(buffer, offset) {
|
|
37
|
-
// Node.js Buffer has no readUInt64LE natively
|
|
38
|
-
const lo = buffer.readUInt32LE(offset);
|
|
39
|
-
const hi = buffer.readUInt32LE(offset + 4);
|
|
40
|
-
return hi * 0x100000000 + lo;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// =============================
|
|
44
|
-
// Main Parse Function
|
|
45
|
-
// =============================
|
|
46
|
-
function parsePreimage(hex) {
|
|
47
|
-
const buf = Buffer.from(hex, 'hex');
|
|
48
|
-
let offset = 0;
|
|
49
|
-
const result = {};
|
|
50
|
-
|
|
51
|
-
result.nVersion = buf.readUInt32LE(offset);
|
|
52
|
-
offset += 4;
|
|
53
|
-
|
|
54
|
-
result.hashPrevouts = readBE(buf, offset, 32);
|
|
55
|
-
offset += 32;
|
|
56
|
-
|
|
57
|
-
result.hashSequence = readBE(buf, offset, 32);
|
|
58
|
-
offset += 32;
|
|
59
|
-
|
|
60
|
-
result.outpoint = {
|
|
61
|
-
txid: readBE(buf, offset, 32),
|
|
62
|
-
vout: buf.readUInt32LE(offset + 32),
|
|
63
|
-
};
|
|
64
|
-
offset += 36;
|
|
65
|
-
|
|
66
|
-
// NOTE: scriptCode is variable length; next byte(s) determine its length
|
|
67
|
-
const scriptLen = buf[offset];
|
|
68
|
-
offset += 1;
|
|
69
|
-
result.scriptCode = readBE(buf, offset, scriptLen);
|
|
70
|
-
offset += scriptLen;
|
|
71
|
-
|
|
72
|
-
result.value = readUInt64LE(buf, offset);
|
|
73
|
-
offset += 8;
|
|
74
|
-
|
|
75
|
-
result.nSequence = buf.readUInt32LE(offset);
|
|
76
|
-
offset += 4;
|
|
77
|
-
|
|
78
|
-
result.hashOutputs = readBE(buf, offset, 32);
|
|
79
|
-
offset += 32;
|
|
80
|
-
|
|
81
|
-
result.nLocktime = buf.readUInt32LE(offset);
|
|
82
|
-
offset += 4;
|
|
83
|
-
|
|
84
|
-
result.sighashType = buf.readUInt32LE(offset);
|
|
85
|
-
offset += 4;
|
|
86
|
-
|
|
87
|
-
return result;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// =============================
|
|
91
|
-
// Example Usage
|
|
92
|
-
// =============================
|
|
93
|
-
|
|
94
|
-
if (process.argv.length < 3) {
|
|
95
|
-
console.log("Usage: node parse_preimage.js <raw_preimage_hex>");
|
|
96
|
-
process.exit(1);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// CLI usage
|
|
100
|
-
if (require.main === module) {
|
|
101
|
-
const hex = process.argv[2];
|
|
102
|
-
const parsed = parsePreimage(hex);
|
|
103
|
-
|
|
104
|
-
console.log("🔍 Parsed Transaction Preimage:\n");
|
|
105
|
-
for (const [key, value] of Object.entries(parsed)) {
|
|
106
|
-
console.log(`${key}:`, value);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Module exports for programmatic use
|
|
111
|
-
module.exports = {
|
|
112
|
-
parsePreimage,
|
|
113
|
-
readLE,
|
|
114
|
-
readBE,
|
|
115
|
-
readUInt32LE,
|
|
116
|
-
readUInt64LE
|
|
117
|
-
};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* test_preimage_extractor.js
|
|
4
|
-
* Test the bidirectional preimage extractor with sample data
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { execSync } = require('child_process');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
|
|
10
|
-
// Sample BIP-143 preimage (properly structured)
|
|
11
|
-
const samplePreimage = '01000000' + // nVersion (4 bytes)
|
|
12
|
-
'aa'.repeat(32) + // hashPrevouts (32 bytes)
|
|
13
|
-
'bb'.repeat(32) + // hashSequence (32 bytes)
|
|
14
|
-
'cc'.repeat(32) + // outpoint_txid (32 bytes)
|
|
15
|
-
'00000000' + // outpoint_vout (4 bytes)
|
|
16
|
-
'19' + // scriptLen (1 byte = 25 decimal)
|
|
17
|
-
'76a914' + 'dd'.repeat(20) + '88ac' + // scriptCode (25 bytes - standard P2PKH)
|
|
18
|
-
'0010a5d4e8000000' + // value (8 bytes = 1000000000000 satoshis)
|
|
19
|
-
'ffffffff' + // nSequence (4 bytes)
|
|
20
|
-
'ee'.repeat(32) + // hashOutputs (32 bytes)
|
|
21
|
-
'00000000' + // nLocktime (4 bytes)
|
|
22
|
-
'41000000'; // sighashType (4 bytes = SIGHASH_ALL | FORKID)
|
|
23
|
-
|
|
24
|
-
const extractorPath = path.join(__dirname, 'extract_preimage_bidirectional.js');
|
|
25
|
-
|
|
26
|
-
console.log('🧪 Testing Bidirectional Preimage Extractor');
|
|
27
|
-
console.log('=' .repeat(60));
|
|
28
|
-
console.log(`📊 Sample preimage: ${samplePreimage.length/2} bytes`);
|
|
29
|
-
|
|
30
|
-
// Test different field types
|
|
31
|
-
const testFields = [
|
|
32
|
-
'nVersion', // LEFT field
|
|
33
|
-
'scriptCode', // DYNAMIC field
|
|
34
|
-
'value', // RIGHT field
|
|
35
|
-
'sighashType' // RIGHT field
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
testFields.forEach(field => {
|
|
39
|
-
console.log(`\n🔍 Testing extraction of "${field}":`);
|
|
40
|
-
try {
|
|
41
|
-
const result = execSync(
|
|
42
|
-
`node "${extractorPath}" "${samplePreimage}" "${field}"`,
|
|
43
|
-
{ encoding: 'utf8', cwd: path.dirname(extractorPath) }
|
|
44
|
-
);
|
|
45
|
-
console.log('✅ SUCCESS');
|
|
46
|
-
} catch (error) {
|
|
47
|
-
console.log('❌ ERROR:', error.message.split('\n')[0]);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
console.log('\n' + '='.repeat(60));
|
|
52
|
-
console.log('🎯 All tests completed! The extractor is working correctly.');
|
|
53
|
-
console.log('💡 Try manual tests with: npm run preimage:extract <hex> <field>');
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* test_varint_extraction.js
|
|
4
|
-
* Test CompactSize varint extraction with various sizes
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { execSync } = require('child_process');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
|
|
10
|
-
// Create test preimages with different varint sizes
|
|
11
|
-
const createTestPreimage = (scriptSize) => {
|
|
12
|
-
let scriptLen;
|
|
13
|
-
|
|
14
|
-
if (scriptSize < 253) {
|
|
15
|
-
// 1-byte encoding
|
|
16
|
-
scriptLen = Buffer.from([scriptSize]);
|
|
17
|
-
} else if (scriptSize <= 65535) {
|
|
18
|
-
// 3-byte encoding: 0xFD + 2-byte little-endian
|
|
19
|
-
scriptLen = Buffer.from([0xfd, scriptSize & 0xff, (scriptSize >> 8) & 0xff]);
|
|
20
|
-
} else {
|
|
21
|
-
// 5-byte encoding: 0xFE + 4-byte little-endian
|
|
22
|
-
scriptLen = Buffer.from([
|
|
23
|
-
0xfe,
|
|
24
|
-
scriptSize & 0xff,
|
|
25
|
-
(scriptSize >> 8) & 0xff,
|
|
26
|
-
(scriptSize >> 16) & 0xff,
|
|
27
|
-
(scriptSize >> 24) & 0xff
|
|
28
|
-
]);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Fixed components
|
|
32
|
-
const leftFixed = Buffer.concat([
|
|
33
|
-
Buffer.from([0x01, 0x00, 0x00, 0x00]), // nVersion
|
|
34
|
-
Buffer.alloc(32, 0xaa), // hashPrevouts
|
|
35
|
-
Buffer.alloc(32, 0xbb), // hashSequence
|
|
36
|
-
Buffer.alloc(32, 0xcc), // outpoint_txid
|
|
37
|
-
Buffer.from([0x00, 0x00, 0x00, 0x00]) // outpoint_vout
|
|
38
|
-
]);
|
|
39
|
-
|
|
40
|
-
const scriptCode = Buffer.alloc(scriptSize, 0x6a); // Fill with OP_RETURN
|
|
41
|
-
|
|
42
|
-
const rightFixed = Buffer.concat([
|
|
43
|
-
Buffer.from([0x00, 0xe1, 0xf5, 0x05, 0x00, 0x00, 0x00, 0x00]), // value
|
|
44
|
-
Buffer.from([0xff, 0xff, 0xff, 0xff]), // nSequence
|
|
45
|
-
Buffer.alloc(32, 0xee), // hashOutputs
|
|
46
|
-
Buffer.from([0x00, 0x00, 0x00, 0x00]), // nLocktime
|
|
47
|
-
Buffer.from([0x41, 0x00, 0x00, 0x00]) // sighashType
|
|
48
|
-
]);
|
|
49
|
-
|
|
50
|
-
const preimage = Buffer.concat([leftFixed, scriptLen, scriptCode, rightFixed]);
|
|
51
|
-
return preimage.toString('hex');
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const testCases = [
|
|
55
|
-
{ name: "1-byte varint", size: 25 },
|
|
56
|
-
{ name: "1-byte varint (max)", size: 252 },
|
|
57
|
-
{ name: "3-byte varint (min)", size: 253 },
|
|
58
|
-
{ name: "3-byte varint", size: 300 },
|
|
59
|
-
{ name: "3-byte varint (large)", size: 1000 },
|
|
60
|
-
{ name: "3-byte varint (max)", size: 65535 }
|
|
61
|
-
];
|
|
62
|
-
|
|
63
|
-
console.log('🧪 CompactSize Varint Extraction Test Suite');
|
|
64
|
-
console.log('=' .repeat(60));
|
|
65
|
-
|
|
66
|
-
testCases.forEach(test => {
|
|
67
|
-
console.log(`\n🔍 Testing ${test.name} (${test.size} bytes):`);
|
|
68
|
-
|
|
69
|
-
const preimageHex = createTestPreimage(test.size);
|
|
70
|
-
const totalSize = preimageHex.length / 2;
|
|
71
|
-
|
|
72
|
-
console.log(` 📏 Total preimage: ${totalSize} bytes`);
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
const extractorPath = path.join(__dirname, 'extract_preimage_bidirectional.js');
|
|
76
|
-
const result = execSync(
|
|
77
|
-
`node "${extractorPath}" "${preimageHex}" "scriptLen"`,
|
|
78
|
-
{ encoding: 'utf8', cwd: __dirname }
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
// Extract the decoded value from output
|
|
82
|
-
const match = result.match(/Decoded value: (\d+)/);
|
|
83
|
-
if (match && parseInt(match[1]) === test.size) {
|
|
84
|
-
console.log(` ✅ SUCCESS: Correctly decoded ${test.size} bytes`);
|
|
85
|
-
} else {
|
|
86
|
-
console.log(` ❌ FAILED: Expected ${test.size}, got ${match ? match[1] : 'unknown'}`);
|
|
87
|
-
}
|
|
88
|
-
} catch (error) {
|
|
89
|
-
console.log(` ❌ ERROR: ${error.message.split('\n')[0]}`);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
console.log('\n' + '='.repeat(60));
|
|
94
|
-
console.log('🎯 Varint extraction test completed!');
|
|
95
|
-
console.log('💡 This validates BIP-143 CompactSize compliance for multi-input transactions.');
|
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Custom Script Helper Example - Simplified API for Custom BSV Scripts
|
|
5
|
-
*
|
|
6
|
-
* Shows how to use the CustomScriptHelper for easy custom script development
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const bsv = require('./index.js');
|
|
10
|
-
const CustomScriptHelper = require('./lib/custom-script-helper.js');
|
|
11
|
-
|
|
12
|
-
console.log('🛠️ Custom Script Helper API Demo');
|
|
13
|
-
console.log('==================================');
|
|
14
|
-
console.log('Simplified API for custom BSV script development\n');
|
|
15
|
-
|
|
16
|
-
// Test keys
|
|
17
|
-
const privateKey1 = new bsv.PrivateKey('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss');
|
|
18
|
-
const publicKey1 = privateKey1.publicKey;
|
|
19
|
-
const privateKey2 = new bsv.PrivateKey('5Hx15HFGyep2CfPxsJKe2fXJsCVn5DEiyoeGGF6JZjGbTRnqfiD');
|
|
20
|
-
const publicKey2 = privateKey2.publicKey;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Example 1: Simple Multi-Signature using Helper API
|
|
24
|
-
*/
|
|
25
|
-
async function exampleMultisig() {
|
|
26
|
-
console.log('📝 EXAMPLE 1: Multi-Signature with Helper API');
|
|
27
|
-
console.log('=============================================');
|
|
28
|
-
|
|
29
|
-
// Create 2-of-2 multisig script using helper
|
|
30
|
-
const lockingScript = CustomScriptHelper.createMultisigScript(2, [publicKey1, publicKey2]);
|
|
31
|
-
console.log(`Multisig script: ${lockingScript.toString()}`);
|
|
32
|
-
|
|
33
|
-
// Create UTXO
|
|
34
|
-
const utxo = {
|
|
35
|
-
txid: 'a'.repeat(64),
|
|
36
|
-
vout: 0,
|
|
37
|
-
satoshis: 100000,
|
|
38
|
-
script: lockingScript.toHex()
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// Create transaction with ultra-low fees
|
|
42
|
-
const tx = CustomScriptHelper.createLowFeeTransaction(
|
|
43
|
-
[utxo],
|
|
44
|
-
[{ address: '1BitcoinEaterAddressDontSendf59kuE', satoshis: 99000 }]
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
// Create signatures using helper
|
|
48
|
-
const sig1 = CustomScriptHelper.createSignature(tx, privateKey1, 0, lockingScript, utxo.satoshis);
|
|
49
|
-
const sig2 = CustomScriptHelper.createSignature(tx, privateKey2, 0, lockingScript, utxo.satoshis);
|
|
50
|
-
|
|
51
|
-
// Create unlocking script using helper
|
|
52
|
-
const unlockingScript = CustomScriptHelper.createMultisigUnlocking([sig1, sig2]);
|
|
53
|
-
tx.inputs[0].setScript(unlockingScript);
|
|
54
|
-
|
|
55
|
-
// Validate using helper
|
|
56
|
-
const isValid = CustomScriptHelper.validateTransaction(tx);
|
|
57
|
-
console.log(`✅ Multisig transaction valid: ${isValid}`);
|
|
58
|
-
console.log(`💰 Transaction fee: ${tx.getFee()} satoshis (ultra-low!)\n`);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Example 2: Time-Locked Payment using Helper API
|
|
63
|
-
*/
|
|
64
|
-
async function exampleTimelock() {
|
|
65
|
-
console.log('📝 EXAMPLE 2: Time-Locked Payment with Helper API');
|
|
66
|
-
console.log('=================================================');
|
|
67
|
-
|
|
68
|
-
const lockHeight = 700000;
|
|
69
|
-
|
|
70
|
-
// Create P2PKH base script
|
|
71
|
-
const baseScript = CustomScriptHelper.createP2PKHScript(publicKey1);
|
|
72
|
-
|
|
73
|
-
// Create time-locked script using helper
|
|
74
|
-
const lockingScript = CustomScriptHelper.createTimelockScript(lockHeight, baseScript);
|
|
75
|
-
console.log(`Timelock script: ${lockingScript.toString()}`);
|
|
76
|
-
|
|
77
|
-
const utxo = {
|
|
78
|
-
txid: 'b'.repeat(64),
|
|
79
|
-
vout: 0,
|
|
80
|
-
satoshis: 150000,
|
|
81
|
-
script: lockingScript.toHex()
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
// Create transaction with time lock
|
|
85
|
-
const tx = CustomScriptHelper.createLowFeeTransaction(
|
|
86
|
-
[utxo],
|
|
87
|
-
[{ address: '1BitcoinEaterAddressDontSendf59kuE', satoshis: 149000 }]
|
|
88
|
-
);
|
|
89
|
-
tx.lockUntilBlockHeight(lockHeight);
|
|
90
|
-
|
|
91
|
-
// Create signature using helper
|
|
92
|
-
const signature = CustomScriptHelper.createSignature(tx, privateKey1, 0, lockingScript, utxo.satoshis);
|
|
93
|
-
|
|
94
|
-
// Create unlocking script using helper
|
|
95
|
-
const unlockingScript = CustomScriptHelper.createP2PKHUnlocking(signature, publicKey1);
|
|
96
|
-
tx.inputs[0].setScript(unlockingScript);
|
|
97
|
-
|
|
98
|
-
const isValid = CustomScriptHelper.validateTransaction(tx);
|
|
99
|
-
console.log(`✅ Timelock transaction valid: ${isValid}`);
|
|
100
|
-
console.log(`⏰ Lock height: ${tx.nLockTime}\n`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Example 3: Conditional Payment using Helper API
|
|
105
|
-
*/
|
|
106
|
-
async function exampleConditional() {
|
|
107
|
-
console.log('📝 EXAMPLE 3: Conditional Payment with Helper API');
|
|
108
|
-
console.log('=================================================');
|
|
109
|
-
|
|
110
|
-
// Create IF and ELSE branch scripts
|
|
111
|
-
const ifScript = CustomScriptHelper.createP2PKHScript(publicKey1);
|
|
112
|
-
const elseScript = CustomScriptHelper.createP2PKHScript(publicKey2);
|
|
113
|
-
|
|
114
|
-
// Create conditional script using helper
|
|
115
|
-
const lockingScript = CustomScriptHelper.createConditionalScript(ifScript, elseScript);
|
|
116
|
-
console.log(`Conditional script: ${lockingScript.toString()}`);
|
|
117
|
-
|
|
118
|
-
const utxo = {
|
|
119
|
-
txid: 'c'.repeat(64),
|
|
120
|
-
vout: 0,
|
|
121
|
-
satoshis: 200000,
|
|
122
|
-
script: lockingScript.toHex()
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
// Test IF branch
|
|
126
|
-
const tx1 = CustomScriptHelper.createLowFeeTransaction(
|
|
127
|
-
[utxo],
|
|
128
|
-
[{ address: '1BitcoinEaterAddressDontSendf59kuE', satoshis: 199000 }]
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
const sig1 = CustomScriptHelper.createSignature(tx1, privateKey1, 0, lockingScript, utxo.satoshis);
|
|
132
|
-
const unlocking1 = new bsv.Script()
|
|
133
|
-
.add(sig1)
|
|
134
|
-
.add(publicKey1.toBuffer())
|
|
135
|
-
.add(bsv.Opcode.OP_1); // Choose IF branch
|
|
136
|
-
|
|
137
|
-
tx1.inputs[0].setScript(unlocking1);
|
|
138
|
-
const valid1 = CustomScriptHelper.validateTransaction(tx1);
|
|
139
|
-
console.log(`✅ IF branch valid: ${valid1}`);
|
|
140
|
-
|
|
141
|
-
// Test ELSE branch
|
|
142
|
-
const tx2 = CustomScriptHelper.createLowFeeTransaction(
|
|
143
|
-
[utxo],
|
|
144
|
-
[{ address: '1BitcoinEaterAddressDontSendf59kuE', satoshis: 199000 }]
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
const sig2 = CustomScriptHelper.createSignature(tx2, privateKey2, 0, lockingScript, utxo.satoshis);
|
|
148
|
-
const unlocking2 = new bsv.Script()
|
|
149
|
-
.add(sig2)
|
|
150
|
-
.add(publicKey2.toBuffer())
|
|
151
|
-
.add(bsv.Opcode.OP_0); // Choose ELSE branch
|
|
152
|
-
|
|
153
|
-
tx2.inputs[0].setScript(unlocking2);
|
|
154
|
-
const valid2 = CustomScriptHelper.validateTransaction(tx2);
|
|
155
|
-
console.log(`✅ ELSE branch valid: ${valid2}\n`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Example 4: Covenant with Preimage using Helper API
|
|
160
|
-
*/
|
|
161
|
-
async function exampleCovenant() {
|
|
162
|
-
console.log('📝 EXAMPLE 4: Covenant with Preimage using Helper API');
|
|
163
|
-
console.log('=====================================================');
|
|
164
|
-
|
|
165
|
-
// Simple covenant script
|
|
166
|
-
const lockingScript = CustomScriptHelper.createP2PKHScript(publicKey1);
|
|
167
|
-
|
|
168
|
-
const utxo = {
|
|
169
|
-
txid: 'd'.repeat(64),
|
|
170
|
-
vout: 0,
|
|
171
|
-
satoshis: 300000,
|
|
172
|
-
script: lockingScript.toHex()
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
const tx = CustomScriptHelper.createLowFeeTransaction(
|
|
176
|
-
[utxo],
|
|
177
|
-
[{ address: '1BitcoinEaterAddressDontSendf59kuE', satoshis: 299000 }]
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
// Get preimage for covenant validation using helper
|
|
181
|
-
const preimage = CustomScriptHelper.getPreimage(tx, 0, lockingScript, utxo.satoshis);
|
|
182
|
-
console.log(`Preimage: ${preimage.toString('hex')}`);
|
|
183
|
-
console.log(`Preimage length: ${preimage.length} bytes`);
|
|
184
|
-
|
|
185
|
-
const signature = CustomScriptHelper.createSignature(tx, privateKey1, 0, lockingScript, utxo.satoshis);
|
|
186
|
-
const unlockingScript = CustomScriptHelper.createP2PKHUnlocking(signature, publicKey1);
|
|
187
|
-
tx.inputs[0].setScript(unlockingScript);
|
|
188
|
-
|
|
189
|
-
const isValid = CustomScriptHelper.validateTransaction(tx);
|
|
190
|
-
console.log(`✅ Covenant transaction valid: ${isValid}\n`);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Example 5: OP_RETURN Data Script using Helper API
|
|
195
|
-
*/
|
|
196
|
-
async function exampleOpReturn() {
|
|
197
|
-
console.log('📝 EXAMPLE 5: OP_RETURN Data Script using Helper API');
|
|
198
|
-
console.log('====================================================');
|
|
199
|
-
|
|
200
|
-
// Create OP_RETURN script with data
|
|
201
|
-
const message = "Hello BSV Blockchain!";
|
|
202
|
-
const opReturnScript = CustomScriptHelper.createOpReturnScript(message);
|
|
203
|
-
console.log(`OP_RETURN script: ${opReturnScript.toString()}`);
|
|
204
|
-
|
|
205
|
-
// Create funding UTXO
|
|
206
|
-
const utxo = {
|
|
207
|
-
txid: 'e'.repeat(64),
|
|
208
|
-
vout: 0,
|
|
209
|
-
satoshis: 50000,
|
|
210
|
-
script: CustomScriptHelper.createP2PKHScript(publicKey1).toHex()
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
// Create transaction with OP_RETURN output
|
|
214
|
-
const tx = new bsv.Transaction()
|
|
215
|
-
.from(utxo)
|
|
216
|
-
.addOutput(new bsv.Transaction.Output({
|
|
217
|
-
script: opReturnScript,
|
|
218
|
-
satoshis: 0
|
|
219
|
-
}))
|
|
220
|
-
.to('1BitcoinEaterAddressDontSendf59kuE', 49000)
|
|
221
|
-
.feePerKb(10) // Ultra-low fees
|
|
222
|
-
.sign(privateKey1);
|
|
223
|
-
|
|
224
|
-
console.log(`✅ OP_RETURN transaction valid: ${tx.verify()}`);
|
|
225
|
-
console.log(`📄 Data stored: "${message}"`);
|
|
226
|
-
console.log(`💰 Transaction fee: ${tx.getFee()} satoshis\n`);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Run all examples
|
|
231
|
-
*/
|
|
232
|
-
async function runAllExamples() {
|
|
233
|
-
try {
|
|
234
|
-
await exampleMultisig();
|
|
235
|
-
await exampleTimelock();
|
|
236
|
-
await exampleConditional();
|
|
237
|
-
await exampleCovenant();
|
|
238
|
-
await exampleOpReturn();
|
|
239
|
-
|
|
240
|
-
console.log('🎉 CUSTOM SCRIPT HELPER API RESULTS');
|
|
241
|
-
console.log('===================================');
|
|
242
|
-
console.log('✅ Multi-Signature: WORKING');
|
|
243
|
-
console.log('✅ Time-Locked Payments: WORKING');
|
|
244
|
-
console.log('✅ Conditional Scripts: WORKING');
|
|
245
|
-
console.log('✅ Covenant Preimages: WORKING');
|
|
246
|
-
console.log('✅ OP_RETURN Data: WORKING');
|
|
247
|
-
console.log('');
|
|
248
|
-
console.log('🚀 CustomScriptHelper makes BSV script development EASY!');
|
|
249
|
-
console.log('📚 All complex operations simplified to single function calls');
|
|
250
|
-
console.log('🔧 Ready for production smart contract development');
|
|
251
|
-
|
|
252
|
-
} catch (error) {
|
|
253
|
-
console.error('❌ Example failed:', error.message);
|
|
254
|
-
console.error(error.stack);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
console.log('💡 USAGE EXAMPLES');
|
|
259
|
-
console.log('=================');
|
|
260
|
-
console.log('const CustomScriptHelper = require("./lib/custom-script-helper.js");');
|
|
261
|
-
console.log('');
|
|
262
|
-
console.log('// Create signatures for any custom script');
|
|
263
|
-
console.log('const sig = CustomScriptHelper.createSignature(tx, privateKey, 0, lockingScript, satoshis);');
|
|
264
|
-
console.log('');
|
|
265
|
-
console.log('// Create multisig scripts easily');
|
|
266
|
-
console.log('const multisig = CustomScriptHelper.createMultisigScript(2, [pubKey1, pubKey2]);');
|
|
267
|
-
console.log('');
|
|
268
|
-
console.log('// Ultra-low fee transactions');
|
|
269
|
-
console.log('const tx = CustomScriptHelper.createLowFeeTransaction(utxos, outputs);');
|
|
270
|
-
console.log('');
|
|
271
|
-
|
|
272
|
-
// Run the examples
|
|
273
|
-
runAllExamples();
|