-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcreate-real-testnet-tx.js
More file actions
145 lines (122 loc) Β· 5.15 KB
/
create-real-testnet-tx.js
File metadata and controls
145 lines (122 loc) Β· 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Create REAL Zcash testnet transaction with REAL UTXO
const { proposeTransaction, getSighash, appendSignature, finalizeAndExtract } = require('./dist/index.js');
const secp256k1 = require('secp256k1');
const wallet = require('./testnet-wallet.json');
// UPDATE THESE WITH YOUR REAL UTXO FROM check-balance.js
const UTXO = {
txid: 'PASTE_TXID_HERE', // From check-balance.js output
vout: 0, // From check-balance.js output
value: 1000000n, // Amount in zatoshis from check-balance.js
scriptPubKey: null, // Will be generated from public key
};
// Destination (can send back to same address or different one)
const DESTINATION = {
address: 'tmHufP83dE54sJA92DFmPwMRUxvpsWq4rAu', // Can change this
amount: 990000n, // Send 0.0099 ZEC (leaving 10000 for fee)
};
async function createRealTransaction() {
console.log('π§ Creating REAL Zcash Testnet Transaction\n');
// Validate
if (UTXO.txid === 'PASTE_TXID_HERE') {
console.error('β ERROR: Update UTXO details first!');
console.log('\nπ Steps:');
console.log('1. Run: node check-balance.js');
console.log('2. Copy the UTXO details (txid, vout, value)');
console.log('3. Update UTXO const in this file');
console.log('4. Run this script again');
process.exit(1);
}
try {
// Generate scriptPubKey from public key (P2PKH)
const publicKey = Buffer.from(wallet.publicKey, 'hex');
const crypto = require('crypto');
const sha256 = (buf) => crypto.createHash('sha256').update(buf).digest();
const ripemd160 = (buf) => crypto.createHash('ripemd160').update(buf).digest();
const pubKeyHash = ripemd160(sha256(publicKey));
// P2PKH scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
const scriptPubKey = Buffer.concat([
Buffer.from([0x76]), // OP_DUP
Buffer.from([0xa9]), // OP_HASH160
Buffer.from([0x14]), // Push 20 bytes
pubKeyHash,
Buffer.from([0x88]), // OP_EQUALVERIFY
Buffer.from([0xac]) // OP_CHECKSIG
]);
console.log('π Transaction Details:');
console.log(' From:', wallet.address);
console.log(' UTXO:', UTXO.txid.slice(0, 16) + '...');
console.log(' Vout:', UTXO.vout);
console.log(' Input Amount:', UTXO.value.toString(), 'zatoshis');
console.log(' To:', DESTINATION.address);
console.log(' Send Amount:', DESTINATION.amount.toString(), 'zatoshis');
console.log(' Fee: ~10000 zatoshis\n');
// Prepare inputs
const inputs = [[
{
txid: UTXO.txid,
vout: UTXO.vout,
sequence: 0xFFFFFFFE, // RBF enabled
},
{
value: UTXO.value,
scriptPubKey: scriptPubKey,
}
]];
// Prepare outputs
const request = {
payments: [{
address: DESTINATION.address,
amount: DESTINATION.amount,
}]
};
// Step 1: Create PCZT
console.log('1οΈβ£ Creating PCZT...');
const pczt = await proposeTransaction(inputs, request);
console.log('β
PCZT created');
console.log(' Inputs:', pczt.transparent?.inputs?.length);
console.log(' Outputs:', pczt.transparent?.outputs?.length);
// Step 2: Get sighash
console.log('\n2οΈβ£ Computing sighash...');
const sighash = await getSighash(pczt, 0);
const sighashHex = Buffer.from(sighash.hash).toString('hex');
console.log('β
Sighash:', sighashHex);
// Step 3: Sign with private key
console.log('\n3οΈβ£ Signing with real private key...');
const privateKey = Buffer.from(wallet.privateKey, 'hex');
const messageHash = Buffer.from(sighash.hash);
const sigObj = secp256k1.ecdsaSign(messageHash, privateKey);
const derSig = secp256k1.signatureExport(sigObj.signature);
const signature = Buffer.concat([derSig, Buffer.from([0x01])]); // SIGHASH_ALL
console.log('β
Signature:', signature.toString('hex').slice(0, 32) + '...');
// Step 4: Append signature
console.log('\n4οΈβ£ Appending signature...');
const signedPczt = await appendSignature(pczt, 0, signature);
console.log('β
Signed');
// Step 5: Finalize
console.log('\n5οΈβ£ Finalizing transaction...');
const txBytes = await finalizeAndExtract(signedPczt);
const txHex = Buffer.from(txBytes).toString('hex');
console.log('β
Transaction created!');
console.log(' Size:', txBytes.length, 'bytes');
console.log('');
console.log('β'.repeat(60));
console.log('π€ RAW TRANSACTION HEX:');
console.log('β'.repeat(60));
console.log(txHex);
console.log('β'.repeat(60));
console.log('\nπ Next Steps:');
console.log('1. Broadcast: node broadcast-tx.js');
console.log(' (or use zcash-cli -testnet sendrawtransaction)');
console.log('2. Get TXID from broadcast response');
console.log('3. Check on explorer: https://blockexplorer.one/zcash/testnet');
console.log('4. SAVE TXID FOR BOUNTY SUBMISSION!');
// Save to file
require('fs').writeFileSync('testnet-tx.hex', txHex);
console.log('\nπΎ Saved to: testnet-tx.hex');
} catch (error) {
console.error('\nβ Error:', error.message);
console.error(error.stack);
process.exit(1);
}
}
createRealTransaction().catch(console.error);