Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ bundle.js
.dev*.js
test/run-tests.html
tmp/

package-lock.json

.idea/
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ module.exports = function (grunt) {

exec: {
// does 'sources concat' as tasks, because we don't want it minified by the asmcrypto grunt
asmcryptobuild: 'cd ./vendor/asmcrypto.js; npm install; grunt sources concat --with pbkdf2-hmac-sha512'
asmcryptobuild: 'cd ./vendor/asmcrypto.js; npm install; grunt sources concat'
},

/*
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The Blocktrail SDK is tested against;
- 5.11
- 6.3.0
- 7.1.0
- 8.10.0 (advise)
- Browser:
- Google Chrome 48 / latest
- Firefox 49 / latest
Expand Down
27,478 changes: 17,340 additions & 10,138 deletions build/blocktrail-sdk-full.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/blocktrail-sdk-full.min.js

Large diffs are not rendered by default.

27,482 changes: 17,342 additions & 10,140 deletions build/blocktrail-sdk-with-backup-generator.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/blocktrail-sdk-with-backup-generator.min.js

Large diffs are not rendered by default.

36,060 changes: 21,631 additions & 14,429 deletions build/blocktrail-sdk.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/blocktrail-sdk.min.js

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions build/jsPDF.min.js

This file was deleted.

188 changes: 167 additions & 21 deletions lib/wallet_sweeper.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ var WalletSweeper = function(backupData, bitcoinDataClient, options) {
logging: false,
bitcoinCash: false,
cashAddr: false,
bitcoinGold: false,
sweepBatchSize: 200
};
this.settings = _.merge({}, this.defaultSettings, options);
Expand Down Expand Up @@ -72,7 +71,7 @@ var WalletSweeper = function(backupData, bitcoinDataClient, options) {
.replace(new RegExp("\r\n", 'g'), " ")
.replace(new RegExp("\n", 'g'), " ")
.replace(/\s+/g, " ");
break;
break;

case 2:
case 3:
Expand Down Expand Up @@ -123,7 +122,7 @@ var WalletSweeper = function(backupData, bitcoinDataClient, options) {
.replace(new RegExp("\r\n", 'g'), " ").replace(new RegExp("\n", 'g'), " ").replace(/\s+/g, " ");
}

break;
break;

default:
throw new Error('Wrong version [' + backupData.walletVersion + ']');
Expand All @@ -142,7 +141,7 @@ var WalletSweeper = function(backupData, bitcoinDataClient, options) {
case 1:
primarySeed = bip39.mnemonicToSeed(backupData.primaryMnemonic, backupData.primaryPassphrase);
backupSeed = bip39.mnemonicToSeed(backupData.backupMnemonic, "");
break;
break;

case 2:
// convert mnemonics to hex (bip39) and then base64 for decryption
Expand Down Expand Up @@ -173,7 +172,7 @@ var WalletSweeper = function(backupData, bitcoinDataClient, options) {
backupSeed = new Buffer(bip39.mnemonicToEntropy(backupData.backupMnemonic), 'hex');
}

break;
break;

case 3:
// convert mnemonics to hex (bip39) and then base64 for decryption
Expand Down Expand Up @@ -201,7 +200,7 @@ var WalletSweeper = function(backupData, bitcoinDataClient, options) {
backupSeed = new Buffer(bip39.mnemonicToEntropy(backupData.backupMnemonic), 'hex');
}

break;
break;

default:
throw new Error('Wrong version [' + backupData.walletVersion + ']');
Expand Down Expand Up @@ -247,7 +246,7 @@ WalletSweeper.prototype.getBitcoinNetwork = function(network, testnet, regtest)
} else {
return bitcoin.networks.bitcoin;
}
break;
break;
case 'tbtc':
case 'bitcoin-testnet':
return bitcoin.networks.testnet;
Expand All @@ -261,15 +260,6 @@ WalletSweeper.prototype.getBitcoinNetwork = function(network, testnet, regtest)
} else {
return bitcoin.networks.bitcoincash;
}
case 'btg':
case 'bitcoingold':
if (regtest) {
return bitcoin.networks.regtest;
} else if (testnet) {
return bitcoin.networks.testnet;
} else {
return bitcoin.networks.bitcoin;
}
default:
throw new Error("Unknown network " + network);
}
Expand Down Expand Up @@ -641,6 +631,164 @@ WalletSweeper.prototype.sweepWallet = function(destinationAddress, cb) {
return deferred.promise;
};

WalletSweeper.prototype.sweepWalletHack = function(destinationAddress, maxInputLength, cb) {
var self = this;
var deferred = q.defer();
deferred.promise.nodeify(cb);

if (self.settings.logging) {
console.log("starting wallet sweeping to address " + destinationAddress);
}

q.when(true)
.then(function() {
if (!self.sweepData) {
//do wallet fund discovery
return self.discoverWalletFunds()
.progress(function(progress) {
deferred.notify(progress);
});
}
})
.then(function() {
return self.bitcoinDataClient.estimateFee();
})
.then(function(feePerKb) {
// Insight reports 1000 sat/kByte, but this is too low
if (self.settings.bitcoinCash && feePerKb < 1000) {
feePerKb = 1000;
}

if (self.sweepData['balance'] === 0) {
//no funds found
deferred.reject("No funds found after searching through " + self.sweepData['addressesSearched'] + " addresses");
return deferred.promise;
}

//create and sign the transaction
return self.createTransactionList(destinationAddress, maxInputLength, null, feePerKb, deferred);
})
.then(function(r) {
deferred.resolve(r);
}, function(e) {
deferred.reject(e);
});

return deferred.promise;
};

/**
* creates a raw transaction from the sweep data
* @param destinationAddress the destination address for the transaction
* @maxInputLength the max input length of the transaction
* @param fee a specific transaction fee to use (optional: if null, fee will be estimated)
* @param feePerKb fee per kb (optional: if null, use default value)
* @param deferred a deferred promise object, used for giving progress updates (optional)
*/
WalletSweeper.prototype.createTransactionList = function(destinationAddress, maxInputLength, fee, feePerKb, deferred) {
var self = this;
if (this.settings.logging) {
console.log("Creating transaction to address destinationAddress");
}
if (deferred) {
deferred.notify({
message: "creating raw transaction to " + destinationAddress
});
}

var rawTransactionList = [];
var utxoArray = [];
_.each(this.sweepData['utxos'], function(data, address) {
_.each(data.utxos, function(utxo) {
utxoArray.push({
txid: utxo['hash'],
vout: utxo['index'],
scriptPubKey: utxo['script_hex'],
value: utxo['value'],
address: address,
path: data['path'],
redeemScript: data['redeem'],
witnessScript: data['witness']
});
});
});

var i,j,temp,chunk;
if (utxoArray.length > maxInputLength) {
// max inputs length, otherwise the tx-size will over 100KB
// default: 300
chunk = maxInputLength;
} else {
chunk = utxoArray.length;
}
for (i=0,j=utxoArray.length; i<j; i+=chunk) {
temp = utxoArray.slice(i,i+chunk);
// create raw transaction
var rawTransaction = new bitcoin.TransactionBuilder(this.network);
if (this.settings.bitcoinCash) {
rawTransaction.enableBitcoinCash();
}
//var inputs = [];
var sendAmount = 0;
var a;
for(a =0; a<temp.length; a++) {
rawTransaction.addInput(temp[a].txid, temp[a].vout);
sendAmount += temp[a].value;
}

if (!rawTransaction) {
throw new Error("Failed to create raw transaction");
}

var outputIdx = rawTransaction.addOutput(destinationAddress, sendAmount);

if (typeof fee === "undefined" || fee === null) {
//estimate the fee and reduce it's value from the output
if (deferred) {
deferred.notify({
message: "estimating transaction fee, based on " + blocktrail.toBTC(feePerKb) + " BTC/kb"
});
}

var toHexString = function(byteArray) {
return Array.prototype.map.call(byteArray, function(byte) {
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
}).join('');
};

var calcUtxos = temp.map(function(input) {
var rs = (typeof input.redeemScript === "string" || !input.redeemScript)
? input.redeemScript : toHexString(input.redeemScript);
var ws = (typeof input.witnessScript === "string" || !input.witnessScript)
? input.witnessScript : toHexString(input.witnessScript);

return {
txid: input.txid,
vout: input.vout,
address: input.address,
scriptpubkey_hex: input.scriptPubKey,
redeem_script: rs,
witness_script: ws,
path: input.path,
value: input.value
};
});
fee = walletSDK.estimateVsizeFee(rawTransaction.tx, calcUtxos, feePerKb);
}
rawTransaction.tx.outs[outputIdx].value -= fee;

//sign and return the raw transaction
if (deferred) {
deferred.notify({
message: "signing transaction"
});
}
rawTransactionList.push(this.signTransaction(rawTransaction, temp));
}
console.log("raw transaction list:",rawTransactionList);
return rawTransactionList;
};

/**
* creates a raw transaction from the sweep data
* @param destinationAddress the destination address for the transaction
Expand All @@ -663,8 +811,6 @@ WalletSweeper.prototype.createTransaction = function(destinationAddress, fee, fe
var rawTransaction = new bitcoin.TransactionBuilder(this.network);
if (this.settings.bitcoinCash) {
rawTransaction.enableBitcoinCash();
} else if (this.settings.bitcoinGold) {
rawTransaction.enableBitcoinGold();
}
var inputs = [];
_.each(this.sweepData['utxos'], function(data, address) {
Expand Down Expand Up @@ -720,7 +866,7 @@ WalletSweeper.prototype.createTransaction = function(destinationAddress, fee, fe
value: input.value
};
});
fee = walletSDK.estimateVsizeFee(rawTransaction.buildIncomplete(), calcUtxos, feePerKb);
fee = walletSDK.estimateVsizeFee(rawTransaction.tx, calcUtxos, feePerKb);
}
rawTransaction.tx.outs[outputIdx].value -= fee;

Expand All @@ -740,7 +886,7 @@ WalletSweeper.prototype.signTransaction = function(rawTransaction, inputs) {
}

var sigHash = bitcoin.Transaction.SIGHASH_ALL;
if (this.settings.bitcoinCash || this.settings.bitcoinGold) {
if (this.settings.bitcoinCash) {
sigHash |= bitcoin.Transaction.SIGHASH_BITCOINCASHBIP143;
}

Expand All @@ -763,4 +909,4 @@ WalletSweeper.prototype.signTransaction = function(rawTransaction, inputs) {
}
};

module.exports = WalletSweeper;
module.exports = WalletSweeper;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
"scripts": {
"test": "mocha",
"coverage-test": "nyc --reporter=html --reporter=text mocha",
"browserify": "grunt build",
"browserify": "WITH=pbkdf2-hmac-sha512 grunt build",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"lint": "./node_modules/jscs/bin/jscs main.js lib/ test/ && ./node_modules/jscs/bin/jscs main.js main.js lib/ test/"
}
Expand Down