Use historic BTC rate for expense items; allow BTC as currency
This commit is contained in:
@@ -18,7 +18,8 @@ export default class AddExpenseItemComponent extends Component {
|
||||
|
||||
currencies = [
|
||||
{ code: 'EUR' },
|
||||
{ code: 'USD' }
|
||||
{ code: 'USD' },
|
||||
{ code: 'BTC' }
|
||||
];
|
||||
|
||||
get isValidAmount () {
|
||||
|
||||
@@ -5,7 +5,9 @@ import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { A } from '@ember/array';
|
||||
import { scheduleOnce } from '@ember/runloop';
|
||||
import { btcToSats, satsToBtc } from 'kredits-web/utils/btc-conversions';
|
||||
import isValidAmount from 'kredits-web/utils/is-valid-amount';
|
||||
import isoDateIsToday from 'kredits-web/utils/iso-date-is-today';
|
||||
import readFileContent from 'kredits-web/utils/read-file-content';
|
||||
import config from 'kredits-web/config/environment';
|
||||
|
||||
@@ -73,22 +75,6 @@ export default class AddReimbursementComponent extends Component {
|
||||
anchor.scrollIntoView();
|
||||
}
|
||||
|
||||
updateTotalAmountFromFiat() {
|
||||
let btcAmount = 0;
|
||||
|
||||
if (this.exchangeRates.btceur > 0 && this.totalEUR > 0) {
|
||||
btcAmount += (this.totalEUR / this.exchangeRates.btceur);
|
||||
}
|
||||
if (this.exchangeRates.btcusd > 0 && this.totalUSD > 0) {
|
||||
btcAmount += (this.totalUSD / this.exchangeRates.btcusd);
|
||||
}
|
||||
if (this.totalUSD === 0 && this.totalEUR === 0) {
|
||||
btcAmount = 0;
|
||||
}
|
||||
|
||||
this.total = btcAmount.toFixed(8);
|
||||
}
|
||||
|
||||
// TODO use ember-concurrency here
|
||||
// https://github.com/67P/kredits-web/pull/209#discussion_r1064234421
|
||||
@action
|
||||
@@ -118,16 +104,38 @@ export default class AddReimbursementComponent extends Component {
|
||||
}
|
||||
|
||||
@action
|
||||
addExpenseItem (expenseItem) {
|
||||
this.expenses.pushObject(expenseItem);
|
||||
this.updateTotalAmountFromFiat();
|
||||
async addExpenseItem (expense) {
|
||||
let totalBTC = parseFloat(this.total);
|
||||
|
||||
if (expense.currency === "BTC") {
|
||||
expense.amountSats = btcToSats(expense.amount);
|
||||
totalBTC += expense.amount;
|
||||
} else {
|
||||
let amountSats;
|
||||
if (isoDateIsToday(expense.date)) {
|
||||
amountSats = btcToSats(expense.amount / this.exchangeRates[expense.currency]);
|
||||
} else {
|
||||
const rates = await this.exchangeRates.fetchHistoricRates(expense.date);
|
||||
amountSats = btcToSats(expense.amount / rates[expense.currency]);
|
||||
}
|
||||
expense.amountSats = amountSats;
|
||||
totalBTC += satsToBtc(amountSats);
|
||||
}
|
||||
console.debug("Adding expense:", expense);
|
||||
|
||||
this.total = totalBTC.toFixed(8);
|
||||
this.expenses.pushObject(expense);
|
||||
this.expenseFormVisible = false;
|
||||
}
|
||||
|
||||
@action
|
||||
removeExpenseItem (expenseItem) {
|
||||
this.expenses.removeObject(expenseItem);
|
||||
this.updateTotalAmountFromFiat();
|
||||
async removeExpenseItem (expense) {
|
||||
let totalBTC = parseFloat(this.total);
|
||||
let amountBTC = satsToBtc(expense.amountSats);
|
||||
totalBTC = totalBTC - amountBTC;
|
||||
this.total = totalBTC.toFixed(8);
|
||||
|
||||
this.expenses.removeObject(expense);
|
||||
|
||||
if (this.expenses.length === 0) {
|
||||
this.expenseFormVisible = true;
|
||||
@@ -143,7 +151,7 @@ export default class AddReimbursementComponent extends Component {
|
||||
const contributor = this.contributors.findBy('id', this.contributorId);
|
||||
|
||||
const attributes = {
|
||||
amount: parseInt(parseFloat(this.total) * 100000000), // convert to sats
|
||||
amount: btcToSats(this.total),
|
||||
token: config.tokens['BTC'],
|
||||
recipientId: this.contributorId,
|
||||
title: `Expenses covered by ${contributor.name}`,
|
||||
|
||||
@@ -2,10 +2,14 @@ import { helper } from '@ember/component/helper';
|
||||
|
||||
export default helper(function fmtFiatCurrency(params) {
|
||||
const lang = navigator.language || navigator.userLanguage;
|
||||
const value = params[0];
|
||||
const currency = params[1] || 'EUR';
|
||||
|
||||
if (currency === 'BTC') return `BTC ${value}`;
|
||||
|
||||
const formatter = new Intl.NumberFormat(lang, {
|
||||
style: 'currency',
|
||||
currency: params[1] || 'EUR',
|
||||
currencyDisplay: 'code'
|
||||
style: 'currency', currency, currencyDisplay: 'code'
|
||||
})
|
||||
|
||||
return formatter.format(params[0]);
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ export default class CommunityFundsService extends Service {
|
||||
|
||||
// Format and round the approximate USD value
|
||||
const lang = navigator.language || navigator.userLanguage;
|
||||
const balanceUSD = (res.confirmed_balance / 100000000) * this.exchangeRates.btcusd;
|
||||
const balanceUSD = (res.confirmed_balance / 100000000) * this.exchangeRates.USD;
|
||||
res.balanceUSD = Math.round(balanceUSD).toLocaleString(lang);
|
||||
|
||||
this.balances.pushObject({
|
||||
|
||||
@@ -4,6 +4,7 @@ import config from 'kredits-web/config/environment';
|
||||
|
||||
// Need to go through proxy for CORS headers
|
||||
const bitstampBaseUrl = `${config.corsProxy}https://www.bitstamp.net/api/v2`;
|
||||
const kosmosBtcPriceBaseUrl = "https://storage.kosmos.org/kosmos/public/btc-price";
|
||||
|
||||
async function fetchFromBitstamp(currencyPair) {
|
||||
try {
|
||||
@@ -16,11 +17,12 @@ async function fetchFromBitstamp(currencyPair) {
|
||||
}
|
||||
|
||||
export default class ExchangeRatesService extends Service {
|
||||
@tracked btceur = 0;
|
||||
@tracked btcusd = 0;
|
||||
@tracked EUR = 0;
|
||||
@tracked USD = 0;
|
||||
@tracked historic = {};
|
||||
|
||||
get exchangeRatesLoaded () {
|
||||
return (this.btceur !== 0) && (this.btcusd !== 0);
|
||||
return (this.EUR !== 0) && (this.USD !== 0);
|
||||
}
|
||||
|
||||
async fetchRates (source='bitstamp') {
|
||||
@@ -28,8 +30,24 @@ export default class ExchangeRatesService extends Service {
|
||||
|
||||
switch(source) {
|
||||
case 'bitstamp':
|
||||
this.btceur = await fetchFromBitstamp('btceur');
|
||||
this.btcusd = await fetchFromBitstamp('btcusd');
|
||||
this.EUR = await fetchFromBitstamp('btceur');
|
||||
this.USD = await fetchFromBitstamp('btcusd');
|
||||
}
|
||||
}
|
||||
|
||||
async fetchHistoricRates (isoDate) {
|
||||
if (typeof this.historic[isoDate] === "object") {
|
||||
return this.historic[isoDate];
|
||||
} else {
|
||||
const url = `${kosmosBtcPriceBaseUrl}/${isoDate}`;
|
||||
try {
|
||||
const rates = await fetch(url).then(res => res.json());
|
||||
this.historic[isoDate] = rates;
|
||||
return rates;
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
Promise.reject(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,5 +18,12 @@ module('Integration | Helper | fmt-fiat-currency', function(hooks) {
|
||||
await render(hbs`{{fmt-fiat-currency this.amount 'USD'}}`);
|
||||
assert.ok(this.element.textContent.trim().match(/USD/),
|
||||
'using defined currency when given');
|
||||
|
||||
await render(hbs`{{fmt-fiat-currency 0.00123 'BTC'}}`);
|
||||
assert.ok(this.element.textContent.trim().match(/0.00123/),
|
||||
'allows more decimals');
|
||||
assert.ok(this.element.textContent.trim().match(/BTC/),
|
||||
'using defined currency when given');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -39,12 +39,4 @@ module('Unit | Component | add-reimbursement', function(hooks) {
|
||||
assert.equal(component.totalEUR, '71');
|
||||
assert.equal(component.totalUSD, '59');
|
||||
});
|
||||
|
||||
test('#updateTotalAmountFromFiat', async function(assert) {
|
||||
let component = createComponent('component:add-reimbursement');
|
||||
component.expenses = expenses;
|
||||
await component.exchangeRates.fetchRates();
|
||||
component.updateTotalAmountFromFiat();
|
||||
assert.equal(component.total, '0.01323322', 'converts EUR and USD totals to BTC and rounds to 8 decimals');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ module('Unit | Service | exchange-rates', function(hooks) {
|
||||
test('#fetchRates', async function(assert) {
|
||||
let service = this.owner.lookup('service:exchange-rates');
|
||||
await service.fetchRates();
|
||||
assert.equal(service.btceur, 9167.57, 'fetches BTCEUR from Bitstamp');
|
||||
assert.equal(service.btcusd, 10749.70, 'fetches BTCUSD from Bitstamp');
|
||||
assert.equal(service.EUR, 9167.57, 'fetches BTCEUR from Bitstamp');
|
||||
assert.equal(service.USD, 10749.70, 'fetches BTCUSD from Bitstamp');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user