-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathwallet.js
More file actions
113 lines (95 loc) · 3.18 KB
/
wallet.js
File metadata and controls
113 lines (95 loc) · 3.18 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
const bitcoin = require('bitcoinjs-lib');
const dotenv = require('dotenv');
dotenv.config();
const network = process.env.NETWORK === 'testnet' ? bitcoin.networks.testnet : bitcoin.networks.bitcoin;
// Mock RPC client for development
const client = {
listunspent: async () => {
// Return mock UTXO data for testing
return [{
txid: '0'.repeat(64),
vout: 0,
address: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
scriptPubKey: {
hex: '0014751e76e8199196d454941c45d1b3a323f1433bd6',
addresses: ['tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx']
},
amount: 0.01 // 1,000,000 satoshis
}];
},
sendrawtransaction: async (txHex) => {
// Mock transaction broadcast
console.log('Mock transaction broadcast:', txHex.substring(0, 20) + '...');
return '0'.repeat(64); // Mock txid
}
};
async function createFundingTransaction(contractAddress, amount, fundingKey) {
const psbt = new bitcoin.Psbt({ network });
// Get UTXOs from the Bitcoin node
const utxos = await client.listunspent();
const utxo = utxos.find(u => u.amount * 1e8 >= amount * 2);
if (!utxo) throw new Error('Insufficient funds');
// Add input from real UTXO
psbt.addInput({
hash: utxo.txid,
index: utxo.vout,
witnessUtxo: {
script: Buffer.from(utxo.scriptPubKey.hex, 'hex'),
value: utxo.amount * 1e8
}
});
// Add output to contract
psbt.addOutput({
address: contractAddress,
value: amount * 2
});
// Add change output if needed
if (utxo.amount * 1e8 > amount * 2 + 1000) {
psbt.addOutput({
address: utxo.address,
value: utxo.amount * 1e8 - amount * 2 - 1000 // Minus fee
});
}
// Sign
const keyPair = bitcoin.ECPair.fromWIF(fundingKey, network);
psbt.signInput(0, keyPair);
psbt.finalizeAllInputs();
// Broadcast transaction
const tx = psbt.extractTransaction();
const txHex = tx.toHex();
const txId = await client.sendrawtransaction(txHex);
return { txId, tx };
}
async function createSettlementTransaction(contractAddress, winnerAddress, amount, keys) {
const psbt = new bitcoin.Psbt({ network });
// Find contract UTXO
const utxos = await client.listunspent();
const utxo = utxos.find(u => u.scriptPubKey.addresses.includes(contractAddress));
if (!utxo) throw new Error('Contract UTXO not found');
// Add input from contract
psbt.addInput({
hash: utxo.txid,
index: utxo.vout,
witnessUtxo: {
script: bitcoin.address.toOutputScript(contractAddress, network),
value: utxo.amount * 1e8
}
});
// Add output to winner
psbt.addOutput({
address: winnerAddress,
value: utxo.amount * 1e8 - 1000 // Minus fee
});
// Cooperative signing
const aliceKey = bitcoin.ECPair.fromWIF(keys.alice.privateKey, network);
const bobKey = bitcoin.ECPair.fromWIF(keys.bob.privateKey, network);
psbt.signInput(0, aliceKey);
psbt.signInput(0, bobKey);
psbt.finalizeAllInputs();
// Broadcast transaction
const tx = psbt.extractTransaction();
const txHex = tx.toHex();
const txId = await client.sendrawtransaction(txHex);
return { txId, tx };
}
module.exports = { createFundingTransaction, createSettlementTransaction };