moac-lightwallets
Version:
A lightweight moac javascript wallet.
1,432 lines (1,149 loc) • 2.52 MB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.lightwallet = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
module.exports = {
txutils: require('./lib/txutils.js'),
encryption: require('./lib/encryption.js'),
signing: require('./lib/signing.js'),
keystore: require('./lib/keystore.js'),
upgrade: require('./lib/upgrade.js'),
};
},{"./lib/encryption.js":2,"./lib/keystore.js":3,"./lib/signing.js":4,"./lib/txutils.js":5,"./lib/upgrade.js":6}],2:[function(require,module,exports){
(function (Buffer){
var util = require("ethereumjs-util");
var nacl = require('tweetnacl');
function nacl_encodeHex(msgUInt8Arr) {
var msgBase64 = nacl.util.encodeBase64(msgUInt8Arr);
return (new Buffer(msgBase64, 'base64')).toString('hex');
}
function nacl_decodeHex(msgHex) {
var msgBase64 = (new Buffer(msgHex, 'hex')).toString('base64');
return nacl.util.decodeBase64(msgBase64);
}
function _asymEncryptRaw (keystore, pwDerivedKey, msgUint8Array, myPubKey, theirPubKey, hdPathString) {
if (hdPathString === undefined) {
hdPathString = keystore.defaultHdPathString;
}
if (keystore.ksData[hdPathString].info.purpose !== 'asymEncrypt') {
throw new Error('encryption._asymEncryptRaw: Function not defined when purpose is not "asymEncrypt"');
}
if (keystore.ksData[hdPathString].encPrivKeys[myPubKey] === undefined) {
throw new Error('encryption._asymEncryptRaw: public key not found in KeyStore');
}
var privKey = keystore.exportPrivateKey(myPubKey, pwDerivedKey, hdPathString);
var privKeyUInt8Array = nacl_decodeHex(privKey);
var pubKeyUInt8Array = nacl_decodeHex(theirPubKey);
var nonce = nacl.randomBytes(nacl.box.nonceLength);
var encryptedMessage = nacl.box(msgUint8Array, nonce, pubKeyUInt8Array, privKeyUInt8Array);
var output = {
alg: 'curve25519-xsalsa20-poly1305',
nonce: nacl.util.encodeBase64(nonce),
ciphertext: nacl.util.encodeBase64(encryptedMessage)
};
return output;
}
function _asymDecryptRaw (keystore, pwDerivedKey, encMsg, theirPubKey, myPubKey, hdPathString) {
if (hdPathString === undefined) {
hdPathString = keystore.defaultHdPathString;
}
if (keystore.ksData[hdPathString].info.purpose !== 'asymEncrypt') {
throw new Error('encryption._asymDecryptRaw: Function not defined when purpose is not "asymEncrypt"');
}
if (keystore.ksData[hdPathString].encPrivKeys[myPubKey] === undefined) {
throw new Error('encryption._asymDecryptRaw: public key not found in KeyStore');
}
var privKey = keystore.exportPrivateKey(myPubKey, pwDerivedKey, hdPathString);
var privKeyUInt8Array = nacl_decodeHex(privKey);
var pubKeyUInt8Array = nacl_decodeHex(theirPubKey);
var nonce = nacl.util.decodeBase64(encMsg.nonce);
var ciphertext = nacl.util.decodeBase64(encMsg.ciphertext);
var cleartext = nacl.box.open(ciphertext, nonce, pubKeyUInt8Array, privKeyUInt8Array);
return cleartext;
}
asymEncryptString = function (keystore, pwDerivedKey, msg, myPubKey, theirPubKey, hdPathString) {
var messageUInt8Array = nacl.util.decodeUTF8(msg);
return _asymEncryptRaw(keystore, pwDerivedKey, messageUInt8Array, myPubKey, theirPubKey, hdPathString);
}
asymDecryptString = function (keystore, pwDerivedKey, encMsg, theirPubKey, myPubKey, hdPathString) {
var cleartext = _asymDecryptRaw(keystore, pwDerivedKey, encMsg, theirPubKey, myPubKey, hdPathString);
if (cleartext === false) {
return false;
}
else {
return nacl.util.encodeUTF8(cleartext);
}
}
multiEncryptString = function (keystore, pwDerivedKey, msg, myPubKey, theirPubKeyArray, hdPathString) {
var messageUInt8Array = nacl.util.decodeUTF8(msg);
var symEncryptionKey = nacl.randomBytes(nacl.secretbox.keyLength);
var symNonce = nacl.randomBytes(nacl.secretbox.nonceLength);
var symEncMessage = nacl.secretbox(messageUInt8Array, symNonce, symEncryptionKey);
if (theirPubKeyArray.length < 1) {
throw new Error('Found no pubkeys to encrypt to.');
}
var encryptedSymKey = {};
encryptedSymKey = []
for (var i=0; i<theirPubKeyArray.length; i++) {
var encSymKey = _asymEncryptRaw(keystore, pwDerivedKey, symEncryptionKey, myPubKey, theirPubKeyArray[i], hdPathString);
delete encSymKey['alg'];
encryptedSymKey.push(encSymKey);
}
var output = {};
output.version = 1;
output.asymAlg = 'curve25519-xsalsa20-poly1305';
output.symAlg = 'xsalsa20-poly1305';
output.symNonce = nacl.util.encodeBase64(symNonce);
output.symEncMessage = nacl.util.encodeBase64(symEncMessage);
output.encryptedSymKey = encryptedSymKey;
return output;
}
multiDecryptString = function (keystore, pwDerivedKey, encMsg, theirPubKey, myPubKey, hdPathString) {
var symKey = false;
for (var i=0; i < encMsg.encryptedSymKey.length; i++) {
var result = _asymDecryptRaw(keystore, pwDerivedKey, encMsg.encryptedSymKey[i], theirPubKey, myPubKey, hdPathString)
if (result !== false) {
symKey = result;
break;
}
}
if (symKey === false) {
return false;
}
else {
var symNonce = nacl.util.decodeBase64(encMsg.symNonce);
var symEncMessage = nacl.util.decodeBase64(encMsg.symEncMessage);
var msg = nacl.secretbox.open(symEncMessage, symNonce, symKey);
if (msg === false) {
return false;
}
else {
return nacl.util.encodeUTF8(msg);
}
}
}
module.exports = {
asymEncryptString: asymEncryptString,
asymDecryptString: asymDecryptString,
multiEncryptString: multiEncryptString,
multiDecryptString: multiDecryptString,
};
}).call(this,require("buffer").Buffer)
},{"buffer":99,"ethereumjs-util":382,"tweetnacl":419}],3:[function(require,module,exports){
(function (Buffer){
var CryptoJS = require('crypto-js');
var Transaction = require('ethereumjs-tx');
var EC = require('elliptic').ec;
var ec = new EC('secp256k1');
var bitcore = require('bitcore-lib');
var Random = bitcore.crypto.Random;
var Hash = bitcore.crypto.Hash;
var Mnemonic = require('bitcore-mnemonic');
var nacl = require('tweetnacl');
var scrypt = require('scrypt-async');
var encryption = require('./encryption');
var signing = require('./signing');
function strip0x (input) {
if (typeof(input) !== 'string') {
return input;
}
else if (input.length >= 2 && input.slice(0,2) === '0x') {
return input.slice(2);
}
else {
return input;
}
}
function add0x (input) {
if (typeof(input) !== 'string') {
return input;
}
else if (input.length < 2 || input.slice(0,2) !== '0x') {
return '0x' + input;
}
else {
return input;
}
}
function leftPadString (stringToPad, padChar, length) {
var repreatedPadChar = '';
for (var i=0; i<length; i++) {
repreatedPadChar += padChar;
}
return ( (repreatedPadChar + stringToPad).slice(-length) );
}
function nacl_encodeHex(msgUInt8Arr) {
var msgBase64 = nacl.util.encodeBase64(msgUInt8Arr);
return (new Buffer(msgBase64, 'base64')).toString('hex');
}
function nacl_decodeHex(msgHex) {
var msgBase64 = (new Buffer(msgHex, 'hex')).toString('base64');
return nacl.util.decodeBase64(msgBase64);
}
var KeyStore = function(mnemonic, pwDerivedKey, hdPathString) {
this.defaultHdPathString = "m/0'/0'/0'";
if (hdPathString === undefined) {
hdPathString = this.defaultHdPathString;
}
this.ksData = {};
this.ksData[hdPathString] = {};
pathKsData = this.ksData[hdPathString];
pathKsData.info = {curve: 'secp256k1', purpose: 'sign'};
this.encSeed = undefined;
this.encHdRootPriv = undefined;
this.version = 2;
pathKsData.encHdPathPriv = undefined;
pathKsData.hdIndex = 0;
pathKsData.encPrivKeys = {};
pathKsData.addresses = [];
if ( (typeof pwDerivedKey !== 'undefined') && (typeof mnemonic !== 'undefined') ){
var words = mnemonic.split(' ');
if (!Mnemonic.isValid(mnemonic, Mnemonic.Words.ENGLISH) || words.length !== 12){
throw new Error('KeyStore: Invalid mnemonic');
}
// Pad the seed to length 120 before encrypting
var paddedSeed = leftPadString(mnemonic, ' ', 120);
this.encSeed = KeyStore._encryptString(paddedSeed, pwDerivedKey);
// hdRoot is the relative root from which we derive the keys using
// generateNewAddress(). The derived keys are then
// `hdRoot/hdIndex`.
//
// Default hdRoot is m/0'/0'/0', the overall logic is
// m/0'/Persona'/Purpose', where the 0' purpose is
// for standard Ethereum accounts.
var hdRoot = new Mnemonic(mnemonic).toHDPrivateKey().xprivkey;
this.encHdRootPriv = KeyStore._encryptString(hdRoot, pwDerivedKey);
var hdRootKey = new bitcore.HDPrivateKey(hdRoot);
var hdPath = hdRootKey.derive(hdPathString).xprivkey;
pathKsData.encHdPathPriv = KeyStore._encryptString(hdPath, pwDerivedKey);
}
};
KeyStore._encryptString = function (string, pwDerivedKey) {
var nonce = nacl.randomBytes(nacl.secretbox.nonceLength);
var encObj = nacl.secretbox(nacl.util.decodeUTF8(string), nonce, pwDerivedKey);
var encString = { 'encStr': nacl.util.encodeBase64(encObj),
'nonce': nacl.util.encodeBase64(nonce)};
return encString;
};
KeyStore._decryptString = function (encryptedStr, pwDerivedKey) {
var secretbox = nacl.util.decodeBase64(encryptedStr.encStr);
var nonce = nacl.util.decodeBase64(encryptedStr.nonce);
var decryptedStr = nacl.secretbox.open(secretbox, nonce, pwDerivedKey);
return nacl.util.encodeUTF8(decryptedStr);
};
KeyStore._encryptKey = function (privKey, pwDerivedKey) {
var privKeyArray = nacl_decodeHex(privKey);
var nonce = nacl.randomBytes(nacl.secretbox.nonceLength);
var encKey = nacl.secretbox(privKeyArray, nonce, pwDerivedKey);
encKey = { 'key': nacl.util.encodeBase64(encKey), 'nonce': nacl.util.encodeBase64(nonce)};
return encKey;
};
KeyStore._decryptKey = function (encryptedKey, pwDerivedKey) {
var secretbox = nacl.util.decodeBase64(encryptedKey.key);
var nonce = nacl.util.decodeBase64(encryptedKey.nonce);
var decryptedKey = nacl.secretbox.open(secretbox, nonce, pwDerivedKey);
return nacl_encodeHex(decryptedKey);
};
KeyStore._computeAddressFromPrivKey = function (privKey) {
var keyPair = ec.genKeyPair();
keyPair._importPrivate(privKey, 'hex');
var compact = false;
var pubKey = keyPair.getPublic(compact, 'hex').slice(2);
var pubKeyWordArray = CryptoJS.enc.Hex.parse(pubKey);
var hash = CryptoJS.SHA3(pubKeyWordArray, { outputLength: 256 });
var address = hash.toString(CryptoJS.enc.Hex).slice(24);
return address;
};
KeyStore._computePubkeyFromPrivKey = function (privKey, curve) {
if (curve !== 'curve25519') {
throw new Error('KeyStore._computePubkeyFromPrivKey: Only "curve25519" supported.')
}
var privKeyBase64 = (new Buffer(privKey, 'hex')).toString('base64')
var privKeyUInt8Array = nacl.util.decodeBase64(privKeyBase64);
var pubKey = nacl.box.keyPair.fromSecretKey(privKeyUInt8Array).publicKey;
var pubKeyBase64 = nacl.util.encodeBase64(pubKey);
var pubKeyHex = (new Buffer(pubKeyBase64, 'base64')).toString('hex');
return pubKeyHex;
}
KeyStore.prototype.addHdDerivationPath = function (hdPathString, pwDerivedKey, info) {
if (info.purpose !== 'sign' && info.purpose !== 'asymEncrypt') {
throw new Error("KeyStore.addHdDerivationPath: info.purpose is '" + info.purpose + "' but must be either 'sign' or 'asymEncrypt'.");
}
if (info.curve !== 'secp256k1' && info.curve !== 'curve25519') {
throw new Error("KeyStore.addHdDerivationPath: info.curve is '" + info.curve + "' but must be either 'secp256k1' or 'curve25519'.");
}
var hdRoot = KeyStore._decryptString(this.encHdRootPriv, pwDerivedKey);
var hdRootKey = new bitcore.HDPrivateKey(hdRoot);
var hdPath = hdRootKey.derive(hdPathString).xprivkey;
this.ksData[hdPathString] = {};
this.ksData[hdPathString].info = info;
this.ksData[hdPathString].encHdPathPriv = KeyStore._encryptString(hdPath, pwDerivedKey);
this.ksData[hdPathString].hdIndex = 0;
this.ksData[hdPathString].encPrivKeys = {};
if (info.purpose === 'sign') {
this.ksData[hdPathString].addresses = [];
}
else if (info.purpose === 'asymEncrypt') {
this.ksData[hdPathString].pubKeys = [];
}
}
KeyStore.prototype.setDefaultHdDerivationPath = function (hdPathString) {
if (this.ksData[hdPathString] === undefined) {
throw new Error('setDefaultHdDerivationPath: HD path does not exist. Cannot set default.');
}
this.defaultHdPathString = hdPathString;
}
KeyStore.prototype._generatePrivKeys = function(pwDerivedKey, n, hdPathString) {
if (hdPathString === undefined) {
hdPathString = this.defaultHdPathString;
}
var hdRoot = KeyStore._decryptString(this.ksData[hdPathString].encHdPathPriv, pwDerivedKey);
var keys = [];
for (var i = 0; i < n; i++){
var hdprivkey = new bitcore.HDPrivateKey(hdRoot).derive(this.ksData[hdPathString].hdIndex++);
var privkeyBuf = hdprivkey.privateKey.toBuffer();
var privkeyHex = privkeyBuf.toString('hex');
if (privkeyBuf.length < 16) {
// Way too small key, something must have gone wrong
// Halt and catch fire
throw new Error('Private key suspiciously small: < 16 bytes. Aborting!');
}
else if (privkeyBuf.length < 32) {
// Pad private key if too short
// bitcore has a bug where it sometimes returns
// truncated keys
privkeyHex = leftPadString(privkeyBuf.toString('hex'), '0', 64);
}
else if (privkeyBuf.length > 32) {
throw new Error('Private key larger than 32 bytes. Aborting!');
}
var encPrivKey = KeyStore._encryptKey(privkeyHex, pwDerivedKey);
keys[i] = {
privKey: privkeyHex,
encPrivKey: encPrivKey
}
}
return keys;
};
// This function is tested using the test vectors here:
// http://www.di-mgt.com.au/sha_testvectors.html
KeyStore._concatAndSha256 = function(entropyBuf0, entropyBuf1) {
var totalEnt = Buffer.concat([entropyBuf0, entropyBuf1]);
if (totalEnt.length !== entropyBuf0.length + entropyBuf1.length) {
throw new Error('generateRandomSeed: Logic error! Concatenation of entropy sources failed.')
}
var hashedEnt = Hash.sha256(totalEnt);
return hashedEnt;
}
// External static functions
// Generates a random seed. If the optional string
// extraEntropy is set, a random set of entropy
// is created, then concatenated with extraEntropy
// and hashed to produce the entropy that gives the seed.
// Thus if extraEntropy comes from a high-entropy source
// (like dice) it can give some protection from a bad RNG.
// If extraEntropy is not set, the random number generator
// is used directly.
KeyStore.generateRandomSeed = function(extraEntropy) {
var seed = '';
if (extraEntropy === undefined) {
seed = new Mnemonic(Mnemonic.Words.ENGLISH);
}
else if (typeof extraEntropy === 'string') {
var entBuf = new Buffer(extraEntropy);
var randBuf = Random.getRandomBuffer(256 / 8);
var hashedEnt = this._concatAndSha256(randBuf, entBuf).slice(0, 128 / 8);
seed = new Mnemonic(hashedEnt, Mnemonic.Words.ENGLISH);
}
else {
throw new Error('generateRandomSeed: extraEntropy is set but not a string.')
}
return seed.toString();
};
KeyStore.isSeedValid = function(seed) {
return Mnemonic.isValid(seed, Mnemonic.Words.ENGLISH)
};
KeyStore.prototype.isDerivedKeyCorrect = function(pwDerivedKey) {
var paddedSeed = KeyStore._decryptString(this.encSeed, pwDerivedKey);
if (paddedSeed.length > 0) {
return true;
}
return false;
};
// Takes keystore serialized as string and returns an instance of KeyStore
KeyStore.deserialize = function (keystore) {
var jsonKS = JSON.parse(keystore);
if (jsonKS.version === undefined || jsonKS.version === 1) {
throw new Error('Old version of serialized keystore. Please use KeyStore.upgradeOldSerialized() to convert it to the latest version.')
}
// Create keystore
var keystoreX = new KeyStore();
keystoreX.encSeed = jsonKS.encSeed;
keystoreX.encHdRootPriv = jsonKS.encHdRootPriv;
keystoreX.ksData = jsonKS.ksData;
return keystoreX;
};
// External API functions
KeyStore.prototype.serialize = function () {
var jsonKS = {'encSeed': this.encSeed,
'ksData' : this.ksData,
'encHdRootPriv' : this.encHdRootPriv,
'version' : this.version};
return JSON.stringify(jsonKS);
};
KeyStore.prototype.getAddresses = function (hdPathString) {
if (hdPathString === undefined) {
hdPathString = this.defaultHdPathString;
}
if (this.ksData[hdPathString].info.purpose !== 'sign') {
throw new Error('KeyStore.getAddresses: Addresses not defined when purpose is not "sign"');
}
return this.ksData[hdPathString].addresses;
};
KeyStore.prototype.getSeed = function (pwDerivedKey) {
var paddedSeed = KeyStore._decryptString(this.encSeed, pwDerivedKey);
return paddedSeed.trim();
};
KeyStore.prototype.exportPrivateKey = function (address, pwDerivedKey, hdPathString) {
if (hdPathString === undefined) {
hdPathString = this.defaultHdPathString;
}
var address = strip0x(address);
if (this.ksData[hdPathString].encPrivKeys[address] === undefined) {
throw new Error('KeyStore.exportPrivateKey: Address not found in KeyStore');
}
var encPrivKey = this.ksData[hdPathString].encPrivKeys[address];
var privKey = KeyStore._decryptKey(encPrivKey, pwDerivedKey);
return privKey;
};
KeyStore.prototype.generateNewAddress = function(pwDerivedKey, n, hdPathString) {
if (hdPathString === undefined) {
hdPathString = this.defaultHdPathString;
}
if (this.ksData[hdPathString].info.purpose !== 'sign') {
throw new Error('KeyStore.generateNewAddress: Address not defined when purpose is not "sign"');
}
if (!this.encSeed) {
throw new Error('KeyStore.generateNewAddress: No seed set');
}
n = n || 1;
var keys = this._generatePrivKeys(pwDerivedKey, n, hdPathString);
for (var i = 0; i < n; i++) {
var keyObj = keys[i];
var address = KeyStore._computeAddressFromPrivKey(keyObj.privKey);
this.ksData[hdPathString].encPrivKeys[address] = keyObj.encPrivKey;
this.ksData[hdPathString].addresses.push(address);
}
};
KeyStore.prototype.generateNewEncryptionKeys = function(pwDerivedKey, n, hdPathString) {
if (hdPathString === undefined) {
hdPathString = this.defaultHdPathString;
}
if (this.ksData[hdPathString].info.purpose !== 'asymEncrypt') {
throw new Error('KeyStore.generateNewEncryptionKeys: Address not defined when purpose is not "asymEncrypt"');
}
if (!this.encSeed) {
throw new Error('KeyStore.generateNewEncryptionKeys: No seed set');
}
n = n || 1;
var keys = this._generatePrivKeys(pwDerivedKey, n, hdPathString);
var curve = this.ksData[hdPathString].info.curve;
for (var i = 0; i < n; i++) {
var keyObj = keys[i];
var pubkey = KeyStore._computePubkeyFromPrivKey(keyObj.privKey, curve);
this.ksData[hdPathString].encPrivKeys[pubkey] = keyObj.encPrivKey;
this.ksData[hdPathString].pubKeys.push(pubkey);
}
};
KeyStore.prototype.getPubKeys = function (hdPathString) {
if (hdPathString === undefined) {
hdPathString = this.defaultHdPathString;
}
if (this.ksData[hdPathString].info.purpose !== 'asymEncrypt') {
throw new Error('KeyStore.getPubKeys: Not defined when purpose is not "asymEncrypt"');
}
if (this.ksData[hdPathString].pubKeys === undefined) {
throw new Error('KeyStore.getPubKeys: No pubKeys data found!');
}
return this.ksData[hdPathString].pubKeys;
}
KeyStore.deriveKeyFromPassword = function(password, callback) {
var salt = 'lightwalletSalt'; // should we have user-defined salt?
var logN = 14;
var r = 8;
var dkLen = 32;
var interruptStep = 200;
var cb = function(derKey) {
var ui8arr = (new Uint8Array(derKey));
callback(null, ui8arr);
}
scrypt(password, salt, logN, r, dkLen, interruptStep, cb, null);
}
// Async functions exposed for Hooked Web3-provider
// hasAddress(address, callback)
// signTransaction(txParams, callback)
//
// The function signTransaction() needs the
// function KeyStore.prototype.passwordProvider(callback)
// to be set in order to run properly.
// The function passwordProvider is an async function
// that calls the callback(err, password) with a password
// supplied by the user or by other means.
// The user of the hooked web3-provider is encouraged
// to write their own passwordProvider.
//
// Uses defaultHdPathString for the addresses.
KeyStore.prototype.passwordProvider = function (callback) {
var password = prompt("Enter password to continue","Enter password");
callback(null, password);
}
KeyStore.prototype.hasAddress = function (address, callback) {
var addrToCheck = strip0x(address);
if (this.ksData[this.defaultHdPathString].encPrivKeys[addrToCheck] === undefined) {
callback('Address not found!', false);
}
else {
callback(null, true);
}
};
KeyStore.prototype.signTransaction = function (txParams, callback) {
var ethjsTxParams = {};
ethjsTxParams.from = add0x(txParams.from);
ethjsTxParams.to = add0x(txParams.to);
ethjsTxParams.gasLimit = add0x(txParams.gas);
ethjsTxParams.gasPrice = add0x(txParams.gasPrice);
ethjsTxParams.nonce = add0x(txParams.nonce);
ethjsTxParams.value = add0x(txParams.value);
ethjsTxParams.data = add0x(txParams.data);
var txObj = new Transaction(ethjsTxParams);
var rawTx = txObj.serialize().toString('hex');
var signingAddress = strip0x(txParams.from);
var self = this;
this.passwordProvider( function (err, password) {
if (err) return callback(err);
KeyStore.deriveKeyFromPassword(password, function (err, pwDerivedKey) {
var signedTx = signing.signTx(self, pwDerivedKey, rawTx, signingAddress, self.defaultHdPathString);
callback(null, '0x' + signedTx);
})
})
};
module.exports = KeyStore;
}).call(this,require("buffer").Buffer)
},{"./encryption":2,"./signing":4,"bitcore-lib":7,"bitcore-mnemonic":86,"buffer":99,"crypto-js":330,"elliptic":356,"ethereumjs-tx":379,"scrypt-async":418,"tweetnacl":419}],4:[function(require,module,exports){
(function (Buffer){
var Transaction = require("ethereumjs-tx")
var util = require("ethereumjs-util")
signTx = function (keystore, pwDerivedKey, rawTx, signingAddress, hdPathString) {
if (hdPathString === undefined) {
hdPathString = keystore.defaultHdPathString;
}
rawTx = util.stripHexPrefix(rawTx);
signingAddress = util.stripHexPrefix(signingAddress);
var txCopy = new Transaction(new Buffer(rawTx, 'hex'));
var privKey = keystore.exportPrivateKey(signingAddress, pwDerivedKey, hdPathString);
txCopy.sign(new Buffer(privKey, 'hex'));
privKey = '';
return txCopy.serialize().toString('hex');
};
module.exports.signTx = signTx;
signMsg = function (keystore, pwDerivedKey, rawMsg, signingAddress, hdPathString) {
if (hdPathString === undefined) {
hdPathString = keystore.defaultHdPathString;
}
signingAddress = util.stripHexPrefix(signingAddress);
var msgHash = util.sha3(rawMsg);
var privKey = keystore.exportPrivateKey(signingAddress, pwDerivedKey, hdPathString);
return util.ecsign(msgHash, new Buffer(privKey, 'hex'));
};
module.exports.signMsg = signMsg;
recoverAddress = function (rawMsg, v, r, s) {
var msgHash = util.sha3(rawMsg);
return util.pubToAddress(util.ecrecover(msgHash, v, r, s));
};
module.exports.recoverAddress = recoverAddress;
concatSig = function (v, r, s) {
r = util.fromSigned(r);
s = util.fromSigned(s);
v = util.bufferToInt(v);
r = util.toUnsigned(r).toString('hex');
s = util.toUnsigned(s).toString('hex');
v = util.stripHexPrefix(util.intToHex(v));
return util.addHexPrefix(r.concat(s, v).toString("hex"));
};
module.exports.concatSig = concatSig;
}).call(this,require("buffer").Buffer)
},{"buffer":99,"ethereumjs-tx":379,"ethereumjs-util":382}],5:[function(require,module,exports){
(function (Buffer){
var Transaction = require('ethereumjs-tx');
var coder = require('web3/lib/solidity/coder');
var rlp = require('rlp');
var CryptoJS = require('crypto-js');
function add0x (input) {
if (typeof(input) !== 'string') {
return input;
}
else if (input.length < 2 || input.slice(0,2) !== '0x') {
return '0x' + input;
}
else {
return input;
}
}
function _encodeFunctionTxData (functionName, types, args) {
var fullName = functionName + '(' + types.join() + ')';
var signature = CryptoJS.SHA3(fullName, { outputLength: 256 }).toString(CryptoJS.enc.Hex).slice(0, 8);
var dataHex = signature + coder.encodeParams(types, args);
return dataHex;
}
function _getTypesFromAbi (abi, functionName) {
function matchesFunctionName(json) {
return (json.name === functionName && json.type === 'function');
}
function getTypes(json) {
return json.type;
}
var funcJson = abi.filter(matchesFunctionName)[0];
return (funcJson.inputs).map(getTypes);
}
function functionTx (abi, functionName, args, txObject) {
// txObject contains gasPrice, gasLimit, nonce, to, value
var types = _getTypesFromAbi(abi, functionName);
var txData = _encodeFunctionTxData(functionName, types, args);
var txObjectCopy = {};
txObjectCopy.to = add0x(txObject.to);
txObjectCopy.gasPrice = add0x(txObject.gasPrice);
txObjectCopy.gasLimit = add0x(txObject.gasLimit);
txObjectCopy.nonce = add0x(txObject.nonce);
txObjectCopy.data = add0x(txData);
txObjectCopy.value = add0x(txObject.value);
return (new Transaction(txObjectCopy)).serialize().toString('hex');
}
function createdContractAddress (fromAddress, nonce) {
var rlpEncodedHex = rlp.encode([new Buffer(fromAddress, 'hex'), nonce]).toString('hex');
var rlpEncodedWordArray = CryptoJS.enc.Hex.parse(rlpEncodedHex);
var hash = CryptoJS.SHA3(rlpEncodedWordArray, {outputLength: 256}).toString(CryptoJS.enc.Hex);
return hash.slice(24);
}
function createContractTx (fromAddress, txObject) {
// txObject contains gasPrice, gasLimit, value, data, nonce
var txObjectCopy = {};
txObjectCopy.to = add0x(txObject.to);
txObjectCopy.gasPrice = add0x(txObject.gasPrice);
txObjectCopy.gasLimit = add0x(txObject.gasLimit);
txObjectCopy.nonce = add0x(txObject.nonce);
txObjectCopy.data = add0x(txObject.data);
txObjectCopy.value = add0x(txObject.value);
var contractAddress = createdContractAddress(fromAddress, txObject.nonce);
var tx = new Transaction(txObjectCopy);
return {tx: tx.serialize().toString('hex'), addr: contractAddress};
}
function valueTx (txObject) {
// txObject contains gasPrice, gasLimit, value, nonce
var txObjectCopy = {};
txObjectCopy.to = add0x(txObject.to);
txObjectCopy.gasPrice = add0x(txObject.gasPrice);
txObjectCopy.gasLimit = add0x(txObject.gasLimit);
txObjectCopy.nonce = add0x(txObject.nonce);
txObjectCopy.value = add0x(txObject.value);
var tx = new Transaction(txObjectCopy);
return tx.serialize().toString('hex');
}
module.exports = {
_encodeFunctionTxData: _encodeFunctionTxData,
_getTypesFromAbi: _getTypesFromAbi,
functionTx: functionTx,
createdContractAddress: createdContractAddress,
createContractTx: createContractTx,
valueTx: valueTx
};
}).call(this,require("buffer").Buffer)
},{"buffer":99,"crypto-js":330,"ethereumjs-tx":379,"rlp":417,"web3/lib/solidity/coder":423}],6:[function(require,module,exports){
var CryptoJS = require('crypto-js');
var keystore = require('./keystore');
var Transaction = require('ethereumjs-tx');
var EC = require('elliptic').ec;
var ec = new EC('secp256k1');
var bitcore = require('bitcore-lib');
var Random = bitcore.crypto.Random;
var Hash = bitcore.crypto.Hash;
var Mnemonic = require('bitcore-mnemonic');
var nacl = require('tweetnacl');
var scrypt = require('scrypt-async');
legacyDecryptString = function (encryptedStr, password) {
var decryptedStr = CryptoJS.AES.decrypt(encryptedStr.encStr, password, {'iv': encryptedStr.iv, 'salt': encryptedStr.salt });
return decryptedStr.toString(CryptoJS.enc.Latin1);
};
legacyGenerateEncKey = function(password, salt, keyHash) {
var encKey = CryptoJS.PBKDF2(password, salt, { keySize: 512 / 32, iterations: 150 }).toString();
var hash = CryptoJS.SHA3(encKey).toString();
if (keyHash !== hash){
throw new Error('Invalid Password');
}
return encKey;
};
upgradeOldSerialized = function (oldSerialized, password, callback) {
// Upgrades old serialized version of the keystore
// to the latest version
var oldKS = JSON.parse(oldSerialized);
if (oldKS.version === undefined || oldKS.version === 1) {
var derivedKey = legacyGenerateEncKey(password, oldKS.salt, oldKS.keyHash);
var seed = legacyDecryptString(oldKS.encSeed, derivedKey);
keystore.deriveKeyFromPassword(password, function(err, pwDerivedKey) {
var newKeyStore = new keystore(seed, pwDerivedKey);
var hdIndex = oldKS.hdIndex;
newKeyStore.generateNewAddress(pwDerivedKey, hdIndex);
callback(null, newKeyStore.serialize());
})
}
else {
throw new Error('Keystore is not of correct version.')
}
}
module.exports.upgradeOldSerialized = upgradeOldSerialized;
},{"./keystore":3,"bitcore-lib":7,"bitcore-mnemonic":86,"crypto-js":330,"elliptic":356,"ethereumjs-tx":379,"scrypt-async":418,"tweetnacl":419}],7:[function(require,module,exports){
(function (global,Buffer){
'use strict';
var bitcore = module.exports;
// module information
bitcore.version = 'v' + require('./package.json').version;
bitcore.versionGuard = function(version) {
if (version !== undefined) {
var message = 'More than one instance of bitcore-lib found. ' +
'Please make sure to require bitcore-lib and check that submodules do' +
' not also include their own bitcore-lib dependency.';
throw new Error(message);
}
};
bitcore.versionGuard(global._bitcore);
global._bitcore = bitcore.version;
// crypto
bitcore.crypto = {};
bitcore.crypto.BN = require('./lib/crypto/bn');
bitcore.crypto.ECDSA = require('./lib/crypto/ecdsa');
bitcore.crypto.Hash = require('./lib/crypto/hash');
bitcore.crypto.Random = require('./lib/crypto/random');
bitcore.crypto.Point = require('./lib/crypto/point');
bitcore.crypto.Signature = require('./lib/crypto/signature');
// encoding
bitcore.encoding = {};
bitcore.encoding.Base58 = require('./lib/encoding/base58');
bitcore.encoding.Base58Check = require('./lib/encoding/base58check');
bitcore.encoding.BufferReader = require('./lib/encoding/bufferreader');
bitcore.encoding.BufferWriter = require('./lib/encoding/bufferwriter');
bitcore.encoding.Varint = require('./lib/encoding/varint');
// utilities
bitcore.util = {};
bitcore.util.buffer = require('./lib/util/buffer');
bitcore.util.js = require('./lib/util/js');
bitcore.util.preconditions = require('./lib/util/preconditions');
// errors thrown by the library
bitcore.errors = require('./lib/errors');
// main bitcoin library
bitcore.Address = require('./lib/address');
bitcore.Block = require('./lib/block');
bitcore.MerkleBlock = require('./lib/block/merkleblock');
bitcore.BlockHeader = require('./lib/block/blockheader');
bitcore.HDPrivateKey = require('./lib/hdprivatekey.js');
bitcore.HDPublicKey = require('./lib/hdpublickey.js');
bitcore.Networks = require('./lib/networks');
bitcore.Opcode = require('./lib/opcode');
bitcore.PrivateKey = require('./lib/privatekey');
bitcore.PublicKey = require('./lib/publickey');
bitcore.Script = require('./lib/script');
bitcore.Transaction = require('./lib/transaction');
bitcore.URI = require('./lib/uri');
bitcore.Unit = require('./lib/unit');
// dependencies, subject to change
bitcore.deps = {};
bitcore.deps.bnjs = require('bn.js');
bitcore.deps.bs58 = require('bs58');
bitcore.deps.Buffer = Buffer;
bitcore.deps.elliptic = require('elliptic');
bitcore.deps._ = require('lodash');
// Internal usage, exposed for testing/advanced tweaking
bitcore._HDKeyCache = require('./lib/hdkeycache');
bitcore.Transaction.sighash = require('./lib/transaction/sighash');
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
},{"./lib/address":8,"./lib/block":11,"./lib/block/blockheader":10,"./lib/block/merkleblock":12,"./lib/crypto/bn":13,"./lib/crypto/ecdsa":14,"./lib/crypto/hash":15,"./lib/crypto/point":16,"./lib/crypto/random":17,"./lib/crypto/signature":18,"./lib/encoding/base58":19,"./lib/encoding/base58check":20,"./lib/encoding/bufferreader":21,"./lib/encoding/bufferwriter":22,"./lib/encoding/varint":23,"./lib/errors":24,"./lib/hdkeycache":26,"./lib/hdprivatekey.js":27,"./lib/hdpublickey.js":28,"./lib/networks":29,"./lib/opcode":30,"./lib/privatekey":31,"./lib/publickey":32,"./lib/script":33,"./lib/transaction":36,"./lib/transaction/sighash":44,"./lib/unit":48,"./lib/uri":49,"./lib/util/buffer":50,"./lib/util/js":51,"./lib/util/preconditions":52,"./package.json":85,"bn.js":53,"bs58":54,"buffer":99,"elliptic":56,"lodash":78}],8:[function(require,module,exports){
(function (Buffer){
'use strict';
var _ = require('lodash');
var $ = require('./util/preconditions');
var errors = require('./errors');
var Base58Check = require('./encoding/base58check');
var Networks = require('./networks');
var Hash = require('./crypto/hash');
var JSUtil = require('./util/js');
var PublicKey = require('./publickey');
/**
* Instantiate an address from an address String or Buffer, a public key or script hash Buffer,
* or an instance of {@link PublicKey} or {@link Script}.
*
* This is an immutable class, and if the first parameter provided to this constructor is an
* `Address` instance, the same argument will be returned.
*
* An address has two key properties: `network` and `type`. The type is either
* `Address.PayToPublicKeyHash` (value is the `'pubkeyhash'` string)
* or `Address.PayToScriptHash` (the string `'scripthash'`). The network is an instance of {@link Network}.
* You can quickly check whether an address is of a given kind by using the methods
* `isPayToPublicKeyHash` and `isPayToScriptHash`
*
* @example
* ```javascript
* // validate that an input field is valid
* var error = Address.getValidationError(input, 'testnet');
* if (!error) {
* var address = Address(input, 'testnet');
* } else {
* // invalid network or checksum (typo?)
* var message = error.messsage;
* }
*
* // get an address from a public key
* var address = Address(publicKey, 'testnet').toString();
* ```
*
* @param {*} data - The encoded data in various formats
* @param {Network|String|number=} network - The network: 'livenet' or 'testnet'
* @param {string=} type - The type of address: 'script' or 'pubkey'
* @returns {Address} A new valid and frozen instance of an Address
* @constructor
*/
function Address(data, network, type) {
/* jshint maxcomplexity: 12 */
/* jshint maxstatements: 20 */
if (!(this instanceof Address)) {
return new Address(data, network, type);
}
if (_.isArray(data) && _.isNumber(network)) {
return Address.createMultisig(data, network, type);
}
if (data instanceof Address) {
// Immutable instance
return data;
}
$.checkArgument(data, 'First argument is required, please include address data.', 'guide/address.html');
if (network && !Networks.get(network)) {
throw new TypeError('Second argument must be "livenet" or "testnet".');
}
if (type && (type !== Address.PayToPublicKeyHash && type !== Address.PayToScriptHash)) {
throw new TypeError('Third argument must be "pubkeyhash" or "scripthash".');
}
var info = this._classifyArguments(data, network, type);
// set defaults if not set
info.network = info.network || Networks.get(network) || Networks.defaultNetwork;
info.type = info.type || type || Address.PayToPublicKeyHash;
JSUtil.defineImmutable(this, {
hashBuffer: info.hashBuffer,
network: info.network,
type: info.type
});
return this;
}
/**
* Internal function used to split different kinds of arguments of the constructor
* @param {*} data - The encoded data in various formats
* @param {Network|String|number=} network - The network: 'livenet' or 'testnet'
* @param {string=} type - The type of address: 'script' or 'pubkey'
* @returns {Object} An "info" object with "type", "network", and "hashBuffer"
*/
Address.prototype._classifyArguments = function(data, network, type) {
/* jshint maxcomplexity: 10 */
// transform and validate input data
if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 20) {
return Address._transformHash(data);
} else if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 21) {
return Address._transformBuffer(data, network, type);
} else if (data instanceof PublicKey) {
return Address._transformPublicKey(data);
} else if (data instanceof Script) {
return Address._transformScript(data, network);
} else if (typeof(data) === 'string') {
return Address._transformString(data, network, type);
} else if (_.isObject(data)) {
return Address._transformObject(data);
} else {
throw new TypeError('First argument is an unrecognized data format.');
}
};
/** @static */
Address.PayToPublicKeyHash = 'pubkeyhash';
/** @static */
Address.PayToScriptHash = 'scripthash';
/**
* @param {Buffer} hash - An instance of a hash Buffer
* @returns {Object} An object with keys: hashBuffer
* @private
*/
Address._transformHash = function(hash) {
var info = {};
if (!(hash instanceof Buffer) && !(hash instanceof Uint8Array)) {
throw new TypeError('Address supplied is not a buffer.');
}
if (hash.length !== 20) {
throw new TypeError('Address hashbuffers must be exactly 20 bytes.');
}
info.hashBuffer = hash;
return info;
};
/**
* Deserializes an address serialized through `Address#toObject()`
* @param {Object} data
* @param {string} data.hash - the hash that this address encodes
* @param {string} data.type - either 'pubkeyhash' or 'scripthash'
* @param {Network=} data.network - the name of the network associated
* @return {Address}
*/
Address._transformObject = function(data) {
$.checkArgument(data.hash || data.hashBuffer, 'Must provide a `hash` or `hashBuffer` property');
$.checkArgument(data.type, 'Must provide a `type` property');
return {
hashBuffer: data.hash ? new Buffer(data.hash, 'hex') : data.hashBuffer,
network: Networks.get(data.network) || Networks.defaultNetwork,
type: data.type
};
};
/**
* Internal function to discover the network and type based on the first data byte
*
* @param {Buffer} buffer - An instance of a hex encoded address Buffer
* @returns {Object} An object with keys: network and type
* @private
*/
Address._classifyFromVersion = function(buffer) {
var version = {};
var pubkeyhashNetwork = Networks.get(buffer[0], 'pubkeyhash');
var scripthashNetwork = Networks.get(buffer[0], 'scripthash');
if (pubkeyhashNetwork) {
version.network = pubkeyhashNetwork;
version.type = Address.PayToPublicKeyHash;
} else if (scripthashNetwork) {
version.network = scripthashNetwork;
version.type = Address.PayToScriptHash;
}
return version;
};
/**
* Internal function to transform a bitcoin address buffer
*
* @param {Buffer} buffer - An instance of a hex encoded address Buffer
* @param {string=} network - The network: 'livenet' or 'testnet'
* @param {string=} type - The type: 'pubkeyhash' or 'scripthash'
* @returns {Object} An object with keys: hashBuffer, network and type
* @private
*/
Address._transformBuffer = function(buffer, network, type) {
/* jshint maxcomplexity: 9 */
var info = {};
if (!(buffer instanceof Buffer) && !(buffer instanceof Uint8Array)) {
throw new TypeError('Address supplied is not a buffer.');
}
if (buffer.length !== 1 + 20) {
throw new TypeError('Address buffers must be exactly 21 bytes.');
}
network = Networks.get(network);
var bufferVersion = Address._classifyFromVersion(buffer);
if (!bufferVersion.network || (network && network !== bufferVersion.network)) {
throw new TypeError('Address has mismatched network type.');
}
if (!bufferVersion.type || (type && type !== bufferVersion.type)) {
throw new TypeError('Address has mismatched type.');
}
info.hashBuffer = buffer.slice(1);
info.network = bufferVersion.network;
info.type = bufferVersion.type;
return info;
};
/**
* Internal function to transform a {@link PublicKey}
*
* @param {PublicKey} pubkey - An instance of PublicKey
* @returns {Object} An object with keys: hashBuffer, type
* @private
*/
Address._transformPublicKey = function(pubkey) {
var info = {};
if (!(pubkey instanceof PublicKey)) {
throw new TypeError('Address must be an instance of PublicKey.');
}
info.hashBuffer = Hash.sha256ripemd160(pubkey.toBuffer());
info.type = Address.PayToPublicKeyHash;
return info;
};
/**
* Internal function to transform a {@link Script} into a `info` object.
*
* @param {Script} script - An instance of Script
* @returns {Object} An object with keys: hashBuffer, type
* @private
*/
Address._transformScript = function(script, network) {
$.checkArgument(script instanceof Script, 'script must be a Script instance');
var info = script.getAddressInfo(network);
if (!info) {
throw new errors.Script.CantDeriveAddress(script);
}
return info;
};
/**
* Creates a P2SH address from a set of public keys and a threshold.
*
* The addresses will be sorted lexicographically, as that is the trend in bitcoin.
* To create an address from unsorted public keys, use the {@link Script#buildMultisigOut}
* interface.
*
* @param {Array} publicKeys - a set of public keys to create an address
* @param {number} threshold - the number of signatures needed to release the funds
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
* @return {Address}
*/
Address.createMultisig = function(publicKeys, threshold, network) {
network = network || publicKeys[0].network || Networks.defaultNetwork;
return Address.payingTo(Script.buildMultisigOut(publicKeys, threshold), network);
};
/**
* Internal function to transform a bitcoin address string
*
* @param {string} data
* @param {String|Network=} network - either a Network instance, 'livenet', or 'testnet'
* @param {string=} type - The type: 'pubkeyhash' or 'scripthash'
* @returns {Object} An object with keys: hashBuffer, network and type
* @private
*/
Address._transformString = function(data, network, type) {
if (typeof(data) !== 'string') {
throw new TypeError('data parameter supplied is not a string.');
}
data = data.trim();
var addressBuffer = Base58Check.decode(data);
var info = Address._transformBuffer(addressBuffer, network, type);
return info;
};
/**
* Instantiate an address from a PublicKey instance
*
* @param {PublicKey} data
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromPublicKey = function(data, network) {
var info = Address._transformPublicKey(data);
network = network || Networks.defaultNetwork;
return new Address(info.hashBuffer, network, info.type);
};
/**
* Instantiate an address from a ripemd160 public key hash
*
* @param {Buffer} hash - An instance of buffer of the hash
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromPublicKeyHash = function(hash, network) {
var info = Address._transformHash(hash);
return new Address(info.hashBuffer, network, Address.PayToPublicKeyHash);
};
/**
* Instantiate an address from a ripemd160 script hash
*
* @param {Buffer} hash - An instance of buffer of the hash
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromScriptHash = function(hash, network) {
$.checkArgument(hash, 'hash parameter is required');
var info = Address._transformHash(hash);
return new Address(info.hashBuffer, network, Address.PayToScriptHash);
};
/**
* Builds a p2sh address paying to script. This will hash the script and
* use that to create the address.
* If you want to extract an address associated with a script instead,
* see {{Address#fromScript}}
*
* @param {Script} script - An instance of Script
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.payingTo = function(script, network) {
$.checkArgument(script, 'script is required');
$.checkArgument(script instanceof Script, 'script must be instance of Script');
return Address.fromScriptHash(Hash.sha256ripemd160(script.toBuffer()), network);
};
/**
* Extract address from a Script. The script must be of one
* of the following types: p2pkh input, p2pkh output, p2sh input
* or p2sh output.
* This will analyze the script and extract address information from it.
* If you want to transform any script to a p2sh Address paying
* to that script's hash instead, use {{Address#payingTo}}
*
* @param {Script} script - An instance of Script
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromScript = function(script, network) {
$.checkArgument(script instanceof Script, 'script must be a Script instance');
var info = Address._transformScript(script, network);
return new Address(info.hashBuffer, network, info.type);
};
/**
* Instantiate an address from a buffer of the address
*
* @param {Buffer} buffer - An instance of buffer of the address
* @param {String|Network=} network - either a Network instance, 'livenet', or 'testnet'
* @param {string=} type - The type of address: 'script' or 'pubkey'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromBuffer = function(buffer, network, type) {
var info = Address._transformBuffer(buffer, network, type);
return new Address(info.hashBuffer, info.network, info.type);
};
/**
* Instantiate an address from an address string
*
* @param {string} str - An string of the bitcoin address
* @param {String|Network=} network - either a Network instance, 'livenet', or 'testnet'
* @param {string=} type - The type of address: 'script' or 'pubkey'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromString = function(str, network, type) {
var info = Address._transformString(str, network, type);
return new Address(info.hashBuffer, info.network, info.type);
};
/**
* Instantiate an address from an Object
*
* @param {string} json - An JSON string or Object with keys: hash, network and type
* @returns {Address} A new valid instance of an Address
*/
Address.fromObject = function fromObject(obj) {
$.checkState(
JSUtil.isHexa(obj.hash),
'Unexpected hash property, "' + obj.hash + '", expected to be hex.'
);
var hashBuffer = new Buffer(obj.hash, 'hex');
return new Address(hashBuffer, obj.network, obj.type);
};
/**
* Will return a validation error if exists
*
* @example
* ```javascript
* // a network mismatch error
* var error = Address.getValidationError('15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2', 'testnet');
* ```
*
* @param {string} data - The encoded data
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
* @param {string} type - The type of address: 'script' or 'pubkey'
* @returns {null|Error} The corresponding error message
*/
Address.getValidationError = function(data, network, type) {
var error;
try {
/* jshint nonew: false */
new Address(data, network, type);
} catch (e) {
error = e;
}
return error;
};
/**
* Will return a boolean if an address is