diff --git a/lib/wallet.js b/lib/wallet.js index a1b556d8f..1318acebd 100644 --- a/lib/wallet.js +++ b/lib/wallet.js @@ -86,5 +86,68 @@ utils.defineProperty(Wallet, 'getIcapAddress', SigningKey.getIcapAddress); utils.defineProperty(Wallet, '_Contract', Contract); +var zero = new utils.BN(0); +var negative1 = new utils.BN(-1); +var tenPower18 = new utils.BN('1000000000000000000'); +utils.defineProperty(Wallet, 'formatEther', function(wei, options) { + if (typeof(wei) === 'number') { wei = new utils.BN(wei); } + if (!options) { options = {}; } + + if (!(wei instanceof utils.BN)) { throw new Error('invalid wei'); } + + var negative = wei.lt(zero); + if (negative) { wei = wei.mul(negative1); } + + var fraction = wei.mod(tenPower18).toString(10); + while (fraction.length < 18) { fraction = '0' + fraction; } + + if (!options.pad) { + fraction = fraction.match(/^([0-9]*[1-9]|0)(0*)/)[1]; + } + + var whole = wei.div(tenPower18).toString(10); + + if (options.commify) { + whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ",") + } + + var value = whole + '.' + fraction; + + if (negative) { value = '-' + value; } + + return value; +}); + +utils.defineProperty(Wallet, 'parseEther', function(ether) { + if (typeof(ether) !== 'string' || !ether.match(/^-?[0-9.]+$/)) { + throw new Error('invalid value'); + } + + // Is it negative? + var negative = (ether.substring(0, 1) === '-'); + if (negative) { ether = ether.substring(1); } + + if (ether === '.') { throw new Error('invalid value'); } + + // Split it into a whole and fractional part + var comps = ether.split('.'); + if (comps.length > 2) { throw new Error('too many decimal points'); } + + var whole = comps[0], fraction = comps[1]; + if (!whole) { whole = '0'; } + if (!fraction) { fraction = '0'; } + if (fraction.length > 18) { throw new Error('too many decimal places'); } + + while (fraction.length < 18) { fraction += '0'; } + + whole = new utils.BN(whole); + fraction = new utils.BN(fraction); + + var wei = (whole.mul(tenPower18)).add(fraction); + + if (negative) { wei = wei.mul(negative1); } + + return wei; +}); module.exports = Wallet; diff --git a/tests/test-ether-format.js b/tests/test-ether-format.js new file mode 100644 index 000000000..fd5725dd3 --- /dev/null +++ b/tests/test-ether-format.js @@ -0,0 +1,55 @@ +'use strict'; +var Wallet = require('../index.js'); + +var BN = Wallet.utils.BN; + +module.exports = function(test) { + function checkFormat(wei, targetEther, options) { + var ether = Wallet.formatEther(wei, options); + //console.log(wei, targetEther, options, ether); + test.equal(ether, targetEther, 'Failed to match formatted ether'); + ether = ether.replace(/,/g, ''); + test.ok(Wallet.parseEther(ether).eq(wei), 'Failed to convert back to wei'); + } + + function checkParse(ether, targetWei) { + //console.log(ether, targetWei, Wallet.parseEther(ether)); + test.ok(targetWei.eq(Wallet.parseEther(ether)), 'Failed to match target wei'); + } + + checkParse('123.012345678901234567', new BN('123012345678901234567')); + + checkParse('1.0', new BN('1000000000000000000')); + checkParse('1', new BN('1000000000000000000')); + checkParse('1.00', new BN('1000000000000000000')); + checkParse('01.0', new BN('1000000000000000000')); + + checkParse('-1.0', new BN('-1000000000000000000')); + + checkParse('0.1', new BN('100000000000000000')); + checkParse('.1', new BN('100000000000000000')); + checkParse('0.10', new BN('100000000000000000')); + checkParse('.100', new BN('100000000000000000')); + checkParse('00.100', new BN('100000000000000000')); + + checkParse('-0.1', new BN('-100000000000000000')); + + + checkFormat(new BN('10000000000000000'), '0.01'); + checkFormat(new BN('1000000000000000000'), '1.0'); + checkFormat(new BN('1230000000000000000'), '1.23'); + checkFormat(new BN('-1230000000000000000'), '-1.23'); + + checkFormat(new BN('1000000000000000000'), '1.000000000000000000', {pad: true}); + checkFormat(new BN('123000000000000000000'), '123.000000000000000000', {pad: true}); + checkFormat(new BN('1230000000000000000'), '1.230000000000000000', {pad: true}); + + checkFormat(new BN('-1230000000000000000'), '-1.230000000000000000', {pad: true}); + + checkFormat(new BN('1234567890000000000000000'), '1,234,567.89', {pad: false, commify: true}); + checkFormat(new BN('1234567890000000000000000'), '1,234,567.890000000000000000', {pad: true, commify: true}); + checkFormat(new BN('-1234567890000000000000000'), '-1,234,567.89', {pad: false, commify: true}); + + + test.done(); +}