diff --git a/src/action/channel.js b/src/action/channel.js
index a236f5b6e..5beaf3b1c 100644
--- a/src/action/channel.js
+++ b/src/action/channel.js
@@ -133,7 +133,7 @@ class ChannelAction {
async connectAndOpen() {
try {
const { channel, settings } = this._store;
- const amount = toSatoshis(channel.amount, settings.unit);
+ const amount = toSatoshis(channel.amount, settings);
if (!channel.pubkeyAtHost.includes('@')) {
return this._notification.display({ msg: 'Please enter pubkey@host' });
}
diff --git a/src/action/invoice.js b/src/action/invoice.js
index 5568d59f1..a63934e64 100644
--- a/src/action/invoice.js
+++ b/src/action/invoice.js
@@ -31,7 +31,7 @@ class InvoiceAction {
try {
const { invoice, settings } = this._store;
const response = await this._grpc.sendCommand('addInvoice', {
- value: toSatoshis(invoice.amount, settings.unit),
+ value: toSatoshis(invoice.amount, settings),
memo: invoice.note,
});
invoice.encoded = response.payment_request;
diff --git a/src/action/payment.js b/src/action/payment.js
index fd97ee8b2..60dbbfcdf 100644
--- a/src/action/payment.js
+++ b/src/action/payment.js
@@ -68,7 +68,7 @@ class PaymentAction {
const request = await this._grpc.sendCommand('decodePayReq', {
pay_req: invoice.replace(PREFIX_URI, ''),
});
- payment.amount = toAmount(parseSat(request.num_satoshis), settings.unit);
+ payment.amount = toAmount(parseSat(request.num_satoshis), settings);
payment.note = request.description;
await this.estimateLightningFee({
destination: request.destination,
@@ -89,7 +89,7 @@ class PaymentAction {
amt: satAmt,
num_routes: 1,
});
- payment.fee = toAmount(parseSat(routes[0].total_fees), settings.unit);
+ payment.fee = toAmount(parseSat(routes[0].total_fees), settings);
} catch (err) {
log.error(`Estimating lightning fee failed!`, err);
}
@@ -100,7 +100,7 @@ class PaymentAction {
const { payment, settings } = this._store;
await this._grpc.sendCommand('sendCoins', {
addr: payment.address,
- amount: toSatoshis(payment.amount, settings.unit),
+ amount: toSatoshis(payment.amount, settings),
});
this._nav.goPayBitcoinDone();
} catch (err) {
diff --git a/src/computed/payment.js b/src/computed/payment.js
index d58c3bdce..a78248ab8 100644
--- a/src/computed/payment.js
+++ b/src/computed/payment.js
@@ -9,8 +9,8 @@ const ComputedPayment = store => {
paymentFeeLabel: computed(() => toLabel(store.payment.fee, store.settings)),
paymentTotalLabel: computed(() => {
const { payment, settings } = store;
- const satAmount = toSatoshis(payment.amount, settings.unit);
- const satFee = toSatoshis(payment.fee, settings.unit);
+ const satAmount = toSatoshis(payment.amount, settings);
+ const satFee = toSatoshis(payment.fee, settings);
return toAmountLabel(satAmount + satFee, settings);
}),
});
diff --git a/src/computed/setting.js b/src/computed/setting.js
index 3f2d12ff0..e814523b6 100644
--- a/src/computed/setting.js
+++ b/src/computed/setting.js
@@ -5,13 +5,13 @@ import { UNITS, FIATS } from '../config';
const ComputedSetting = store => {
extendObservable(store, {
selectedUnitLabel: computed(() => getUnitLabel(store.settings.unit)),
- selectedFiatLabel: computed(() => FIATS[store.settings.fiat].display),
+ selectedFiatLabel: computed(() => FIATS[store.settings.fiat].displayLong),
satUnitLabel: computed(() => getUnitLabel('sat')),
bitUnitLabel: computed(() => getUnitLabel('bit')),
btcUnitLabel: computed(() => getUnitLabel('btc')),
- usdFiatLabel: computed(() => FIATS['usd'].display),
- eurFiatLabel: computed(() => FIATS['eur'].display),
- gbpFiatLabel: computed(() => FIATS['gbp'].display),
+ usdFiatLabel: computed(() => FIATS['usd'].displayLong),
+ eurFiatLabel: computed(() => FIATS['eur'].displayLong),
+ gbpFiatLabel: computed(() => FIATS['gbp'].displayLong),
});
};
diff --git a/src/computed/wallet.js b/src/computed/wallet.js
index e23d4edb0..6303f6d4d 100644
--- a/src/computed/wallet.js
+++ b/src/computed/wallet.js
@@ -1,6 +1,6 @@
import { computed, extendObservable } from 'mobx';
import { toAmountLabel } from '../helper';
-import { UNITS } from '../config';
+import { UNITS, FIATS } from '../config';
const ComputedWallet = store => {
extendObservable(store, {
@@ -13,6 +13,10 @@ const ComputedWallet = store => {
channelBalanceLabel: computed(() =>
toAmountLabel(store.channelBalanceSatoshis, store.settings)
),
+ unitFiatLabel: computed(() => {
+ const { displayFiat, unit, fiat } = store.settings;
+ return displayFiat ? FIATS[fiat].display : UNITS[unit].display;
+ }),
unitLabel: computed(() => {
const { settings } = store;
return !settings.displayFiat ? UNITS[settings.unit].display : null;
diff --git a/src/config.js b/src/config.js
index 41419ee31..0ffeb3cde 100644
--- a/src/config.js
+++ b/src/config.js
@@ -21,9 +21,9 @@ module.exports.UNITS = {
btc: { display: 'BTC', displayLong: 'Bitcoin', denominator: 100000000 },
};
module.exports.FIATS = {
- usd: { display: 'US Dollar' },
- eur: { display: 'Euro' },
- gbp: { display: 'British Pound' },
+ usd: { display: '$', displayLong: 'US Dollar' },
+ eur: { display: '€', displayLong: 'Euro' },
+ gbp: { display: '£', displayLong: 'British Pound' },
};
module.exports.DEFAULT_UNIT = 'btc';
module.exports.DEFAULT_FIAT = 'usd';
diff --git a/src/helper.js b/src/helper.js
index 0125ad2ca..d27c374b7 100644
--- a/src/helper.js
+++ b/src/helper.js
@@ -56,33 +56,45 @@ export const parseSat = satoshis => {
};
/**
- * Convert a string formatted BTC amount to satoshis
- * @param {string} amount The amount e.g. '0.0001'
- * @param {string} unit The BTC unit e.g. 'btc' or 'bit'
- * @return {number} The satoshis as an integer
+ * Convert a string formatted btc/fiat amount to satoshis
+ * @param {string} amount The amount e.g. '0.0001'
+ * @param {Object} settings Contains the current exchange rate
+ * @return {number} The satoshis as an integer
*/
-export const toSatoshis = (amount, unit) => {
+export const toSatoshis = (amount, settings) => {
if (
typeof amount !== 'string' ||
!/^[0-9]*[.]?[0-9]*$/.test(amount) ||
- !UNITS[unit]
+ !settings ||
+ typeof settings.displayFiat !== 'boolean'
) {
- throw new Error('Missing args!');
+ throw new Error('Invalid input!');
+ }
+ if (settings.displayFiat) {
+ const rate = settings.exchangeRate[settings.fiat] || 0;
+ return Math.round(Number(amount) * rate * UNITS.btc.denominator);
+ } else {
+ return Math.round(Number(amount) * UNITS[settings.unit].denominator);
}
- return Math.round(Number(amount) * UNITS[unit].denominator);
};
/**
* Convert satoshis to a BTC values than can set as a text input value
* @param {number} satoshis The value as a string or number
- * @param {string} unit The BTC unit e.g. 'btc' or 'bit'
+ * @param {Object} settings Contains the current exchange rate
* @return {string} The amount formatted as '0.0001'
*/
-export const toAmount = (satoshis, unit) => {
- if (!Number.isInteger(satoshis) || !UNITS[unit]) {
+export const toAmount = (satoshis, settings) => {
+ if (
+ !Number.isInteger(satoshis) ||
+ !settings ||
+ typeof settings.displayFiat !== 'boolean'
+ ) {
throw new Error('Invalid input!');
}
- const num = satoshis / UNITS[unit].denominator;
+ const num = settings.displayFiat
+ ? calculateExchangeRate(satoshis, settings)
+ : satoshis / UNITS[settings.unit].denominator;
return num.toLocaleString('en-US', {
useGrouping: false,
maximumFractionDigits: 8,
@@ -103,8 +115,7 @@ export const calculateExchangeRate = (satoshis, settings) => {
throw new Error('Invalid input!');
}
const rate = settings.exchangeRate[settings.fiat] || 0;
- const balance = satoshis / rate / UNITS.btc.denominator;
- return formatFiat(balance, settings.fiat);
+ return satoshis / rate / UNITS.btc.denominator;
};
/**
@@ -122,22 +133,19 @@ export const toAmountLabel = (satoshis, settings) => {
throw new Error('Invalid input!');
}
return settings.displayFiat
- ? calculateExchangeRate(satoshis, settings)
- : formatNumber(toAmount(satoshis, settings.unit));
+ ? formatFiat(calculateExchangeRate(satoshis, settings), settings.fiat)
+ : formatNumber(toAmount(satoshis, settings));
};
/**
- * Convert a string formatted BTC amount either to fiat or the selected BTC unit.
+ * Convert a string formatted btc/fiat amount either to fiat or the selected BTC unit.
* The output should be used throughout the UI for value labels.
- * @param {string} amount The amount e.g. '0.0001'
+ * @param {string} amount The amount e.g. '0.0001'
* @param {Object} settings Contains the current exchange rate
* @return {string} The corresponding value label
*/
export const toLabel = (amount, settings) => {
- if (!settings) {
- throw new Error('Missing args!');
- }
- const satoshis = toSatoshis(amount, settings.unit);
+ const satoshis = toSatoshis(amount, settings);
return toAmountLabel(satoshis, settings);
};
diff --git a/src/view/channel-create.js b/src/view/channel-create.js
index 48ca0371a..3303495a2 100644
--- a/src/view/channel-create.js
+++ b/src/view/channel-create.js
@@ -44,7 +44,9 @@ const ChannelCreateView = ({ store, nav, channel }) => (
onChangeText={amount => channel.setAmount({ amount })}
onSubmitEditing={() => channel.connectAndOpen()}
/>
- {store.unit}
+
+ {store.unitFiatLabel}
+
(
onChangeText={amount => invoice.setAmount({ amount })}
onSubmitEditing={() => invoice.generateUri()}
/>
- {store.unit}
+
+ {store.unitFiatLabel}
+
(
onSubmitEditing={() => nav.goPayBitcoinConfirm()}
/>
- {store.unit}
+ {store.unitFiatLabel}
{
it('should format fiat amount', () => {
store.settings.displayFiat = true;
store.settings.exchangeRate.usd = 0.00014503;
- store.invoice.amount = '0.1001';
+ store.invoice.amount = '1.10';
ComputedInvoice(store);
- expect(store.invoiceAmountLabel, 'to match', /690[,.]20/);
+ expect(store.invoiceAmountLabel, 'to match', /1[,.]10/);
});
});
});
diff --git a/test/unit/computed/payment.spec.js b/test/unit/computed/payment.spec.js
index 83ad8d6f1..cc4ae1470 100644
--- a/test/unit/computed/payment.spec.js
+++ b/test/unit/computed/payment.spec.js
@@ -28,12 +28,12 @@ describe('Computed Payment Unit Tests', () => {
it('should calculate fiat total', () => {
store.settings.displayFiat = true;
store.settings.exchangeRate.usd = 0.00014503;
- store.payment.fee = '0.0001';
- store.payment.amount = '0.1';
+ store.payment.fee = '0.10';
+ store.payment.amount = '1.00';
ComputedPayment(store);
- expect(store.paymentAmountLabel, 'to match', /689[,.]51/);
- expect(store.paymentFeeLabel, 'to match', /0[,.]69/);
- expect(store.paymentTotalLabel, 'to match', /690[,.]20/);
+ expect(store.paymentAmountLabel, 'to match', /1[,.]00/);
+ expect(store.paymentFeeLabel, 'to match', /0[,.]10/);
+ expect(store.paymentTotalLabel, 'to match', /1[,.]10/);
});
it('should ignore fee if blank', () => {
diff --git a/test/unit/computed/wallet.spec.js b/test/unit/computed/wallet.spec.js
index 8ab8960c3..24ada1f79 100644
--- a/test/unit/computed/wallet.spec.js
+++ b/test/unit/computed/wallet.spec.js
@@ -14,7 +14,9 @@ describe('Computed Wallet Unit Tests', () => {
expect(store.walletAddressUri, 'to equal', '');
expect(store.balanceLabel, 'to equal', '0');
expect(store.channelBalanceLabel, 'to equal', '0');
+ expect(store.unitFiatLabel, 'to equal', 'BTC');
expect(store.unitLabel, 'to equal', 'BTC');
+ expect(store.unit, 'to equal', 'BTC');
});
it('should generate valid wallet address uri', () => {
@@ -35,6 +37,7 @@ describe('Computed Wallet Unit Tests', () => {
ComputedWallet(store);
expect(store.balanceLabel, 'to match', /6[,.]895[,.]13/);
expect(store.channelBalanceLabel, 'to match', /0[,.]69/);
+ expect(store.unitFiatLabel, 'to equal', '$');
expect(store.unitLabel, 'to equal', null);
});
@@ -50,6 +53,7 @@ describe('Computed Wallet Unit Tests', () => {
/^1{1}[,.]0{3}[,.]0{3}[,.]0{1}1{1}$/
);
expect(store.channelBalanceLabel, 'to equal', '100');
+ expect(store.unitFiatLabel, 'to equal', 'bits');
expect(store.unitLabel, 'to equal', 'bits');
});
});
diff --git a/test/unit/helper.spec.js b/test/unit/helper.spec.js
index b513789d0..ae2c7f972 100644
--- a/test/unit/helper.spec.js
+++ b/test/unit/helper.spec.js
@@ -154,82 +154,143 @@ describe('Helpers Unit Tests', () => {
});
describe('toSatoshis()', () => {
+ let settings;
+
+ beforeEach(() => {
+ settings = {
+ displayFiat: false,
+ unit: 'btc',
+ fiat: 'usd',
+ exchangeRate: { usd: 0.00014503 },
+ };
+ });
+
it('should throw error if amount is undefined', () => {
expect(
- helpers.toSatoshis.bind(null, undefined, 'btc'),
+ helpers.toSatoshis.bind(null, undefined, settings),
'to throw',
- /Missing/
+ /Invalid/
);
});
it('should throw error if amount is null', () => {
- expect(helpers.toSatoshis.bind(null, null, 'btc'), 'to throw', /Missing/);
+ expect(
+ helpers.toSatoshis.bind(null, null, settings),
+ 'to throw',
+ /Invalid/
+ );
});
it('should throw error if amount is number', () => {
- expect(helpers.toSatoshis.bind(null, 0.1, 'btc'), 'to throw', /Missing/);
+ expect(
+ helpers.toSatoshis.bind(null, 0.1, settings),
+ 'to throw',
+ /Invalid/
+ );
});
it('should throw error if amount is separated with a comma', () => {
expect(
- helpers.toSatoshis.bind(null, '0,1', 'btc'),
+ helpers.toSatoshis.bind(null, '0,1', settings),
'to throw',
- /Missing/
+ /Invalid/
);
});
- it('should throw error if unit is undefined', () => {
+ it('should throw error if settings is undefined', () => {
expect(
helpers.toSatoshis.bind(null, '100', undefined),
'to throw',
- /Missing/
+ /Invalid/
);
});
+ it('should throw error for wrong settings', () => {
+ expect(helpers.toSatoshis.bind(null, '100', {}), 'to throw', /Invalid/);
+ });
+
it('should be 0 for empty amount', () => {
- const num = helpers.toSatoshis('', 'btc');
+ const num = helpers.toSatoshis('', settings);
expect(num, 'to equal', 0);
});
- it('should work for string input', () => {
- const num = helpers.toSatoshis('0.10', 'btc');
+ it('should work for string amount', () => {
+ const num = helpers.toSatoshis('0.10', settings);
expect(num, 'to equal', 10000000);
});
it('should have use ony 8 decimal values', () => {
- const num = helpers.toSatoshis('0.000000014', 'btc');
+ const num = helpers.toSatoshis('0.000000014', settings);
expect(num, 'to equal', 1);
});
it('should round up to two satoshis', () => {
- const num = helpers.toSatoshis('0.000000019', 'btc');
+ const num = helpers.toSatoshis('0.000000019', settings);
expect(num, 'to equal', 2);
});
+
+ it('should be 0 is exchange rate is not set (fiat)', () => {
+ settings.displayFiat = true;
+ settings.fiat = 'invalid';
+ const num = helpers.toSatoshis('100', settings);
+ expect(num, 'to equal', 0);
+ });
+
+ it('should be 0 for empty amount (fiat)', () => {
+ settings.displayFiat = true;
+ const num = helpers.toSatoshis('', settings);
+ expect(num, 'to equal', 0);
+ });
+
+ it('should work for string amount (fiat)', () => {
+ settings.displayFiat = true;
+ const num = helpers.toSatoshis('10.00', settings);
+ expect(num, 'to equal', 145030);
+ });
});
describe('toAmount()', () => {
+ let settings;
+
+ beforeEach(() => {
+ settings = {
+ displayFiat: false,
+ unit: 'btc',
+ fiat: 'usd',
+ exchangeRate: { usd: 0.00014503 },
+ };
+ });
+
it('should throw error if satoshis is undefined', () => {
expect(
- helpers.toAmount.bind(null, undefined, 'btc'),
+ helpers.toAmount.bind(null, undefined, settings),
'to throw',
/Invalid/
);
});
it('should throw error if satoshis is null', () => {
- expect(helpers.toAmount.bind(null, null, 'btc'), 'to throw', /Invalid/);
+ expect(
+ helpers.toAmount.bind(null, null, settings),
+ 'to throw',
+ /Invalid/
+ );
});
it('should throw error if satoshis is not a number', () => {
expect(
- helpers.toAmount.bind(null, 'not-a-number', 'btc'),
+ helpers.toAmount.bind(null, 'not-a-number', settings),
'to throw',
/Invalid/
);
});
it('should throw error for string number', () => {
- expect(helpers.toAmount.bind(null, '100', 'btc'), 'to throw', /Invalid/);
+ expect(
+ helpers.toAmount.bind(null, '100', settings),
+ 'to throw',
+ /Invalid/
+ );
});
it('should throw error if unit is invalid', () => {
@@ -240,7 +301,7 @@ describe('Helpers Unit Tests', () => {
);
});
- it('should throw error if unit is undefined', () => {
+ it('should throw error if settings is undefined', () => {
expect(
helpers.toAmount.bind(null, 100, undefined),
'to throw',
@@ -248,53 +309,94 @@ describe('Helpers Unit Tests', () => {
);
});
+ it('should throw error if settings is invalid', () => {
+ expect(helpers.toAmount.bind(null, 100, {}), 'to throw', /Invalid/);
+ });
+
it('should throw error for non-integer numbers', () => {
expect(
- helpers.toAmount.bind(null, 100000000.9, 'btc'),
+ helpers.toAmount.bind(null, 100000000.9, settings),
'to throw',
/Invalid/
);
});
it('should work for number input', () => {
- const num = helpers.toAmount(100000000, 'btc');
+ const num = helpers.toAmount(100000000, settings);
expect(num, 'to equal', '1');
});
it('should not format number input', () => {
- const num = helpers.toAmount(100000000000, 'btc');
+ const num = helpers.toAmount(100000000000, settings);
expect(num, 'to equal', '1000');
});
it('should use period for decimals values', () => {
- const num = helpers.toAmount(10000000, 'btc');
+ const num = helpers.toAmount(10000000, settings);
expect(num, 'to equal', '0.1');
});
it('should work for 0', () => {
- const num = helpers.toAmount(0, 'btc');
+ const num = helpers.toAmount(0, settings);
expect(num, 'to equal', '0');
});
it('should work for 1', () => {
- const num = helpers.toAmount(1, 'btc');
+ const num = helpers.toAmount(1, settings);
expect(num, 'to equal', '0.00000001');
});
it('should work for 10', () => {
- const num = helpers.toAmount(10, 'btc');
+ const num = helpers.toAmount(10, settings);
expect(num, 'to equal', '0.0000001');
});
it('should work for 100', () => {
- const num = helpers.toAmount(100, 'btc');
+ const num = helpers.toAmount(100, settings);
expect(num, 'to equal', '0.000001');
});
it('should work for 1000', () => {
- const num = helpers.toAmount(1000, 'btc');
+ const num = helpers.toAmount(1000, settings);
expect(num, 'to equal', '0.00001');
});
+
+ it('should be infinity if exchange rate is not set (fiat)', () => {
+ settings.displayFiat = true;
+ settings.fiat = 'invalid-fiat';
+ const rate = helpers.toAmount(100, settings);
+ expect(rate, 'to match', /∞/);
+ });
+
+ it('should work for number input (fiat)', () => {
+ settings.displayFiat = true;
+ const num = helpers.toAmount(100000, settings);
+ expect(num, 'to equal', '6.89512515');
+ });
+
+ it('should use period for decimals values (fiat)', () => {
+ settings.displayFiat = true;
+ const num = helpers.toAmount(100000000, settings);
+ expect(num, 'to equal', '6895.12514652');
+ });
+
+ it('should work for 0 (fiat)', () => {
+ settings.displayFiat = true;
+ const num = helpers.toAmount(0, settings);
+ expect(num, 'to equal', '0');
+ });
+
+ it('should work for 1 (fiat)', () => {
+ settings.displayFiat = true;
+ const num = helpers.toAmount(1, settings);
+ expect(num, 'to equal', '0.00006895');
+ });
+
+ it('should work for 1000 (fiat)', () => {
+ settings.displayFiat = true;
+ const num = helpers.toAmount(1000, settings);
+ expect(num, 'to equal', '0.06895125');
+ });
});
describe('calculateExchangeRate()', () => {
@@ -358,13 +460,13 @@ describe('Helpers Unit Tests', () => {
it('should work for a number value', () => {
const rate = helpers.calculateExchangeRate(100000, settings);
- expect(rate, 'to match', /6{1}[,.]9{1}0{1}/);
+ expect(rate, 'to equal', 6.8951251465214085);
});
it('should be infinite for unknown rate', () => {
settings.fiat = 'eur';
const rate = helpers.calculateExchangeRate(100000, settings);
- expect(rate, 'to match', /∞/);
+ expect(rate, 'to equal', Infinity);
});
});
@@ -466,23 +568,23 @@ describe('Helpers Unit Tests', () => {
expect(
helpers.toLabel.bind(null, undefined, settings),
'to throw',
- /Missing/
+ /Invalid/
);
});
it('should throw error if amount is null', () => {
- expect(helpers.toLabel.bind(null, null, settings), 'to throw', /Missing/);
+ expect(helpers.toLabel.bind(null, null, settings), 'to throw', /Invalid/);
});
it('should throw error if amount is number', () => {
- expect(helpers.toLabel.bind(null, 0.1, settings), 'to throw', /Missing/);
+ expect(helpers.toLabel.bind(null, 0.1, settings), 'to throw', /Invalid/);
});
it('should throw error if amount is separated with a comma', () => {
expect(
helpers.toLabel.bind(null, '0,1', settings),
'to throw',
- /Missing/
+ /Invalid/
);
});
@@ -490,7 +592,7 @@ describe('Helpers Unit Tests', () => {
expect(
helpers.toLabel.bind(null, '100', undefined),
'to throw',
- /Missing/
+ /Invalid/
);
});
@@ -499,14 +601,14 @@ describe('Helpers Unit Tests', () => {
expect(num, 'to match', /0{1}[,.]0{2}/);
});
- it('should work for string input', () => {
+ it('should work for fiat amount', () => {
const num = helpers.toLabel('0.10', settings);
- expect(num, 'to match', /689[,.]51/);
+ expect(num, 'to match', /0[,.]10/);
});
- it('should format a number value', () => {
+ it('should work for btc amount', () => {
settings.displayFiat = false;
const lbl = helpers.toLabel('0.10', settings);
- expect(lbl, 'to match', /0[,.]1/);
+ expect(lbl, 'to match', /^0[,.]1$/);
});
});