Skip to content

Commit

Permalink
Added segwit support
Browse files Browse the repository at this point in the history
  • Loading branch information
chiguireitor committed Oct 24, 2018
1 parent f0b74a0 commit 2ee8747
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 11 deletions.
87 changes: 78 additions & 9 deletions src/js/components/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,16 @@ function WalletViewModel() {
);
}

function isBech32(addr) {
try {
bitcoinjs.address.fromBech32(addr)

return true
} catch (e) {
return false
}
}

self.signAndBroadcastTxRaw = function(key, unsignedTxHex, onSuccess, onError, verifySourceAddr, verifyDestAddr) {
assert(verifySourceAddr, "Source address must be specified");
assert(verifyDestAddr, "Destination address must be specified");
Expand All @@ -515,16 +525,75 @@ function WalletViewModel() {

$.jqlog.debug("RAW UNSIGNED HEX: " + unsignedTxHex);

//Sign the input(s)
console.log(key)
key.checkAndSignRawTransaction(unsignedTxHex, verifyDestAddr, function(err, signedHex) {
if (err) {
bootbox.alert("Failed to sign transaction: " + err);
return
}
var sourceIsBech32 = isBech32(verifySourceAddr);
var hasAnyBech32 = verifyDestAddr.reduce((p, x) => p || isBech32(x), sourceIsBech32);

self.broadcastSignedTx(signedHex, onSuccess, onError);
});
if (hasAnyBech32) {
// Use bitcoinjs implementation
var tx = bitcoinjs.Transaction.fromHex(unsignedTxHex);
var network = bitcoinjs.networks[self.BITCOIN_WALLET.HierarchicalKey.network.alias];

var txb = new bitcoinjs.TransactionBuilder(network);
var keypair = bitcoinjs.ECPair.fromWIF(key.priv.toWIF(), network); // Way easier to convert to WIF and then back to ECPair

self.retrieveBTCAddrsInfo([verifySourceAddr], function(data) {
var utxoMap = {}
data[0].rawUtxoData.forEach(utxo => {
utxoMap[utxo.txid] = utxo
})

var p2wpkh = bitcoinjs.payments.p2wpkh({ pubkey: keypair.publicKey, network: network })

for (var i=0; i < tx.ins.length; i++) {
// We get reversed tx hashes somehow after parsing
var txhash = tx.ins[i].hash.reverse().toString('hex')
var prev = utxoMap[txhash]

txb.addInput(tx.ins[i].hash.toString('hex'), prev.vout, null, p2wpkh.output)
}

for (var i=0; i < tx.outs.length; i++) {
var txout = tx.outs[i]

txb.addOutput(txout.script, txout.value)
}

for (var i=0; i < tx.ins.length; i++) {
var txhash = tx.ins[i].hash.toString('hex')
if (txhash in utxoMap) {
var prev = utxoMap[txhash]
txb.sign(i, keypair, null, null, parseFloat(prev.amount) * 100000000);
} else {
// This should throw an error?
bootbox.alert("Failed to sign transaction: " + "Incomplete SegWit inputs");
return
}
}

var signedHex = txb.build().toHex();

$.jqlog.debug("RAW SIGNED HEX: " + signedHex);

self.broadcastSignedTx(signedHex, onSuccess, onError);
}, function(jqXHR, textStatus, errorThrown) {
if (err) {
bootbox.alert("Failed to sign transaction: " + textStatus);
return
}
});

} else {
// Use legacy bitcore implementation
//Sign the input(s)
key.checkAndSignRawTransaction(unsignedTxHex, verifyDestAddr, function(err, signedHex) {
if (err) {
bootbox.alert("Failed to sign transaction: " + err);
return
}

self.broadcastSignedTx(signedHex, onSuccess, onError);
});
}
}

self.signAndBroadcastTx = function(address, unsignedTxHex, onSuccess, onError, verifyDestAddr) {
Expand Down
64 changes: 62 additions & 2 deletions src/js/util.api.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,58 @@ function multiAPIConsensus(method, params, onSuccess, onConsensusError, onSysErr
};
}

function isBech32(addr) {
try {
bitcoinjs.address.fromBech32(addr)

return true
} catch (e) {
return false
}
}

/*function sw_compareOutputs(source, apiResponses) {
// TODO: This should be enabled when we get support for segwit multisig and P2WSH
var t;
// apiResponse might be a plain transaction hex
// or it might be a container with transaction info
var responseIsTxInfo = (typeof apiResponses[0] == 'object')
var resolveTxHex = function(apiResponse) {
return (responseIsTxInfo ? apiResponse.tx_hex : apiResponse);
}
var tx0 = bitcoinjs.Transaction.fromHex(resolveTxHex(apiResponses[0]));
var txHexesValid = apiResponses.map(function(apiResponse, idx) {
if (idx === 0) {
return true;
}
var txHex = resolveTxHex(apiResponse);
var tx1 = bitcore.Transaction(txHex);
if (tx0.outputs.length != tx1.outputs.length) {
return false;
}
var outputsValid = tx0.outs.map(function(output, idx) {
var addresses0 = CWBitcore.extractAddressFromTxOut(output).split(',').sort().join(',');
var addresses1 = CWBitcore.extractAddressFromTxOut(tx1.outputs[idx]).split(',').sort().join(',');
var amount0 = output.satoshis;
var amount1 = tx1.outputs[idx].satoshis;
// addresses need to be the same and values need to be the same
// except for the change output
return addresses0 == addresses1 && (amount0 == amount1 || addresses0.indexOf(source) != -1);
});
return outputsValid.filter(function(v) { return !v; }).length === 0;
})
return txHexesValid.filter(function(v) { return !v; }).length === 0;
}*/

_multiAPIPrimative(method, params, function(results) {
var successResults = [];
var i = 0;
Expand All @@ -424,8 +476,16 @@ function multiAPIConsensus(method, params, onSuccess, onConsensusError, onSysErr
return onSysError(results[i - 1]['jqXHR'], results[i - 1]['textStatus'], results[i - 1]['errorThrown'], results[i - 1]['endpoint']);
}

if (!CWBitcore.compareOutputs(params['source'], successResults)) {
return onConsensusError(successResults); //not all consensus data matches
if (isBech32(params['source'])) {
/*// TODO: This should be enabled when we get support for segwit multisig and P2WSH
if (!sw_compareOutputs(params['source'], successResults)) {
return onConsensusError(successResults); //not all consensus data matches
}*/

} else {
if (!CWBitcore.compareOutputs(params['source'], successResults)) {
return onConsensusError(successResults); //not all consensus data matches
}
}

//if here, all is well
Expand Down

0 comments on commit 2ee8747

Please sign in to comment.