-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrefundtxhex.js
133 lines (115 loc) · 3.28 KB
/
refundtxhex.js
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
var bitcoin = require("bitcoinjs-lib");
var testnet = bitcoin.networks.testnet;
var crypto = require("crypto");
var bip65 = require("bip65");
var util = require('util');
var request = require('sync-request');
var argv = require('argv');
//
// add valuables to execute
//
argv.option({
name: 'privkeyhex',
short: 'p',
type: 'string',
description: 'private key in hex to unlock outputs of swap address'
});
argv.option({
name: 'swapaddr',
short: 's',
type: 'string',
description: 'swap address'
});
argv.option({
name: 'callbackaddr',
short: 'c',
type: 'string',
description: 'address of refund or callback(p2pkh, p2sh)'
});
argv.option({
name: 'redeemscripthex',
short: 'r',
type: 'string',
description: 'redeemscript in hex'
});
var args = argv.run();
if (Object.keys(args.options).length < 4) {
console.log("check 'node refundtxhex.js -h'");
process.exit(1)
};
var bobPrivKeyHex = args.options.privkeyhex;
var swapAddr = args.options.swapaddr;
var refundAddr = args.options.callbackaddr;
var redeemScriptHex = args.options.redeemscripthex;
//
// [main code]
// create refund hex tx
//
const bobKeyPair = bitcoin.ECPair.fromPrivateKey(Buffer.from(bobPrivKeyHex, "hex"), testnet);
var [outpointsToSwapAddr, valueSatoshi] = txOutpointsToSwapAddr(swapAddr);
// todo: add fee estimation
var feeSatoshi = valueSatoshi * 0.01;
const txb = new bitcoin.TransactionBuilder(testnet)
txb.setLockTime(bip65.encode({ utc: utcNow() }));
for (var outpoint of outpointsToSwapAddr) {
txb.addInput(outpoint.txid, outpoint.index, 0xfffffffe);
};
txb.addOutput(refundAddr, valueSatoshi-feeSatoshi);
const tx = txb.buildIncomplete()
const hashType = bitcoin.Transaction.SIGHASH_ALL;
var redeemScript = Buffer.from(redeemScriptHex, "hex");
for (var idx in outpointsToSwapAddr) {
const signatureHash = tx.hashForSignature(parseInt(idx), redeemScript, hashType)
const redeemScriptSig = bitcoin.payments.p2sh({
redeem: {
input: bitcoin.script.compile([
bitcoin.script.signature.encode(bobKeyPair.sign(signatureHash), hashType),
bobKeyPair.publicKey,
bitcoin.script.OP_FALSE,
]),
output: redeemScript
}
}).input
tx.setInputScript(parseInt(idx), redeemScriptSig)
}
console.log(tx.toHex());
//
// tx outputpoint
//
// input: btc address
// output: [outpoints, value]
// outpoints:
// {
// txid,
// index,
// }
function txOutpointsToSwapAddr(swapAddr){
var url = util.format("https://api.blockcypher.com/v1/btc/test3/addrs/%s", swapAddr)
var addrInfo= JSON.parse(httpGet(url));
var totalValue = addrInfo.balance;
var outpoints = [];
for (var tx of addrInfo.txrefs) {
outpoints.push({txid: tx.tx_hash, index: tx.tx_output_n});
};
return [outpoints, totalValue];
};
//
// currenct time in utc
//
// input: nothing
// output: currecnt time in utc in seconds
function utcNow() {
return Math.floor(Date.now() / 1000)
}
//
// http GET
//
// input: url
// output: response body
function httpGet(url){
var response = request('GET', url);
if (response.statusCode != 200) {
throw new Error(util.format("invalid status code: %s", response.statusCode));
};
return response.getBody();
}