datapay
Version:
post data over bitcoin sv
1,602 lines (1,431 loc) • 2.79 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.datapay = 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){
(function (Buffer){
const mingo = require("mingo")
const _Buffer = require('buffer/')
const bitcoin = require('bsv');
const explorer = require('bitcore-explorers');
const defaults = {
rpc: "api.mattercloud.net",
fee: 400,
feeb: 1.4
}
// The end goal of 'build' is to create a hex formated transaction object
// therefore this function must end with _tx() for all cases
// and return a hex formatted string of either a tranaction or a script
var build = function(options, callback) {
let script = null;
let rpcaddr = (options.pay && options.pay.rpc) ? options.pay.rpc : defaults.rpc;
if (options.tx) {
// if tx exists, check to see if it's already been signed.
// if it's a signed transaction
// and the request is trying to override using 'data' or 'pay',
// we should throw an error
let tx = new bitcoin.Transaction(options.tx)
// transaction is already signed
if (tx.inputs.length > 0 && tx.inputs[0].script) {
if (options.pay || options.data) {
callback(new Error("the transaction is already signed and cannot be modified"))
return;
}
}
} else {
// construct script only if transaction doesn't exist
// if a 'transaction' attribute exists, the 'data' should be ignored to avoid confusion
if (options.data) {
script = _script(options)
}
}
// Instantiate pay
if (options.pay && options.pay.key) {
// key exists => create a signed transaction
let key = options.pay.key;
const privateKey = new bitcoin.PrivateKey(key);
const address = privateKey.toAddress();
const insight = new explorer.Insight(rpcaddr)
insight.getUnspentUtxos(address, function (err, res) {
if (err) {
callback(err);
return;
}
if (options.pay.filter && options.pay.filter.q && options.pay.filter.q.find) {
let f = new mingo.Query(options.pay.filter.q.find)
res = res.filter(function(item) {
return f.test(item)
})
}
let tx = new bitcoin.Transaction(options.tx).from(res);
if (script) {
tx.addOutput(new bitcoin.Transaction.Output({ script: script, satoshis: 0 }));
}
if (options.pay.to && Array.isArray(options.pay.to)) {
options.pay.to.forEach(function(receiver) {
tx.to(receiver.address, receiver.value)
})
}
tx.fee(defaults.fee).change(address);
let opt_pay = options.pay || {};
let myfee = opt_pay.fee || Math.ceil(tx._estimateSize()* (opt_pay.feeb || defaults.feeb));
tx.fee(myfee);
//Check all the outputs for dust
for(var i=0;i<tx.outputs.length;i++){
if(tx.outputs[i]._satoshis>0 && tx.outputs[i]._satoshis<546){
tx.outputs.splice(i,1);
i--;
}
}
let transaction = tx.sign(privateKey);
callback(null, transaction);
})
} else {
// key doesn't exist => create an unsigned transaction
let fee = (options.pay && options.pay.fee) ? options.pay.fee : defaults.fee;
let tx = new bitcoin.Transaction(options.tx).fee(fee);
if (script) {
tx.addOutput(new bitcoin.Transaction.Output({ script: script, satoshis: 0 }));
}
callback(null, tx)
}
}
var send = function(options, callback) {
if (!callback) {
callback = function() {};
}
build(options, function(err, tx) {
if (err) {
callback(err);
return;
}
let rpcaddr = (options.pay && options.pay.rpc) ? options.pay.rpc : defaults.rpc;
const insight = new explorer.Insight(rpcaddr)
insight.broadcast(tx.toString(), callback)
})
}
// compose script
var _script = function(options) {
var s = null;
if (options.data) {
if (Array.isArray(options.data)) {
s = new bitcoin.Script();
if (!options.hasOwnProperty("safe")) {
options.safe = true;
}
if (options.safe) {
s.add(bitcoin.Opcode.OP_FALSE);
}
// Add op_return
s.add(bitcoin.Opcode.OP_RETURN);
options.data.forEach(function(item) {
// add push data
if (item.constructor.name === 'ArrayBuffer') {
let buffer = _Buffer.Buffer.from(item)
s.add(buffer)
} else if (item.constructor.name === 'Buffer') {
s.add(item)
} else if (typeof item === 'string') {
if (/^0x/i.test(item)) {
// ex: 0x6d02
s.add(Buffer.from(item.slice(2), "hex"))
} else {
// ex: "hello"
s.add(Buffer.from(item))
}
} else if (typeof item === 'object' && item.hasOwnProperty('op')) {
s.add({ opcodenum: item.op })
}
})
} else if (typeof options.data === 'string') {
// Exported transaction
s = bitcoin.Script.fromHex(options.data);
}
}
return s;
}
var connect = function(endpoint) {
var rpc = endpoint ? endpoint : defaults.rpc;
return new explorer.Insight(rpc);
}
module.exports = {
build: build,
send: send,
bsv: bitcoin,
connect: connect,
}
}).call(this,require("buffer").Buffer)
},{"bitcore-explorers":3,"bsv":89,"buffer":218,"buffer/":82,"mingo":84}],2:[function(require,module,exports){
'use strict'
exports.byteLength = byteLength
exports.toByteArray = toByteArray
exports.fromByteArray = fromByteArray
var lookup = []
var revLookup = []
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
for (var i = 0, len = code.length; i < len; ++i) {
lookup[i] = code[i]
revLookup[code.charCodeAt(i)] = i
}
// Support decoding URL-safe base64 strings, as Node.js does.
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
revLookup['-'.charCodeAt(0)] = 62
revLookup['_'.charCodeAt(0)] = 63
function getLens (b64) {
var len = b64.length
if (len % 4 > 0) {
throw new Error('Invalid string. Length must be a multiple of 4')
}
// Trim off extra bytes after placeholder bytes are found
// See: https://github.com/beatgammit/base64-js/issues/42
var validLen = b64.indexOf('=')
if (validLen === -1) validLen = len
var placeHoldersLen = validLen === len
? 0
: 4 - (validLen % 4)
return [validLen, placeHoldersLen]
}
// base64 is 4/3 + up to two characters of the original data
function byteLength (b64) {
var lens = getLens(b64)
var validLen = lens[0]
var placeHoldersLen = lens[1]
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
}
function _byteLength (b64, validLen, placeHoldersLen) {
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
}
function toByteArray (b64) {
var tmp
var lens = getLens(b64)
var validLen = lens[0]
var placeHoldersLen = lens[1]
var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
var curByte = 0
// if there are placeholders, only get up to the last complete 4 chars
var len = placeHoldersLen > 0
? validLen - 4
: validLen
for (var i = 0; i < len; i += 4) {
tmp =
(revLookup[b64.charCodeAt(i)] << 18) |
(revLookup[b64.charCodeAt(i + 1)] << 12) |
(revLookup[b64.charCodeAt(i + 2)] << 6) |
revLookup[b64.charCodeAt(i + 3)]
arr[curByte++] = (tmp >> 16) & 0xFF
arr[curByte++] = (tmp >> 8) & 0xFF
arr[curByte++] = tmp & 0xFF
}
if (placeHoldersLen === 2) {
tmp =
(revLookup[b64.charCodeAt(i)] << 2) |
(revLookup[b64.charCodeAt(i + 1)] >> 4)
arr[curByte++] = tmp & 0xFF
}
if (placeHoldersLen === 1) {
tmp =
(revLookup[b64.charCodeAt(i)] << 10) |
(revLookup[b64.charCodeAt(i + 1)] << 4) |
(revLookup[b64.charCodeAt(i + 2)] >> 2)
arr[curByte++] = (tmp >> 8) & 0xFF
arr[curByte++] = tmp & 0xFF
}
return arr
}
function tripletToBase64 (num) {
return lookup[num >> 18 & 0x3F] +
lookup[num >> 12 & 0x3F] +
lookup[num >> 6 & 0x3F] +
lookup[num & 0x3F]
}
function encodeChunk (uint8, start, end) {
var tmp
var output = []
for (var i = start; i < end; i += 3) {
tmp =
((uint8[i] << 16) & 0xFF0000) +
((uint8[i + 1] << 8) & 0xFF00) +
(uint8[i + 2] & 0xFF)
output.push(tripletToBase64(tmp))
}
return output.join('')
}
function fromByteArray (uint8) {
var tmp
var len = uint8.length
var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
var parts = []
var maxChunkLength = 16383 // must be multiple of 3
// go through the array every three bytes, we'll deal with trailing stuff later
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
parts.push(encodeChunk(
uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)
))
}
// pad the end with zeros, but make sure to not forget the extra bytes
if (extraBytes === 1) {
tmp = uint8[len - 1]
parts.push(
lookup[tmp >> 2] +
lookup[(tmp << 4) & 0x3F] +
'=='
)
} else if (extraBytes === 2) {
tmp = (uint8[len - 2] << 8) + uint8[len - 1]
parts.push(
lookup[tmp >> 10] +
lookup[(tmp >> 4) & 0x3F] +
lookup[(tmp << 2) & 0x3F] +
'='
)
}
return parts.join('')
}
},{}],3:[function(require,module,exports){
module.exports = require('./lib');
},{"./lib":4}],4:[function(require,module,exports){
module.exports = {
models: require('./models'),
Insight: require('./insight')
};
},{"./insight":5,"./models":7}],5:[function(require,module,exports){
'use strict';
var request = require('request');
var bitcore = require('bitcore-lib');
var _ = bitcore.deps._;
var $ = bitcore.util.preconditions;
var Address = bitcore.Address;
var JSUtil = bitcore.util.js;
var Networks = bitcore.Networks;
var Transaction = bitcore.Transaction;
var UnspentOutput = Transaction.UnspentOutput;
var AddressInfo = require('./models/addressinfo');
/**
* Allows the retrieval of information regarding the state of the blockchain
* (and broadcasting of transactions) from/to a trusted Insight server.
* @param {string=} url the url of the Insight server
* @param {Network=} network whether to use livenet or testnet
* @constructor
*/
function Insight(url, network) {
if (!url && !network) {
return new Insight(Networks.defaultNetwork);
}
if (Networks.get(url)) {
network = Networks.get(url);
if (network === Networks.livenet) {
url = 'https://insight.bitpay.com';
} else {
url = 'https://test-insight.bitpay.com';
}
}
JSUtil.defineImmutable(this, {
url: url,
network: Networks.get(network) || Networks.defaultNetwork
});
this.request = request;
return this;
}
/**
* @callback Insight.GetUnspentUtxosCallback
* @param {Error} err
* @param {Array.UnspentOutput} utxos
*/
/**
* Retrieve a list of unspent outputs associated with an address or set of addresses
* @param {Address|string|Array.Address|Array.string} addresses
* @param {GetUnspentUtxosCallback} callback
*/
Insight.prototype.getUnspentUtxos = function(addresses, callback) {
$.checkArgument(_.isFunction(callback));
if (!_.isArray(addresses)) {
addresses = [addresses];
}
addresses = _.map(addresses, function(address) {
return new Address(address);
});
this.requestPost('/api/addrs/utxo', {
addrs: _.map(addresses, function(address) {
return address.toString();
}).join(',')
}, function(err, res, unspent) {
if (err || res.statusCode !== 200) {
return callback(err || res);
}
try {
unspent = _.map(unspent, UnspentOutput);
} catch (ex) {
if (ex instanceof bitcore.errors.InvalidArgument) {
return callback(ex);
}
}
return callback(null, unspent);
});
};
/**
* @callback Insight.BroadcastCallback
* @param {Error} err
* @param {string} txid
*/
/**
* Broadcast a transaction to the bitcoin network
* @param {transaction|string} transaction
* @param {BroadcastCallback} callback
*/
Insight.prototype.broadcast = function(transaction, callback) {
$.checkArgument(JSUtil.isHexa(transaction) || transaction instanceof Transaction);
$.checkArgument(_.isFunction(callback));
if (transaction instanceof Transaction) {
transaction = transaction.serialize();
}
this.requestPost('/api/tx/send', {
rawtx: transaction
}, function(err, res, body) {
if (err || res.statusCode !== 200) {
return callback(err || body);
}
return callback(null, body ? body.txid : null);
});
};
/**
* @callback Insight.AddressCallback
* @param {Error} err
* @param {AddressInfo} info
*/
/**
* Retrieve information about an address
* @param {Address|string} address
* @param {AddressCallback} callback
*/
Insight.prototype.address = function(address, callback) {
$.checkArgument(_.isFunction(callback));
address = new Address(address);
this.requestGet('/api/addr/' + address.toString(), function(err, res, body) {
if (err || res.statusCode !== 200) {
return callback(err || body);
}
var info;
try {
info = AddressInfo.fromInsight(body);
} catch (e) {
if (e instanceof SyntaxError) {
return callback(e);
}
throw e;
}
return callback(null, info);
});
};
/**
* Internal function to make a post request to the server
* @param {string} path
* @param {?} data
* @param {function} callback
* @private
*/
Insight.prototype.requestPost = function(path, data, callback) {
$.checkArgument(_.isString(path));
$.checkArgument(_.isFunction(callback));
this.request({
method: 'POST',
url: this.url + path,
json: data
}, callback);
};
/**
* Internal function to make a get request with no params to the server
* @param {string} path
* @param {function} callback
* @private
*/
Insight.prototype.requestGet = function(path, callback) {
$.checkArgument(_.isString(path));
$.checkArgument(_.isFunction(callback));
this.request({
method: 'GET',
url: this.url + path
}, callback);
};
module.exports = Insight;
},{"./models/addressinfo":6,"bitcore-lib":8,"request":81}],6:[function(require,module,exports){
'use strict';
var bitcore = require('bitcore-lib');
var _ = bitcore.deps._;
var $ = bitcore.util.preconditions;
var Address = bitcore.Address;
var JSUtil = bitcore.util.js;
function AddressInfo(param) {
if (!(this instanceof AddressInfo)) {
return new AddressInfo(param);
}
if (param instanceof AddressInfo) {
return param;
}
$.checkArgument(param.address instanceof Address);
$.checkArgument(_.isNumber(param.balance));
$.checkArgument(_.isNumber(param.totalSent));
$.checkArgument(_.isNumber(param.totalReceived));
$.checkArgument(_.isNumber(param.unconfirmedBalance));
$.checkArgument(_.isArray(param.transactionIds));
$.checkArgument(_.all(_.map(param.transactionIds, JSUtil.isHexa)));
JSUtil.defineImmutable(this, param);
}
AddressInfo.fromInsight = function(param) {
if (_.isString(param)) {
param = JSON.parse(param);
}
return new AddressInfo({
address: new Address(param.addrStr),
balance: param.balanceSat,
totalReceived: param.totalReceivedSat,
totalSent: param.totalSentSat,
unconfirmedBalance: param.unconfirmedBalanceSat,
transactionIds: param.transactions
});
};
module.exports = AddressInfo;
},{"bitcore-lib":8}],7:[function(require,module,exports){
module.exports = {
AddressInfo: require('./addressinfo')
};
},{"./addressinfo":6}],8:[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":9,"./lib/block":12,"./lib/block/blockheader":11,"./lib/block/merkleblock":13,"./lib/crypto/bn":14,"./lib/crypto/ecdsa":15,"./lib/crypto/hash":16,"./lib/crypto/point":17,"./lib/crypto/random":18,"./lib/crypto/signature":19,"./lib/encoding/base58":20,"./lib/encoding/base58check":21,"./lib/encoding/bufferreader":22,"./lib/encoding/bufferwriter":23,"./lib/encoding/varint":24,"./lib/errors":25,"./lib/hdkeycache":27,"./lib/hdprivatekey.js":28,"./lib/hdpublickey.js":29,"./lib/networks":30,"./lib/opcode":31,"./lib/privatekey":32,"./lib/publickey":33,"./lib/script":34,"./lib/transaction":37,"./lib/transaction/sighash":45,"./lib/unit":49,"./lib/uri":50,"./lib/util/buffer":51,"./lib/util/js":52,"./lib/util/preconditions":53,"./package.json":80,"bn.js":54,"bs58":55,"buffer":218,"elliptic":57,"lodash":79}],9:[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 valid
*
* @example
* ```javascript
* assert(Address.isValid('15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2', 'livenet'));
* ```
*
* @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 {boolean} The corresponding error message
*/
Address.isValid = function(data, network, type) {
return !Address.getValidationError(data, network, type);
};
/**
* Returns true if an address is of pay to public key hash type
* @return boolean
*/
Address.prototype.isPayToPublicKeyHash = function() {
return this.type === Address.PayToPublicKeyHash;
};
/**
* Returns true if an address is of pay to script hash type
* @return boolean
*/
Address.prototype.isPayToScriptHash = function() {
return this.type === Address.PayToScriptHash;
};
/**
* Will return a buffer representation of the address
*
* @returns {Buffer} Bitcoin address buffer
*/
Address.prototype.toBuffer = function() {
var version = new Buffer([this.network[this.type]]);
var buf = Buffer.concat([version, this.hashBuffer]);
return buf;
};
/**
* @returns {Object} A plain object with the address information
*/
Address.prototype.toObject = Address.prototype.toJSON = function toObject() {
return {
hash: this.hashBuffer.toString('hex'),
type: this.type,
network: this.network.toString()
};
};
/**
* Will return a the string representation of the address
*
* @returns {string} Bitcoin address
*/
Address.prototype.toString = function() {
return Base58Check.encode(this.toBuffer());
};
/**
* Will return a string formatted for the console
*
* @returns {string} Bitcoin address
*/
Address.prototype.inspect = function() {
return '<Address: ' + this.toString() + ', type: ' + this.type + ', network: ' + this.network + '>';
};
module.exports = Address;
var Script = require('./script');
}).call(this,require("buffer").Buffer)
},{"./crypto/hash":16,"./encoding/base58check":21,"./errors":25,"./networks":30,"./publickey":33,"./script":34,"./util/js":52,"./util/preconditions":53,"buffer":218,"lodash":79}],10:[function(require,module,exports){
(function (Buffer){
'use strict';
var _ = require('lodash');
var BlockHeader = require('./blockheader');
var BN = require('../crypto/bn');
var BufferUtil = require('../util/buffer');
var BufferReader = require('../encoding/bufferreader');
var BufferWriter = require('../encoding/bufferwriter');
var Hash = require('../crypto/hash');
var Transaction = require('../transaction');
var $ = require('../util/preconditions');
/**
* Instantiate a Block from a Buffer, JSON object, or Object with
* the properties of the Block
*
* @param {*} - A Buffer, JSON string, or Object
* @returns {Block}
* @constructor
*/
function Block(arg) {
if (!(this instanceof Block)) {
return new Block(arg);
}
_.extend(this, Block._from(arg));
return this;
}
// https://github.com/bitcoin/bitcoin/blob/b5fa132329f0377d787a4a21c1686609c2bfaece/src/primitives/block.h#L14
Block.MAX_BLOCK_SIZE = 1000000;
/**
* @param {*} - A Buffer, JSON string or Object
* @returns {Object} - An object representing block data
* @throws {TypeError} - If the argument was not recognized
* @private
*/
Block._from = function _from(arg) {
var info = {};
if (BufferUtil.isBuffer(arg)) {
info = Block._fromBufferReader(BufferReader(arg));
} else if (_.isObject(arg)) {
info = Block._fromObject(arg);
} else {
throw new TypeError('Unrecognized argument for Block');
}
return info;
};
/**
* @param {Object} - A plain JavaScript object
* @returns {Object} - An object representing block data
* @private
*/
Block._fromObject = function _fromObject(data) {
var transactions = [];
data.transactions.forEach(function(tx) {
if (tx instanceof Transaction) {
transactions.push(tx);
} else {
transactions.push(Transaction().fromObject(tx));
}
});
var info = {
header: BlockHeader.fromObject(data.header),
transactions: transactions
};
return info;
};
/**
* @param {Object} - A plain JavaScript object
* @returns {Block} - An instance of block
*/
Block.fromObject = function fromObject(obj) {
var info = Block._fromObject(obj);
return new Block(info);
};
/**
* @param {BufferReader} - Block data
* @returns {Object} - An object representing the block data
* @private
*/
Block._fromBufferReader = function _fromBufferReader(br) {
var info = {};
$.checkState(!br.finished(), 'No block data received');
info.header = BlockHeader.fromBufferReader(br);
var transactions = br.readVarintNum();
info.transactions = [];
for (var i = 0; i < transactions; i++) {
info.transactions.push(Transaction().fromBufferReader(br));
}
return info;
};
/**
* @param {BufferReader} - A buffer reader of the block
* @returns {Block} - An instance of block
*/
Block.fromBufferReader = function fromBufferReader(br) {
$.checkArgument(br, 'br is required');
var info = Block._fromBufferReader(br);
return new Block(info);
};
/**
* @param {Buffer} - A buffer of the block
* @returns {Block} - An instance of block
*/
Block.fromBuffer = function fromBuffer(buf) {
return Block.fromBufferReader(new BufferReader(buf));
};
/**
* @param {string} - str - A hex encoded string of the block
* @returns {Block} - A hex encoded string of the block
*/
Block.fromString = function fromString(str) {
var buf = new Buffer(str, 'hex');
return Block.fromBuffer(buf);
};
/**
* @param {Binary} - Raw block binary data or buffer
* @returns {Block} - An instance of block
*/
Block.fromRawBlock = function fromRawBlock(data) {
if (!BufferUtil.isBuffer(data)) {
data = new Buffer(data, 'binary');
}
var br = BufferReader(data);
br.pos = Block.Values.START_OF_BLOCK;
var info = Block._fromBufferReader(br);
return new Block(info);
};
/**
* @returns {Object} - A plain object with the block properties
*/
Block.prototype.toObject = Block.prototype.toJSON = function toObject() {
var transactions = [];
this.transactions.forEach(function(tx) {
transactions.push(tx.toObject());
});
return {
header: this.header.toObject(),
transactions: transactions
};
};
/**
* @returns {Buffer} - A buffer of the block
*/
Block.prototype.toBuffer = function toBuffer() {
return this.toBufferWriter().concat();
};
/**
* @returns {string} - A hex encoded string of the block
*/
Block.prototype.toString = function toString() {
return this.toBuffer().toString('hex');
};
/**
* @param {BufferWriter} - An existing instance of BufferWriter
* @returns {BufferWriter} - An instance of BufferWriter representation of the Block
*/
Block.prototype.toBufferWriter = function toBufferWriter(bw) {
if (!bw) {
bw = new BufferWriter();
}
bw.write(this.header.toBuffer());
bw.writeVarintNum(this.transactions.length);
for (var i = 0; i < this.transactions.length; i++) {
this.transactions[i].toBufferWriter(bw);
}
return bw;
};
/**
* Will iterate through each transaction and return an array of hashes
* @returns {Array} - An array with transaction hashes
*/
Block.prototype.getTransactionHashes = function getTransactionHashes() {
var hashes = [];
if (this.transactions.length === 0) {
return [Block.Values.NULL_HASH];
}
for (var t = 0; t < this.transactions.length; t++) {
hashes.push(this.transactions[t]._getHash());
}
return hashes;
};
/**
* Will build a merkle tree of all the transactions, ultimately arriving at
* a single point, the merkle root.
* @link https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees
* @returns {Array} - An array with each level of the tree after the other.
*/
Block.prototype.getMerkleTree = function getMerkleTree() {
var tree = this.getTransactionHashes();
var j = 0;
for (var size = this.transactions.length; size > 1; size = Math.floor((size + 1) / 2)) {
for (var i = 0; i < size; i += 2) {
var i2 = Math.min(i + 1, size - 1);
var buf = Buffer.concat([tree[j + i], tree[j + i2]]);
tree.push(Hash.sha256sha256(buf));
}
j += size;
}
return tree;
};
/**
* Calculates the merkleRoot from the transactions.
* @returns {Buffer} - A buffer of the merkle root hash
*/
Block.prototype.getMerkleRoot = function getMerkleRoot() {
var tree = this.getMerkleTree();
return tree[tree.length - 1];
};
/**
* Verifies that the transactions in the block match the header merkle root
* @returns {Boolean} - If the merkle roots match
*/
Block.prototype.validMerkleRoot = function validMerkleRoot() {
var h = new BN(this.header.merkleRoot.toString('hex'), 'hex');
var c = new BN(this.getMerkleRoot().toString('hex'), 'hex');
if (h.cmp(c) !== 0) {
return false;
}
return true;
};
/**
* @returns {Buffer} - The little endian hash buffer of the header
*/
Block.prototype._getHash = function() {
return this.header._getHash();
};
var idProperty = {
configurable: false,
enumerable: true,
/**
* @returns {string} - The big endian hash buffer of the header
*/
get: function() {
if (!this._id) {
this._id = this.header.id;
}
return this._id;
},
set: _.noop
};
Object.defineProperty(Block.prototype, 'id', idProperty);
Object.defineProperty(Block.prototype, 'hash', idProperty);
/**
* @returns {string} - A string formatted for the console
*/
Block.prototype.inspect = function inspect() {
return '<Block ' + this.id + '>';
};
Block.Values = {
START_OF_BLOCK: 8, // Start of block in raw block data
NULL_HASH: new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex')
};
module.exports = Block;
}).call(this,require("buffer").Buffer)
},{"../crypto/bn":14,"../crypto/hash":16,"../encoding/bufferreader":22,"../encoding/bufferwriter":23,"../transaction":37,"../util/buffer":51,"../util/preconditions":53,"./blockheader":11,"buffer":218,"lodash":79}],11:[function(require,module,exports){
(function (Buffer){
'use strict';
var _ = require('lodash');
var BN = require('../crypto/bn');
var BufferUtil = require('../util/buffer');
var BufferReader = require('../encoding/bufferreader');
var BufferWriter = require('../encoding/bufferwriter');
var Hash = require('../crypto/hash');
var JSUtil = require('../util/js');
var $ = require('../util/preconditions');
var GENESIS_BITS = 0x1d00ffff;
/**
* Instantiate a BlockHeader from a Buffer, JSON object, or Object with
* the properties of the BlockHeader
*
* @param {*} - A Buffer, JSON string, or Object
* @returns {BlockHeader} - An instance of block header
* @constructor
*/
var BlockHeader = function BlockHeader(arg) {
if (!(this instanceof BlockHeader)) {
return new BlockHeader(arg);
}
var info = BlockHeader._from(arg);
this.version = info.version;
this.prevHash = info.prevHash;
this.merkleRoot = info.merkleRoot;
this.time = info.time;
this.timestamp = info.time;
this.bits = info.bits;
this.nonce = info.nonce;
if (info.hash) {
$.checkState(
this.hash === info.hash,
'Argument object hash property does not match block hash.'
);
}
return this;
};
/**
* @param {*} - A Buffer, JSON string or Object
* @returns {Object} - An object representing block header data
* @throws {TypeError} - If the argument was not recognized
* @private
*/
BlockHeader._from = function _from(arg) {
var info = {};
if (BufferUtil.isBuffer(arg)) {
info = BlockHeader._fromBufferReader(BufferReader(arg));
} else if (_.isObject(arg)) {
info = BlockHeader._fromObject(arg);
} else {
throw new TypeError('Unrecognized argument for BlockHeader');
}
return info;
};
/**
* @param {Object} - A JSON string
* @returns {Object} - An object representing block header data
* @private
*/
BlockHeader._fromObject = function _fromObject(data) {
$.checkArgument(data, 'data is required');
var prevHash = data.prevHash;
var merkleRoot = data.merkleRoot;
if (_.isString(data.prevHash)) {
prevHash = BufferUtil.reverse(new Buffer(data.prevHash, 'hex'));
}
if (_.isString(data.merkleRoot)) {
merkleRoot = BufferUtil.reverse(new Buffer(data.merkleRoot, 'hex'));
}
var info = {
hash: data.hash,
version: data.version,
prevHash: prevHash,
merkleRoot: merkleRoot,
time: data.time,
timestamp: data.time,
bits: data.bits,
nonce: data.nonce
};
return info;
};
/**
* @param {Object} - A plain JavaScript object
* @returns {BlockHeader} - An instance of block header
*/
BlockHeader.fromObject = function fromObject(obj) {
var info = BlockHeader._fromObject(obj);
return new BlockHeader(info);
};
/**
* @param {Binary} - Raw block binary data or buffer
* @returns {BlockHeader} - An instance of block header
*/
BlockHeader.fromRawBlock = function fromRawBlock(data) {
if (!BufferUtil.isBuffer(data)) {
data = new Buffer(data, 'binary');
}
var br = BufferReader(data);
br.pos = BlockHeader.Constants.START_OF_HEADER;
var info = BlockHeader._fromBufferReader(br);
return new BlockHeader(info);
};
/**
* @param {Buffer} - A buffer of the block header
* @returns {BlockHeader} - An instance of block header
*/
BlockHeader.fromBuffer = function fromBuffer(buf) {
var info = BlockHeader._fromBufferReader(BufferReader(buf));
return new BlockHeader(info);
};
/**
* @param {string} - A hex encoded buffer of the block header
* @returns {BlockHeader} - An instance of block header
*/
BlockHeader.fromString = function fromString(str) {
var buf = new Buffer(str, 'hex');
return BlockHeader.fromBuffer(buf);
};
/**
* @param {BufferReader} - A BufferReader of the block header
* @returns {Object} - An object representing block header data
* @private
*/
BlockHeader._fromBufferReader = function _fromBufferReader(br) {
var info = {};
info.version = br.readUInt32LE();
info.prevHash = br.read(32);
info.merkleRoot = br.read(32);
info.time = br.readUInt32LE();
info.bits = br.readUInt32LE();
info.nonce = br.readUInt32LE();
return info;
};
/**
* @param {BufferReader} - A BufferReader of the block header
* @returns {BlockHeader} - An instance of block header
*/
BlockHeader.fromBufferReader = function fromBufferReader(br) {
var info = BlockHeader._fromBufferReader(br);
return new BlockHeader(info);
};
/**
* @returns {Object} - A plain object of the BlockHeader
*/
BlockHeader.prototype.toObject = BlockHeader.prototype.toJSON = function toObject() {
return {
hash: this.hash,
version: this.version,
prevHash: BufferUtil.reverse(this.prevHash).toString('hex'),
merkleRoot: BufferUtil.reverse(this.merkleRoot).toString('hex'),
time: this.time,
bits: this.bits,
nonce: this.nonce
};
};
/**
* @returns {Buffer} - A Buffer of the BlockHeader
*/
BlockHeader.prototype.toBuffer = function toBuffer() {
return this.toBufferWriter().concat();
};
/**
* @returns {string} - A hex encoded string of the BlockHeader
*/
BlockHeader.prototype.toString = function toString() {
return this.toBuffer().toString('hex');
};
/**
* @param {BufferWriter} - An existing instance BufferWriter
* @returns {BufferWriter} - An instance of BufferW