amount/utils: drop utils.btc and utils.satoshi.

This commit is contained in:
Christopher Jeffrey 2016-11-19 09:59:47 -08:00
parent 9e9b657eab
commit ae093d2242
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
19 changed files with 291 additions and 321 deletions

View File

@ -257,7 +257,7 @@ pool.open().then(function() {
wallet.on('balance', function(balance) {
console.log('Balance updated.');
console.log(bcoin.utils.btc(balance.unconfirmed));
console.log(bcoin.amount.btc(balance.unconfirmed));
});
});
```

View File

@ -7,6 +7,7 @@ var utils = require('../lib/utils/utils');
var co = require('../lib/utils/co');
var Client = require('../lib/http/client');
var Wallet = require('../lib/http/wallet');
var Amount = require('../lib/utils/amount');
var main;
function CLI() {
@ -286,10 +287,10 @@ CLI.prototype.sendTX = co(function* sendTX() {
if (this.config.script) {
output.script = this.config.script;
output.value = utils.satoshi(this.config.value || this.argv[0]);
output.value = Amount.value(this.config.value || this.argv[0]);
} else {
output.address = this.config.address || this.argv[0];
output.value = utils.satoshi(this.config.value || this.argv[1]);
output.value = Amount.value(this.config.value || this.argv[1]);
}
options = {
@ -309,10 +310,10 @@ CLI.prototype.createTX = co(function* createTX() {
if (this.config.script) {
output.script = this.config.script;
output.value = utils.satoshi(this.config.value || this.argv[0]);
output.value = Amount.value(this.config.value || this.argv[0]);
} else {
output.address = this.config.address || this.argv[0];
output.value = utils.satoshi(this.config.value || this.argv[1]);
output.value = Amount.value(this.config.value || this.argv[1]);
}
options = {

View File

@ -82,7 +82,7 @@ send.onsubmit = function(ev) {
options = {
outputs: [{
address: address,
value: utils.satoshi(value)
value: bcoin.amount.value(value)
}]
};
@ -148,7 +148,7 @@ function addItem(tx) {
chainState.innerHTML = ''
+ 'tx=' + node.chain.db.state.tx
+ ' coin=' + node.chain.db.state.coin
+ ' value=' + utils.btc(node.chain.db.state.value);
+ ' value=' + bcoin.amount.btc(node.chain.db.state.value);
}
function setMouseup(el, obj) {
@ -182,11 +182,11 @@ function formatWallet(wallet) {
wallet.getBalance().then(function(balance) {
html += 'Confirmed Balance: <b>'
+ utils.btc(balance.confirmed)
+ bcoin.amount.btc(balance.confirmed)
+ '</b><br>';
html += 'Unconfirmed Balance: <b>'
+ utils.btc(balance.unconfirmed)
+ bcoin.amount.btc(balance.unconfirmed)
+ '</b><br>';
return wallet.getHistory();

View File

@ -13,6 +13,7 @@ var utils = require('../utils/utils');
var assert = require('assert');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var Amount = require('../utils/amount');
var encoding = require('../utils/encoding');
var co = require('../utils/co');
var Network = require('../protocol/network');
@ -145,7 +146,7 @@ ChainDB.prototype._open = co(function* open() {
this.state.rhash,
this.state.tx,
this.state.coin,
utils.btc(this.state.value));
Amount.btc(this.state.value));
});
/**

View File

@ -10,6 +10,7 @@
var Network = require('../protocol/network');
var AsyncObject = require('../utils/async');
var RPCClient = require('./rpcclient');
var Amount = require('../utils/amount');
var utils = require('../utils/utils');
var co = require('../utils/co');
var request = require('./request').promise;
@ -620,11 +621,11 @@ HTTPClient.prototype.send = function send(id, options) {
options.outputs = options.outputs || [];
if (options.rate)
options.rate = utils.btc(options.rate);
options.rate = Amount.btc(options.rate);
options.outputs = options.outputs.map(function(output) {
return {
value: utils.btc(output.value),
value: Amount.btc(output.value),
address: output.address,
script: toHex(output.script)
};
@ -668,11 +669,11 @@ HTTPClient.prototype.createTX = function createTX(id, options) {
options = utils.merge({}, options);
if (options.rate)
options.rate = utils.btc(options.rate);
options.rate = Amount.btc(options.rate);
options.outputs = options.outputs.map(function(output) {
return {
value: utils.btc(output.value),
value: Amount.btc(output.value),
address: output.address,
script: toHex(output.script)
};

View File

@ -13,6 +13,7 @@ var assert = require('assert');
var constants = require('../protocol/constants');
var ec = require('../crypto/ec');
var time = require('../net/time');
var Amount = require('../utils/amount');
var NetworkAddress = require('../primitives/netaddress');
var Script = require('../script/script');
var Address = require('../primitives/address');
@ -322,7 +323,7 @@ RPC.prototype.getinfo = co(function* getinfo(args) {
version: constants.USER_VERSION,
protocolversion: constants.VERSION,
walletversion: 0,
balance: +utils.btc(balance.unconfirmed),
balance: Amount.btc(balance.unconfirmed, true),
blocks: this.chain.height,
timeoffset: time.offset,
connections: this.pool.peers.all.length,
@ -332,8 +333,8 @@ RPC.prototype.getinfo = co(function* getinfo(args) {
keypoololdest: 0,
keypoolsize: 0,
unlocked_until: this.wallet.master.until,
paytxfee: +utils.btc(this.network.feeRate),
relayfee: +utils.btc(this.network.minRelay),
paytxfee: Amount.btc(this.network.feeRate, true),
relayfee: Amount.btc(this.network.minRelay, true),
errors: ''
};
});
@ -379,7 +380,7 @@ RPC.prototype.getnetworkinfo = function getnetworkinfo(args) {
timeoffset: time.offset,
connections: this.pool.peers.all.length,
networks: [],
relayfee: +utils.btc(this.network.getMinRelay()),
relayfee: Amount.btc(this.network.getMinRelay(), true),
localaddresses: [],
warnings: ''
});
@ -794,7 +795,7 @@ RPC.prototype._txToJSON = function _txToJSON(tx) {
}),
vout: tx.outputs.map(function(output, i) {
return {
value: +utils.btc(output.value),
value: Amount.btc(output.value, true),
n: i,
scriptPubKey: self._scriptToJSON(output.script, true)
};
@ -984,7 +985,7 @@ RPC.prototype.getmempoolinfo = function getmempoolinfo(args) {
bytes: this.mempool.getSize(),
usage: this.mempool.getSize(),
maxmempool: constants.mempool.MAX_MEMPOOL_SIZE,
mempoolminfee: +utils.btc(this.mempool.minRelay)
mempoolminfee: Amount.btc(this.mempool.minRelay, true)
});
};
@ -1123,18 +1124,18 @@ RPC.prototype._entryToJSON = function _entryToJSON(entry) {
var tx = entry.tx;
return {
size: entry.size,
fee: +utils.btc(entry.fee),
modifiedfee: +utils.btc(entry.fees),
fee: Amount.btc(entry.fee, true),
modifiedfee: Amount.btc(entry.fees, true),
time: entry.ts,
height: entry.height,
startingpriority: entry.priority,
currentpriority: entry.getPriority(this.chain.height),
descendantcount: this.mempool.countDescendants(tx),
descendantsize: entry.sizes,
descendantfees: +utils.btc(entry.fees),
descendantfees: Amount.btc(entry.fees, true),
ancestorcount: this.mempool.countAncestors(tx),
ancestorsize: entry.sizes,
ancestorfees: +utils.btc(entry.fees),
ancestorfees: Amount.btc(entry.fees, true),
depends: this.mempool.getDepends(tx).map(utils.revHex)
};
};
@ -1172,7 +1173,7 @@ RPC.prototype.gettxout = co(function* gettxout(args) {
return {
bestblock: this.chain.tip.rhash,
confirmations: coin.getConfirmations(this.chain.height),
value: +utils.btc(coin.value),
value: Amount.btc(coin.value, true),
scriptPubKey: this._scriptToJSON(coin.script, true),
version: coin.version,
coinbase: coin.coinbase
@ -1283,7 +1284,7 @@ RPC.prototype.gettxoutsetinfo = function gettxoutsetinfo(args) {
txouts: this.chain.db.state.coin,
bytes_serialized: 0,
hash_serialized: 0,
total_amount: +utils.btc(this.chain.db.state.value)
total_amount: Amount.btc(this.chain.db.state.value, true)
});
};
@ -2333,7 +2334,7 @@ RPC.prototype.fundrawtransaction = co(function* fundrawtransaction(args) {
return {
hex: tx.toRaw().toString('hex'),
changepos: tx.changeIndex,
fee: +utils.btc(tx.getFee())
fee: Amount.btc(tx.getFee(), true)
};
});
@ -2545,7 +2546,7 @@ RPC.prototype.estimatefee = function estimatefee(args) {
if (fee === 0)
fee = -1;
else
fee = +utils.btc(fee);
fee = Amount.btc(fee, true);
return Promise.resolve(fee);
};
@ -2588,7 +2589,7 @@ RPC.prototype.estimatesmartfee = function estimatesmartfee(args) {
if (fee === 0)
fee = -1;
else
fee = +utils.btc(fee);
fee = Amount.btc(fee, true);
return Promise.resolve({
fee: fee,
@ -2901,7 +2902,7 @@ RPC.prototype.getbalance = co(function* getbalance(args) {
else
value = balance.unconfirmed;
return +utils.btc(value);
return Amount.btc(value, true);
});
RPC.prototype.getnewaddress = co(function* getnewaddress(args) {
@ -2982,7 +2983,7 @@ RPC.prototype.getreceivedbyaccount = co(function* getreceivedbyaccount(args) {
}
}
return +utils.btc(total);
return Amount.btc(total, true);
});
RPC.prototype.getreceivedbyaddress = co(function* getreceivedbyaddress(args) {
@ -3019,7 +3020,7 @@ RPC.prototype.getreceivedbyaddress = co(function* getreceivedbyaddress(args) {
}
}
return +utils.btc(total);
return Amount.btc(total, true);
});
RPC.prototype._toWalletTX = co(function* _toWalletTX(tx) {
@ -3054,7 +3055,7 @@ RPC.prototype._toWalletTX = co(function* _toWalletTX(tx) {
account: member.path.name,
address: member.address.toBase58(this.network),
category: 'receive',
amount: +utils.btc(member.value),
amount: Amount.btc(member.value, true),
label: member.path.name,
vout: i
});
@ -3073,8 +3074,8 @@ RPC.prototype._toWalletTX = co(function* _toWalletTX(tx) {
? member.address.toBase58(this.network)
: null,
category: 'send',
amount: -(+utils.btc(member.value)),
fee: -(+utils.btc(details.fee)),
amount: -(Amount.btc(member.value, true)),
fee: -(Amount.btc(details.fee, true)),
vout: i
});
@ -3082,7 +3083,7 @@ RPC.prototype._toWalletTX = co(function* _toWalletTX(tx) {
}
json = {
amount: +utils.btc(receive ? received : -sent),
amount: Amount.btc(receive ? received : -sent, true),
confirmations: details.confirmations,
blockhash: details.block ? utils.revHex(details.block) : null,
blockindex: details.index,
@ -3145,7 +3146,7 @@ RPC.prototype.getunconfirmedbalance = co(function* getunconfirmedbalance(args) {
balance = yield this.wallet.getBalance();
return +utils.btc(balance.unconfirmed);
return Amount.btc(balance.unconfirmed, true);
});
RPC.prototype.getwalletinfo = co(function* getwalletinfo(args) {
@ -3159,15 +3160,15 @@ RPC.prototype.getwalletinfo = co(function* getwalletinfo(args) {
return {
walletid: this.wallet.id,
walletversion: 6,
balance: +utils.btc(balance.unconfirmed),
unconfirmed_balance: +utils.btc(balance.unconfirmed),
balance: Amount.btc(balance.unconfirmed, true),
unconfirmed_balance: Amount.btc(balance.unconfirmed, true),
txcount: this.wallet.state.tx,
keypoololdest: 0,
keypoolsize: 0,
unlocked_until: this.wallet.master.until,
paytxfee: this.feeRate != null
? +utils.btc(this.feeRate)
: +utils.btc(0)
? Amount.btc(this.feeRate, true)
: 0
};
});
@ -3312,7 +3313,7 @@ RPC.prototype.listaccounts = co(function* listaccounts(args) {
for (i = 0; i < accounts.length; i++) {
account = accounts[i];
balance = yield this.wallet.getBalance(account);
map[account] = +utils.btc(balance.unconfirmed);
map[account] = Amount.btc(balance.unconfirmed, true);
}
return map;
@ -3465,7 +3466,7 @@ RPC.prototype._listReceived = co(function* _listReceived(minconf, empty, account
continue;
if (entry.confirmations === -1)
entry.confirmations = 0;
entry.amount = +utils.btc(entry.amount);
entry.amount = Amount.btc(entry.amount, true);
result.push(entry);
}
@ -3587,7 +3588,7 @@ RPC.prototype._toListTX = co(function* _toListTX(tx) {
? member.address.toBase58(this.network)
: null,
category: receive ? 'receive' : 'send',
amount: +utils.btc(receive ? received : -sent),
amount: Amount.btc(receive ? received : -sent, true),
label: member.path ? member.path.name : undefined,
vout: index,
confirmations: details.confirmations,
@ -3714,7 +3715,7 @@ RPC.prototype.listunspent = co(function* listunspent(args) {
? ring.script.toJSON()
: undefined,
scriptPubKey: coin.script.toJSON(),
amount: +utils.btc(coin.value),
amount: Amount.btc(coin.value, true),
confirmations: depth,
spendable: !this.wallet.isLocked(coin),
solvable: true
@ -4179,7 +4180,7 @@ function isHash(obj) {
function toSatoshi(obj) {
if (typeof obj !== 'number')
throw new RPCError('Bad BTC amount.');
return utils.satoshi(obj + '');
return Amount.value(obj, true);
}
function reverseEndian(data) {

View File

@ -17,6 +17,7 @@ var HTTPBase = require('./base');
var utils = require('../utils/utils');
var co = require('../utils/co');
var base58 = require('../utils/base58');
var Amount = require('../utils/amount');
var Address = require('../primitives/address');
var Bloom = require('../utils/bloom');
var TX = require('../primitives/tx');
@ -304,16 +305,16 @@ HTTPServer.prototype._init = function _init() {
}
if (params.fee)
options.fee = utils.satoshi(params.fee);
options.fee = Amount.value(params.fee);
if (params.hardFee)
options.hardFee = utils.satoshi(params.hardFee);
options.hardFee = Amount.value(params.hardFee);
if (params.maxFee)
options.maxFee = utils.satoshi(params.maxFee);
options.maxFee = Amount.value(params.maxFee);
if (params.rate)
options.rate = utils.satoshi(params.rate);
options.rate = Amount.value(params.rate);
if (params.m != null) {
options.m = Number(params.m);
@ -382,7 +383,7 @@ HTTPServer.prototype._init = function _init() {
script: output.script
? Script.fromRaw(output.script, 'hex')
: null,
value: utils.satoshi(output.value)
value: Amount.value(output.value)
});
}
}
@ -732,11 +733,11 @@ HTTPServer.prototype._init = function _init() {
var fee;
if (!this.fees)
return send(200, { rate: utils.btc(this.network.feeRate) });
return send(200, { rate: Amount.btc(this.network.feeRate) });
fee = this.fees.estimateFee(req.options.blocks);
send(200, { rate: utils.btc(fee) });
send(200, { rate: Amount.btc(fee) });
});
// Reset chain
@ -1358,12 +1359,12 @@ HTTPServer.prototype._initIO = function _initIO() {
if (!self.fees) {
rate = self.network.feeRate;
rate = utils.btc(rate);
rate = Amount.btc(rate);
return callback(null, rate);
}
rate = self.fees.estimateFee(blocks);
rate = utils.btc(rate);
rate = Amount.btc(rate);
return callback(null, rate);
});

View File

@ -7,10 +7,11 @@
'use strict';
var assert = require('assert');
var utils = require('../utils/utils');
var constants = require('../protocol/constants');
var Network = require('../protocol/network');
var assert = require('assert');
var Amount = require('../utils/amount');
var Output = require('./output');
var Script = require('../script/script');
var Network = require('../protocol/network');
@ -122,7 +123,7 @@ Coin.prototype.inspect = function inspect() {
type: this.getType(),
version: this.version,
height: this.height,
value: utils.btc(this.value),
value: Amount.btc(this.value),
script: this.script,
coinbase: this.coinbase,
hash: this.hash ? utils.revHex(this.hash) : null,
@ -150,7 +151,7 @@ Coin.prototype.toJSON = function toJSON(network) {
return {
version: this.version,
height: this.height,
value: utils.btc(this.value),
value: Amount.btc(this.value),
script: this.script.toJSON(),
address: address,
coinbase: this.coinbase,
@ -186,7 +187,7 @@ Coin.prototype.fromJSON = function fromJSON(json) {
this.version = json.version;
this.height = json.height;
this.value = utils.satoshi(json.value);
this.value = Amount.value(json.value);
this.script.fromJSON(json.script);
this.coinbase = json.coinbase;
this.hash = json.hash ? utils.revHex(json.hash) : null;

View File

@ -175,8 +175,8 @@ MTX.prototype.addInput = function addInput(options, index) {
* Add an output.
* @example
* tx.addOutput({ address: ..., value: 100000 });
* tx.addOutput({ address: ..., value: utils.satoshi('0.1') });
* tx.addOutput(receivingWallet, utils.satoshi('0.1'));
* tx.addOutput({ address: ..., value: Amount.value('0.1') });
* tx.addOutput(receivingWallet, Amount.value('0.1'));
* @param {Wallet|KeyRing|Object} obj - Wallet, Address,
* or options (see {@link Script.createOutputScript} for options).
* @param {Amount?} value - Only needs to be present for non-options.

View File

@ -9,6 +9,7 @@
var utils = require('../utils/utils');
var constants = require('../protocol/constants');
var Amount = require('../utils/amount');
var Network = require('../protocol/network');
var Script = require('../script/script');
var BufferWriter = require('../utils/writer');
@ -117,7 +118,7 @@ Output.prototype.getHash = function getHash(enc) {
Output.prototype.inspect = function inspect() {
return {
type: this.getType(),
value: utils.btc(this.value),
value: Amount.btc(this.value),
script: this.script,
address: this.getAddress()
};
@ -138,7 +139,7 @@ Output.prototype.toJSON = function toJSON(network) {
address = address.toBase58(network);
return {
value: utils.btc(this.value),
value: Amount.btc(this.value),
script: this.script.toJSON(),
address: address
};
@ -205,7 +206,7 @@ Output.prototype.isDust = function isDust(rate) {
Output.prototype.fromJSON = function fromJSON(json) {
assert(typeof json.value === 'string');
this.value = utils.satoshi(json.value);
this.value = Amount.value(json.value);
this.script.fromJSON(json.script);
return this;
};

View File

@ -11,6 +11,7 @@ var assert = require('assert');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var btcutils = require('../utils/btcutils');
var Amount = require('../utils/amount');
var constants = require('../protocol/constants');
var Network = require('../protocol/network');
var Script = require('../script/script');
@ -2041,10 +2042,10 @@ TX.prototype.inspect = function inspect() {
size: this.getSize(),
virtualSize: this.maxSize(),
height: this.height,
value: utils.btc(this.getOutputValue()),
fee: utils.btc(this.getFee()),
minFee: utils.btc(this.getMinFee()),
rate: utils.btc(rate),
value: Amount.btc(this.getOutputValue()),
fee: Amount.btc(this.getFee()),
minFee: Amount.btc(this.getMinFee()),
rate: Amount.btc(rate),
date: utils.date(this.ts || this.ps),
block: this.block ? utils.revHex(this.block) : null,
ts: this.ts,
@ -2084,8 +2085,8 @@ TX.prototype.toJSON = function toJSON(network) {
ps: this.ps,
date: utils.date(this.ts || this.ps),
index: this.index,
fee: utils.btc(this.getFee()),
rate: utils.btc(rate),
fee: Amount.btc(this.getFee()),
rate: Amount.btc(rate),
version: this.version,
flag: this.flag,
inputs: this.inputs.map(function(input) {

View File

@ -1,5 +1,19 @@
/*!
* amount.js - amount object for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var utils = require('./utils');
/**
* Amount
* @constructor
*/
function Amount(value, unit, num) {
if (!(this instanceof Amount))
return new Amount(value, unit, num);
@ -47,6 +61,7 @@ Amount.prototype.to = function to(unit, num) {
switch (unit) {
case 'sat':
return this.toSatoshis(num);
case 'ubtc':
case 'bits':
return this.toBits(num);
case 'mbtc':
@ -91,6 +106,7 @@ Amount.prototype.from = function from(unit, value, num) {
switch (unit) {
case 'sat':
return this.fromSatoshis(value, num);
case 'ubtc':
case 'bits':
return this.fromBits(value, num);
case 'mbtc':
@ -101,7 +117,7 @@ Amount.prototype.from = function from(unit, value, num) {
throw new Error('Unknown unit "' + unit + '".');
};
Amount.fromOptions = function fromOptions(value) {
Amount.fromOptions = function fromOptions(value, unit, num) {
return new Amount().fromOptions(value);
};
@ -141,19 +157,21 @@ Amount.prototype.inspect = function inspect() {
* @returns {String} BTC string.
*/
Amount.btc = function btc(value) {
Amount.btc = function btc(value, num) {
if (utils.isFloat(value))
return value;
return Amount.serialize(value, 8, false);
return Amount.serialize(value, 8, num);
};
/**
* Safely convert satoshis to a BTC string.
* This function explicitly avoids any
* floating point arithmetic.
* @param {Amount} value - Satoshis.
* @returns {String} BTC string.
* @param {Amount} value
* @param {Number} dec - Number of decimals.
* @param {Boolean} num - Return a number.
* @returns {String}
*/
Amount.serialize = function serialize(value, dec, num) {
@ -167,11 +185,9 @@ Amount.serialize = function serialize(value, dec, num) {
negative = true;
}
assert(value <= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1.');
value = value.toString(10);
assert(value.length <= 8 + dec, 'Number exceeds 2^53-1.');
assert(value.length <= 16, 'Number exceeds 2^53-1.');
while (value.length < dec + 1)
value = '0' + value;
@ -195,22 +211,44 @@ Amount.serialize = function serialize(value, dec, num) {
return result;
};
/**
* Unsafely convert satoshis to a BTC string.
* @param {Amount} value
* @param {Number} dec - Number of decimals.
* @param {Boolean} num - Return a number.
* @returns {String}
*/
Amount.serializeUnsafe = function serializeUnsafe(value, dec, num) {
assert(utils.isInt(value), 'Non-satoshi value for conversion.');
value /= pow10(dec);
value = value.toFixed(dec);
if (num)
return +value;
if (dec !== 0) {
value = value.replace(/0+$/, '');
if (value[value.length - 1] === '.')
value += '0';
}
return value;
};
/**
* Safely convert a BTC string to satoshis.
* This function explicitly avoids any
* floating point arithmetic. It also does
* extra validation to ensure the resulting
* Number will be 53 bits or less.
* @param {String} value - BTC
* @returns {Amount} Satoshis.
* @throws on parse error
*/
Amount.satoshi = function satoshi(value) {
Amount.value = function value(value, num) {
if (utils.isInt(value))
return value;
return Amount.parse(value, 8, false);
return Amount.parse(value, 8, num);
};
/**
@ -220,15 +258,17 @@ Amount.satoshi = function satoshi(value) {
* extra validation to ensure the resulting
* Number will be 53 bits or less.
* @param {String} value - BTC
* @param {Number} dec - Number of decimals.
* @param {Boolean} num - Allow numbers.
* @returns {Amount} Satoshis.
* @throws on parse error
*/
Amount.parse = function parse(value, dec, num) {
var negative = false;
var mult = Math.pow(10, dec);
var maxLo = utils.MAX_SAFE_INTEGER % mult;
var maxHi = (utils.MAX_SAFE_INTEGER - maxLo) / mult;
var mult = pow10(dec);
var maxLo = modSafe(mult);
var maxHi = divSafe(mult);
var parts, hi, lo, result;
if (num && typeof value === 'number') {
@ -276,6 +316,110 @@ Amount.parse = function parse(value, dec, num) {
return result;
};
/**
* Unsafely convert a BTC string to satoshis.
* @param {String} value - BTC
* @param {Number} dec - Number of decimals.
* @param {Boolean} num - Allow numbers.
* @returns {Amount} Satoshis.
* @throws on parse error
*/
Amount.parseUnsafe = function parseUnsafe(value, dec, num) {
if (typeof value === 'string') {
assert(utils.isFloat(value), 'Non-BTC value for conversion.');
value = parseFloat(value, 10);
} else {
assert(utils.isNumber(value), 'Non-BTC value for conversion.');
assert(num, 'Cannot parse number.');
}
value *= pow10(dec);
assert(value % 1 === 0, 'Too many decimal places.');
return value;
};
/*
* Helpers
*/
function pow10(exp) {
switch (exp) {
case 0:
return 1;
case 1:
return 10;
case 2:
return 100;
case 3:
return 1000;
case 4:
return 10000;
case 5:
return 100000;
case 6:
return 1000000;
case 7:
return 10000000;
case 8:
return 100000000;
default:
assert(false);
}
}
function modSafe(mod) {
switch (mod) {
case 1:
return 0;
case 10:
return 1;
case 100:
return 91;
case 1000:
return 991;
case 10000:
return 991;
case 100000:
return 40991;
case 1000000:
return 740991;
case 10000000:
return 4740991;
case 100000000:
return 54740991;
default:
assert(false);
}
}
function divSafe(div) {
switch (div) {
case 1:
return 9007199254740991;
case 10:
return 900719925474099;
case 100:
return 90071992547409;
case 1000:
return 9007199254740;
case 10000:
return 900719925474;
case 100000:
return 90071992547;
case 1000000:
return 9007199254;
case 10000000:
return 900719925;
case 100000000:
return 90071992;
default:
assert(false);
}
}
/*
* Expose
*/

View File

@ -11,6 +11,7 @@ var assert = require('assert');
var BN = require('bn.js');
var constants = require('../protocol/constants');
var utils = require('./utils');
var Amount = require('./amount');
var btcutils = exports;
/**
@ -194,42 +195,9 @@ btcutils.getRate = function getRate(size, fee) {
*/
btcutils.btc = function btc(value) {
var negative = false;
var hi, lo, result;
if (utils.isFloat(value))
return value;
assert(utils.isInt(value), 'Non-satoshi value for conversion.');
if (value < 0) {
value = -value;
negative = true;
}
assert(value <= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1.');
value = value.toString(10);
assert(value.length <= 16, 'Number exceeds 2^53-1.');
while (value.length < 9)
value = '0' + value;
hi = value.slice(0, -8);
lo = value.slice(-8);
lo = lo.replace(/0+$/, '');
if (lo.length === 0)
lo += '0';
result = hi + '.' + lo;
if (negative)
result = '-' + result;
return result;
return Amount.fromValue(value).toBTC();
};
/**
@ -244,50 +212,9 @@ btcutils.btc = function btc(value) {
*/
btcutils.satoshi = function satoshi(value) {
var negative = false;
var parts, hi, lo, result;
if (utils.isInt(value))
return value;
assert(utils.isFloat(value), 'Non-BTC value for conversion.');
if (value[0] === '-') {
negative = true;
value = value.substring(1);
}
parts = value.split('.');
assert(parts.length <= 2, 'Bad decimal point.');
hi = parts[0] || '0';
lo = parts[1] || '0';
hi = hi.replace(/^0+/, '');
lo = lo.replace(/0+$/, '');
assert(hi.length <= 8, 'Number exceeds 2^53-1.');
assert(lo.length <= 8, 'Too many decimal places.');
if (hi.length === 0)
hi = '0';
while (lo.length < 8)
lo += '0';
hi = parseInt(hi, 10);
lo = parseInt(lo, 10);
assert(hi < 90071992 || (hi === 90071992 && lo <= 54740991),
'Number exceeds 2^53-1.');
result = hi * 100000000 + lo;
if (negative)
result = -result;
return result;
return Amount.fromBTC(value).toValue();
};
/**
@ -297,11 +224,8 @@ btcutils.satoshi = function satoshi(value) {
*/
btcutils.isSatoshi = function isSatoshi(value) {
if (typeof value !== 'number')
return false;
try {
utils.satoshi(value);
Amount.fromValue(value);
return true;
} catch (e) {
return false;
@ -315,11 +239,8 @@ btcutils.isSatoshi = function isSatoshi(value) {
*/
btcutils.isBTC = function isBTC(value) {
if (typeof value !== 'string')
return false;
try {
utils.btc(value);
Amount.fromBTC(value);
return true;
} catch (e) {
return false;

View File

@ -9,6 +9,7 @@
var utils = require('../utils/utils');
var constants = require('../protocol/constants');
var Amount = require('./amount');
/**
* An error thrown during verification. Can be either
@ -140,8 +141,8 @@ function FundingError(msg, available, required) {
if (Error.captureStackTrace)
Error.captureStackTrace(this, FundingError);
msg += ' (available=' + utils.btc(available) + ',';
msg += ' required=' + utils.btc(required) + ')';
msg += ' (available=' + Amount.btc(available) + ',';
msg += ' required=' + Amount.btc(required) + ')';
this.type = 'FundingError';
this.message = msg;

View File

@ -6,8 +6,9 @@
'use strict';
var utils = require('../utils/utils');
var utils = require('./utils');
var Address = require('../primitives/address');
var Amount = require('./amount');
var assert = require('assert');
function URI(options) {
@ -88,7 +89,7 @@ URI.prototype.fromString = function fromString(str) {
query = parsePairs(query);
if (query.amount)
this.amount = utils.satoshi(query.amount);
this.amount = Amount.value(query.amount);
if (query.label)
this.label = query.label;
@ -113,7 +114,7 @@ URI.prototype.toString = function toString() {
str += this.address.toBase58();
if (this.amount !== -1)
query.push('amount=' + utils.btc(this.amount));
query.push('amount=' + Amount.btc(this.amount));
if (this.label)
query.push('label=' + escape(this.label));

View File

@ -9,20 +9,13 @@
/* global gc */
/**
* @exports utils
*/
var utils = exports;
var assert = require('assert');
var util = require('util');
var fs = require('fs');
var os = require('os');
var BN = require('bn.js');
var base58 = require('./base58');
var utils = exports;
var Number, Math, Date;
var lazy;
/**
* Reference to the global object.
@ -47,6 +40,10 @@ utils.global = (function() {
assert(false, 'No global defined.');
})();
/*
* Globals
*/
Number = utils.global.Number;
Math = utils.global.Math;
Date = utils.global.Date;
@ -264,111 +261,6 @@ utils.merge = function merge(target) {
if (Object.assign)
utils.merge = Object.assign;
/**
* Safely convert satoshis to a BTC string.
* This function explicitly avoids any
* floating point arithmetic.
* @param {Amount} value - Satoshis.
* @returns {String} BTC string.
*/
utils.btc = function btc(value) {
var negative = false;
var hi, lo, result;
if (utils.isFloat(value))
return value;
assert(utils.isInt(value), 'Non-satoshi value for conversion.');
if (value < 0) {
value = -value;
negative = true;
}
assert(value <= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1.');
value = value.toString(10);
assert(value.length <= 16, 'Number exceeds 2^53-1.');
while (value.length < 9)
value = '0' + value;
hi = value.slice(0, -8);
lo = value.slice(-8);
lo = lo.replace(/0+$/, '');
if (lo.length === 0)
lo += '0';
result = hi + '.' + lo;
if (negative)
result = '-' + result;
return result;
};
/**
* Safely convert a BTC string to satoshis.
* This function explicitly avoids any
* floating point arithmetic. It also does
* extra validation to ensure the resulting
* Number will be 53 bits or less.
* @param {String} value - BTC
* @returns {Amount} Satoshis.
* @throws on parse error
*/
utils.satoshi = function satoshi(value) {
var negative = false;
var parts, hi, lo, result;
if (utils.isInt(value))
return value;
assert(utils.isFloat(value), 'Non-BTC value for conversion.');
if (value[0] === '-') {
negative = true;
value = value.substring(1);
}
parts = value.split('.');
assert(parts.length <= 2, 'Bad decimal point.');
hi = parts[0] || '0';
lo = parts[1] || '0';
hi = hi.replace(/^0+/, '');
lo = lo.replace(/0+$/, '');
assert(hi.length <= 8, 'Number exceeds 2^53-1.');
assert(lo.length <= 8, 'Too many decimal places.');
if (hi.length === 0)
hi = '0';
while (lo.length < 8)
lo += '0';
hi = parseInt(hi, 10);
lo = parseInt(lo, 10);
assert(hi < 90071992 || (hi === 90071992 && lo <= 54740991),
'Number exceeds 2^53-1.');
result = hi * 100000000 + lo;
if (negative)
result = -result;
return result;
};
/**
* Max safe integer (53 bits).
* @const {Number}

View File

@ -15,6 +15,7 @@ var constants = require('../protocol/constants');
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');
var btcutils = require('../utils/btcutils');
var Amount = require('../utils/amount');
var TX = require('../primitives/tx');
var Coin = require('../primitives/coin');
var Outpoint = require('../primitives/outpoint');
@ -81,8 +82,8 @@ TXDB.prototype.open = co(function* open() {
this.logger.info(
'Balance: unconfirmed=%s confirmed=%s.',
utils.btc(this.state.unconfirmed),
utils.btc(this.state.confirmed));
Amount.btc(this.state.unconfirmed),
Amount.btc(this.state.confirmed));
});
/**
@ -2808,8 +2809,8 @@ Balance.prototype.toJSON = function toJSON(minimal) {
wid: !minimal ? this.wid : undefined,
id: !minimal ? this.id : undefined,
account: !minimal ? this.account : undefined,
unconfirmed: utils.btc(this.unconfirmed),
confirmed: utils.btc(this.confirmed)
unconfirmed: Amount.btc(this.unconfirmed),
confirmed: Amount.btc(this.confirmed)
};
};
@ -2820,8 +2821,8 @@ Balance.prototype.toJSON = function toJSON(minimal) {
Balance.prototype.toString = function toString() {
return '<Balance'
+ ' unconfirmed=' + utils.btc(this.unconfirmed)
+ ' confirmed=' + utils.btc(this.confirmed)
+ ' unconfirmed=' + Amount.btc(this.unconfirmed)
+ ' confirmed=' + Amount.btc(this.confirmed)
+ '>';
};
@ -2944,8 +2945,8 @@ TXDBState.prototype.toJSON = function toJSON(minimal) {
id: !minimal ? this.id : undefined,
tx: this.tx,
coin: this.coin,
unconfirmed: utils.btc(this.unconfirmed),
confirmed: utils.btc(this.confirmed)
unconfirmed: Amount.btc(this.unconfirmed),
confirmed: Amount.btc(this.confirmed)
};
};
@ -3221,8 +3222,8 @@ Details.prototype.toJSON = function toJSON() {
index: this.index,
size: this.size,
virtualSize: this.vsize,
fee: utils.btc(fee),
rate: utils.btc(rate),
fee: Amount.btc(fee),
rate: Amount.btc(rate),
confirmations: this.getConfirmations(),
inputs: this.inputs.map(function(input) {
return input.toJSON(self.network);
@ -3259,7 +3260,7 @@ function DetailsMember() {
DetailsMember.prototype.toJSON = function toJSON(network) {
return {
value: utils.btc(this.value),
value: Amount.btc(this.value),
address: this.address
? this.address.toBase58(network)
: null,

View File

@ -9,6 +9,7 @@ var crypto = require('../lib/crypto/crypto');
var assert = require('assert');
var scriptTypes = constants.scriptTypes;
var co = require('../lib/utils/co');
var Amount = require('../lib/utils/amount');
var cob = co.cob;
var dummyInput = {
@ -108,16 +109,16 @@ describe('HTTP', function() {
assert.equal(receive.type, 'pubkeyhash');
assert.equal(receive.branch, 0);
assert(balance);
assert.equal(utils.satoshi(balance.confirmed), 0);
assert.equal(utils.satoshi(balance.unconfirmed), 201840);
assert.equal(Amount.value(balance.confirmed), 0);
assert.equal(Amount.value(balance.unconfirmed), 201840);
assert(details);
assert.equal(details.hash, t1.rhash);
}));
it('should get balance', cob(function* () {
var balance = yield wallet.getBalance();
assert.equal(utils.satoshi(balance.confirmed), 0);
assert.equal(utils.satoshi(balance.unconfirmed), 201840);
assert.equal(Amount.value(balance.confirmed), 0);
assert.equal(Amount.value(balance.unconfirmed), 201840);
}));
it('should send a tx', cob(function* () {
@ -138,8 +139,8 @@ describe('HTTP', function() {
assert.equal(tx.inputs.length, 1);
assert.equal(tx.outputs.length, 2);
value += utils.satoshi(tx.outputs[0].value);
value += utils.satoshi(tx.outputs[1].value);
value += Amount.value(tx.outputs[0].value);
value += Amount.value(tx.outputs[1].value);
assert.equal(value, 48190);
hash = tx.hash;
@ -160,7 +161,7 @@ describe('HTTP', function() {
it('should get balance', cob(function* () {
var balance = yield wallet.getBalance();
assert.equal(utils.satoshi(balance.unconfirmed), 199570);
assert.equal(Amount.value(balance.unconfirmed), 199570);
}));
it('should execute an rpc call', cob(function* () {

View File

@ -9,6 +9,7 @@ var base58 = require('../lib/utils/base58');
var encoding = require('../lib/utils/encoding');
var crypto = require('../lib/crypto/crypto');
var schnorr = require('../lib/crypto/schnorr');
var Amount = require('../lib/utils/amount');
describe('Utils', function() {
var vectors = [
@ -49,42 +50,42 @@ describe('Utils', function() {
});
it('should convert satoshi to btc', function() {
var btc = btcutils.btc(5460);
var btc = Amount.btc(5460);
assert.equal(btc, '0.0000546');
btc = btcutils.btc(54678 * 1000000);
btc = Amount.btc(54678 * 1000000);
assert.equal(btc, '546.78');
btc = btcutils.btc(5460 * 10000000);
btc = Amount.btc(5460 * 10000000);
assert.equal(btc, '546.0');
});
it('should convert btc to satoshi', function() {
var btc = btcutils.satoshi('0.0000546');
var btc = Amount.value('0.0000546');
assert(btc === 5460);
btc = btcutils.satoshi('546.78');
btc = Amount.value('546.78');
assert(btc === 54678 * 1000000);
btc = btcutils.satoshi('546');
btc = Amount.value('546');
assert(btc === 5460 * 10000000);
btc = btcutils.satoshi('546.0');
btc = Amount.value('546.0');
assert(btc === 5460 * 10000000);
btc = btcutils.satoshi('546.0000');
btc = Amount.value('546.0000');
assert(btc === 5460 * 10000000);
assert.doesNotThrow(function() {
btcutils.satoshi('546.00000000000000000');
Amount.value('546.00000000000000000');
});
assert.throws(function() {
btcutils.satoshi('546.00000000000000001');
Amount.value('546.00000000000000001');
});
assert.doesNotThrow(function() {
btcutils.satoshi('90071992.54740991');
Amount.value('90071992.54740991');
});
assert.doesNotThrow(function() {
btcutils.satoshi('090071992.547409910');
Amount.value('090071992.547409910');
});
assert.throws(function() {
btcutils.satoshi('90071992.54740992');
Amount.value('90071992.54740992');
});
assert.throws(function() {
btcutils.satoshi('190071992.54740991');
Amount.value('190071992.54740991');
});
});