Compare commits

..

3 Commits

43 changed files with 6418 additions and 10583 deletions
-1
View File
@@ -1 +0,0 @@
16
+1 -2
View File
@@ -18,8 +18,7 @@ export default class AddExpenseItemComponent extends Component {
currencies = [ currencies = [
{ code: 'EUR' }, { code: 'EUR' },
{ code: 'USD' }, { code: 'USD' }
{ code: 'BTC' }
]; ];
get isValidAmount () { get isValidAmount () {
+26 -38
View File
@@ -5,9 +5,7 @@ import { inject as service } from '@ember/service';
import { action } from '@ember/object'; import { action } from '@ember/object';
import { A } from '@ember/array'; import { A } from '@ember/array';
import { scheduleOnce } from '@ember/runloop'; import { scheduleOnce } from '@ember/runloop';
import { btcToSats, satsToBtc } from 'kredits-web/utils/btc-conversions';
import isValidAmount from 'kredits-web/utils/is-valid-amount'; 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 readFileContent from 'kredits-web/utils/read-file-content';
import config from 'kredits-web/config/environment'; import config from 'kredits-web/config/environment';
@@ -29,10 +27,6 @@ export default class AddReimbursementComponent extends Component {
this.exchangeRates.fetchRates(); this.exchangeRates.fetchRates();
} }
get contributorId () {
return this.recipientId || this.kredits.currentUser?.id;
}
get isValidTotal () { get isValidTotal () {
return isValidAmount(this.total); return isValidAmount(this.total);
} }
@@ -75,6 +69,22 @@ export default class AddReimbursementComponent extends Component {
anchor.scrollIntoView(); anchor.scrollIntoView();
} }
updateTotalAmountFromFiat() {
let btcAmount = parseFloat(this.total);
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 // TODO use ember-concurrency here
// https://github.com/67P/kredits-web/pull/209#discussion_r1064234421 // https://github.com/67P/kredits-web/pull/209#discussion_r1064234421
@action @action
@@ -94,7 +104,7 @@ export default class AddReimbursementComponent extends Component {
@action @action
updateContributor (event) { updateContributor (event) {
this.recipientId = parseInt(event.target.value); this.recipientId = event.target.value;
} }
@action @action
@@ -104,38 +114,16 @@ export default class AddReimbursementComponent extends Component {
} }
@action @action
async addExpenseItem (expense) { addExpenseItem (expenseItem) {
let totalBTC = parseFloat(this.total); this.expenses.pushObject(expenseItem);
this.updateTotalAmountFromFiat();
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; this.expenseFormVisible = false;
} }
@action @action
async removeExpenseItem (expense) { removeExpenseItem (expenseItem) {
let totalBTC = parseFloat(this.total); this.expenses.removeObject(expenseItem);
let amountBTC = satsToBtc(expense.amountSats); this.updateTotalAmountFromFiat();
totalBTC = totalBTC - amountBTC;
this.total = totalBTC.toFixed(8);
this.expenses.removeObject(expense);
if (this.expenses.length === 0) { if (this.expenses.length === 0) {
this.expenseFormVisible = true; this.expenseFormVisible = true;
@@ -148,12 +136,12 @@ export default class AddReimbursementComponent extends Component {
if (!this.kredits.currentUser) { window.alert('You need to connect your RSK account first.'); return false } if (!this.kredits.currentUser) { window.alert('You need to connect your RSK account first.'); return false }
if (!this.kredits.currentUserIsCore) { window.alert('Only core contributors can submit reimbursements.'); return false } if (!this.kredits.currentUserIsCore) { window.alert('Only core contributors can submit reimbursements.'); return false }
const contributor = this.contributors.findBy('id', this.contributorId); const contributor = this.contributors.findBy('id', parseInt(this.recipientId));
const attributes = { const attributes = {
amount: btcToSats(this.total), amount: parseInt(parseFloat(this.total) * 100000000), // convert to sats
token: config.tokens['BTC'], token: config.tokens['BTC'],
recipientId: this.contributorId, recipientId: parseInt(this.recipientId),
title: `Expenses covered by ${contributor.name}`, title: `Expenses covered by ${contributor.name}`,
description: this.description, description: this.description,
url: this.url, url: this.url,
@@ -2,7 +2,8 @@
<label> <label>
<p class="label">Contributor:</p> <p class="label">Contributor:</p>
<p> <p>
<select id="contributor" required {{on "change" this.updateContributor}}> <select required {{on "change" this.updateContributor}}>
<option value="" selected disabled hidden></option>
{{#each this.contributors as |contributor|}} {{#each this.contributors as |contributor|}}
<option value={{contributor.id}} selected={{eq this.contributorId contributor.id}}>{{contributor.name}}</option> <option value={{contributor.id}} selected={{eq this.contributorId contributor.id}}>{{contributor.name}}</option>
{{/each}} {{/each}}
@@ -14,7 +15,6 @@
<p class="label">Total amount (BTC):</p> <p class="label">Total amount (BTC):</p>
<p> <p>
<Input @type="text" <Input @type="text"
@name="total-btc"
@placeholder="0.0015" @placeholder="0.0015"
@value={{this.total}} @value={{this.total}}
@required={{true}} @required={{true}}
@@ -50,9 +50,7 @@
<p class="actions"> <p class="actions">
<button {{on "click" this.showExpenseForm}} <button {{on "click" this.showExpenseForm}}
id="add-another-item" class="green small" type="button"> class="green small" type="button">+ Add another item</button>
+ Add another item
</button>
</p> </p>
{{else}} {{else}}
<p>No line items yet.</p> <p>No line items yet.</p>
+2 -4
View File
@@ -1,5 +1,3 @@
{{#if this.isConfirmed}} {{#unless this.isConfirmed}}
Confirmed at block <strong>{{@confirmedAtBlock}}</strong> (~ {{this.confirmedInHumanTime}} ago)
{{else}}
Confirming in <strong>{{this.confirmedInBlocks}}</strong> blocks (~ {{this.confirmedInHumanTime}}) Confirming in <strong>{{this.confirmedInBlocks}}</strong> blocks (~ {{this.confirmedInHumanTime}})
{{/if}} {{/unless}}
+13 -38
View File
@@ -1,43 +1,18 @@
import Component from '@glimmer/component'; import Component from '@ember/component';
import { action } from '@ember/object';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class ContributorComponent extends Component { export default Component.extend({
@service router; tagName: '',
@tracked selectedContributorId = null; router: service(),
@tracked showToplistOnly = true;
selectedContributorId: null,
actions: {
openContributorDetails(contributor) {
this.router.transitionTo('dashboard.contributors.show', contributor);
}
get contributorList () {
return this.args.contributorList;
} }
});
get contributorTop10 () {
return this.contributorList ?
this.contributorList.slice(0, 10) : [];
}
get contributors () {
return this.showToplistOnly ?
this.contributorTop10 : this.contributorList;
}
get hiddenContributorsAmount () {
return this.contributorList.length - 10;
}
get showAllButtonText () {
return `Show ${this.hiddenContributorsAmount} more contributors`;
}
@action
openContributorDetails (contributor) {
this.router.transitionTo('dashboard.contributors.show', contributor);
}
@action
showAllContributors () {
this.showToplistOnly = false;
}
}
+1 -8
View File
@@ -2,7 +2,7 @@
<thead> <thead>
</thead> </thead>
<tbody> <tbody>
{{#each this.contributors as |c|}} {{#each @contributorList as |c|}}
<tr role="button" <tr role="button"
onclick={{action "openContributorDetails" c.contributor}} onclick={{action "openContributorDetails" c.contributor}}
class="{{if (is-current-user c.contributor) "current-user"}} {{if (eq c.contributor.id @selectedContributorId) "selected"}}"> class="{{if (is-current-user c.contributor) "current-user"}} {{if (eq c.contributor.id @selectedContributorId) "selected"}}">
@@ -21,12 +21,5 @@
</td> </td>
</tr> </tr>
{{/each}} {{/each}}
{{#if this.showToplistOnly}}
<tr role="button" onclick={{action "showAllContributors"}}>
<td colspan="2">
{{this.showAllButtonText}}
</td>
</tr>
{{/if}}
</tbody> </tbody>
</table> </table>
+1 -1
View File
@@ -5,7 +5,7 @@
<span class="date">{{fmt-date-localized expense.date}}:</span> <span class="date">{{fmt-date-localized expense.date}}:</span>
<span class="title">{{expense.title}}</span> <span class="title">{{expense.title}}</span>
</h4> </h4>
<div class="amount" title="{{fmt-amount-sats-title expense.amountSats}}"> <div class="amount">
{{fmt-fiat-currency expense.amount expense.currency}} {{fmt-fiat-currency expense.amount expense.currency}}
</div> </div>
<p class="description"> <p class="description">
@@ -1,20 +1,10 @@
import Component from '@glimmer/component'; import Component from '@glimmer/component';
import { action } from '@ember/object'; import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import config from 'kredits-web/config/environment'; import config from 'kredits-web/config/environment';
import fmtDateLocalized from 'kredits-web/helpers/fmt-date-localized';
export default class ReimbursementItemComponent extends Component { export default class ReimbursementItemComponent extends Component {
@service kredits; @service kredits;
@tracked showExpenseDetails = false;
constructor(owner, args) {
super(owner, args);
if (this.isUnconfirmed && !this.isVetoed) {
this.showExpenseDetails = true;
}
}
get ipfsGatewayUrl () { get ipfsGatewayUrl () {
return config.ipfs.gatewayUrl; return config.ipfs.gatewayUrl;
@@ -28,37 +18,10 @@ export default class ReimbursementItemComponent extends Component {
return !this.isConfirmed; return !this.isConfirmed;
} }
get isVetoed () {
return this.args.reimbursement.vetoed;
}
get showVetoButton () { get showVetoButton () {
return this.isUnconfirmed && this.kredits.currentUserIsCore; return this.isUnconfirmed && this.kredits.currentUserIsCore;
} }
get showConfirmedIn () {
return !this.isVetoed &&
(this.showExpenseDetails || this.isUnconfirmed);
}
get expenses () {
return this.args.reimbursement.expenses;
}
get expensesDateRange () {
const dates = this.expenses.map(e => e.date).uniq().sort();
let out = fmtDateLocalized.compute(dates.firstObject)
if (dates.length > 1) {
out += ' - ' + fmtDateLocalized.compute(dates.lastObject)
}
return out;
}
@action
toggleExpenseDetails () {
this.showExpenseDetails = !this.showExpenseDetails;
}
@action @action
veto (id) { veto (id) {
this.kredits.vetoReimbursement(id).then(transaction => { this.kredits.vetoReimbursement(id).then(transaction => {
@@ -1,7 +1,6 @@
<li data-reimbursement-id={{@reimbursement.id}} <li data-reimbursement-id={{@reimbursement.id}}
class="{{item-status @reimbursement}}"> class="{{item-status @reimbursement}}">
<p class="meta cursor-pointer" role="button" <p class="meta">
{{on "click" this.toggleExpenseDetails}}>
<span class="recipient"> <span class="recipient">
<UserAvatar @contributor={{@reimbursement.contributor}} /> <UserAvatar @contributor={{@reimbursement.contributor}} />
</span> </span>
@@ -14,17 +13,11 @@
{{sats-to-btc @reimbursement.amount}}</span>&#8239;<span class="symbol">BTC</span> {{sats-to-btc @reimbursement.amount}}</span>&#8239;<span class="symbol">BTC</span>
</p> </p>
{{#if this.showExpenseDetails}}
<ExpenseList @expenses={{@reimbursement.expenses}} /> <ExpenseList @expenses={{@reimbursement.expenses}} />
{{/if}}
<div class="meta"> <div class="meta">
<p> <p class="confirmation-eta">
{{#if this.showConfirmedIn}}
<ConfirmedIn @confirmedAtBlock={{@reimbursement.confirmedAt}} /> <ConfirmedIn @confirmedAtBlock={{@reimbursement.confirmedAt}} />
{{else}}
{{#unless this.isVetoed}}{{this.expensesDateRange}}{{/unless}}
{{/if}}
</p> </p>
<p class="actions"> <p class="actions">
<a href="{{this.ipfsGatewayUrl}}/{{@reimbursement.ipfsHash}}" <a href="{{this.ipfsGatewayUrl}}/{{@reimbursement.ipfsHash}}"
@@ -1,4 +1,4 @@
<ul class="item-list collapsible spaced reimbursement-list {{if @loading 'loading'}}"> <ul class="item-list spaced reimbursement-list {{if @loading 'loading'}}">
{{#each this.itemsSorted as |item|}} {{#each this.itemsSorted as |item|}}
<ReimbursementItem @reimbursement={{item}} /> <ReimbursementItem @reimbursement={{item}} />
{{/each}} {{/each}}
-16
View File
@@ -1,26 +1,10 @@
import Controller from '@ember/controller'; import Controller from '@ember/controller';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed'; import { alias } from '@ember/object/computed';
import { action } from '@ember/object';
export default class BudgetController extends Controller { export default class BudgetController extends Controller {
@service kredits; @service kredits;
@service router;
@alias('kredits.reimbursementsUnconfirmed') reimbursementsUnconfirmed; @alias('kredits.reimbursementsUnconfirmed') reimbursementsUnconfirmed;
@alias('kredits.reimbursementsConfirmed') reimbursementsConfirmed; @alias('kredits.reimbursementsConfirmed') reimbursementsConfirmed;
@alias('kredits.currentUserIsCore') currentUserIsCore;
@action
addReimbursement () {
if (!this.kredits.currentUser) {
window.alert('You need to connect your RSK account first.');
return false;
}
if (!this.kredits.currentUserIsCore) {
window.alert('Only core contributors can submit reimbursements.');
return false;
}
this.router.transitionTo('reimbursements.new');
}
} }
+1 -4
View File
@@ -25,10 +25,7 @@ export default Controller.extend({
kreditsToplistSorting: computed('showUnconfirmedKredits', function(){ kreditsToplistSorting: computed('showUnconfirmedKredits', function(){
return this.showUnconfirmedKredits ? ['amountTotal:desc'] : ['amountConfirmed:desc']; return this.showUnconfirmedKredits ? ['amountTotal:desc'] : ['amountConfirmed:desc'];
}), }),
kreditsToplist: computed('kreditsByContributor', function(){ kreditsToplist: sort('kreditsByContributor', 'kreditsToplistSorting'),
return this.kreditsByContributor.filter(c => c.amountTotal > 0);
}),
kreditsToplistSorted: sort('kreditsToplist', 'kreditsToplistSorting'),
showUnconfirmedKredits: true, showUnconfirmedKredits: true,
hideUnconfirmedKredits: not('showUnconfirmedKredits'), hideUnconfirmedKredits: not('showUnconfirmedKredits'),
-11
View File
@@ -1,11 +0,0 @@
import { helper } from '@ember/component/helper';
export default helper(function fmtAmountSatsTitle(params) {
const amountSats = params[0];
if (typeof amountSats === 'number' && amountSats > 0) {
return `${amountSats} sats`;
} else {
return '';
}
});
+1 -1
View File
@@ -1,7 +1,7 @@
import { helper } from '@ember/component/helper'; import { helper } from '@ember/component/helper';
import getLocale from 'kredits-web/utils/get-locale'; import getLocale from 'kredits-web/utils/get-locale';
export default helper(function fmtDateLocalized(dateStr) { export default helper(function(dateStr) {
const date = new Date(dateStr); const date = new Date(dateStr);
const locale = getLocale(); const locale = getLocale();
return new Intl.DateTimeFormat(locale).format(date); return new Intl.DateTimeFormat(locale).format(date);
+3 -7
View File
@@ -2,14 +2,10 @@ import { helper } from '@ember/component/helper';
export default helper(function fmtFiatCurrency(params) { export default helper(function fmtFiatCurrency(params) {
const lang = navigator.language || navigator.userLanguage; 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, { const formatter = new Intl.NumberFormat(lang, {
style: 'currency', currency, currencyDisplay: 'code' style: 'currency',
currency: params[1] || 'EUR',
currencyDisplay: 'code'
}) })
return formatter.format(params[0]); return formatter.format(params[0]);
}); });
+3
View File
@@ -30,5 +30,8 @@ export default class BudgetRoute extends Route {
} }
schedule('afterRender', this.kredits.fetchMissingReimbursements, schedule('afterRender', this.kredits.fetchMissingReimbursements,
this.kredits.fetchMissingReimbursements.perform); this.kredits.fetchMissingReimbursements.perform);
schedule('afterRender', this.kredits.syncReimbursementEvents,
this.kredits.syncReimbursementEvents.perform);
} }
} }
+1 -1
View File
@@ -42,7 +42,7 @@ export default class CommunityFundsService extends Service {
// Format and round the approximate USD value // Format and round the approximate USD value
const lang = navigator.language || navigator.userLanguage; const lang = navigator.language || navigator.userLanguage;
const balanceUSD = (res.confirmed_balance / 100000000) * this.exchangeRates.USD; const balanceUSD = (res.confirmed_balance / 100000000) * this.exchangeRates.btcusd;
res.balanceUSD = Math.round(balanceUSD).toLocaleString(lang); res.balanceUSD = Math.round(balanceUSD).toLocaleString(lang);
this.balances.pushObject({ this.balances.pushObject({
+5 -23
View File
@@ -4,7 +4,6 @@ import config from 'kredits-web/config/environment';
// Need to go through proxy for CORS headers // Need to go through proxy for CORS headers
const bitstampBaseUrl = `${config.corsProxy}https://www.bitstamp.net/api/v2`; const bitstampBaseUrl = `${config.corsProxy}https://www.bitstamp.net/api/v2`;
const kosmosBtcPriceBaseUrl = "https://storage.kosmos.org/kosmos/public/btc-price";
async function fetchFromBitstamp(currencyPair) { async function fetchFromBitstamp(currencyPair) {
try { try {
@@ -17,12 +16,11 @@ async function fetchFromBitstamp(currencyPair) {
} }
export default class ExchangeRatesService extends Service { export default class ExchangeRatesService extends Service {
@tracked EUR = 0; @tracked btceur = 0;
@tracked USD = 0; @tracked btcusd = 0;
@tracked historic = {};
get exchangeRatesLoaded () { get exchangeRatesLoaded () {
return (this.EUR !== 0) && (this.USD !== 0); return (this.btceur !== 0) && (this.btcusd !== 0);
} }
async fetchRates (source='bitstamp') { async fetchRates (source='bitstamp') {
@@ -30,24 +28,8 @@ export default class ExchangeRatesService extends Service {
switch(source) { switch(source) {
case 'bitstamp': case 'bitstamp':
this.EUR = await fetchFromBitstamp('btceur'); this.btceur = await fetchFromBitstamp('btceur');
this.USD = await fetchFromBitstamp('btcusd'); this.btcusd = 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);
}
} }
} }
} }
+27
View File
@@ -780,5 +780,32 @@ export default Service.extend({
this.contributors this.contributors
.findBy('address', to) .findBy('address', to)
.incrementProperty('balance', value); .incrementProperty('balance', value);
},
syncReimbursementEvents: task(function * () {
yield this.fetchEvents(
'Reimbursement', // contract
'ReimbursementAdded', // event
0,
// this.kredits.currentBlock - (2*60*24*14), // from block
this.currentBlock // to block
);
}).group('syncTaskGroup'),
async fetchEvents(contractName, eventName, fromBlock, toBlock) {
const contract = this.kredits[contractName].contract;
const eventFilter = contract.filters[eventName]();
const filterOptions = { fromBlock, toBlock };
console.debug(contract, eventFilter, filterOptions);
contract.queryFilter(eventFilter)
.then(events => {
events.forEach(event => {
console.debug("Event:", event.args.creator, event.args.key, event.args.value);
});
}).catch(e => {
console.error(e);
});
} }
}); });
-10
View File
@@ -16,16 +16,6 @@ ul.item-list {
} }
} }
&.collapsible {
> li {
border-left: 1px solid transparent;
&:hover {
border-left: 1px solid $blue;
}
}
}
&.loading { &.loading {
@include loading-border-top; @include loading-border-top;
-4
View File
@@ -45,10 +45,6 @@ a {
color: $primary-color; color: $primary-color;
} }
.cursor-pointer {
cursor: pointer;
}
section { section {
h2 { h2 {
font-size: 1.5rem; font-size: 1.5rem;
@@ -43,6 +43,9 @@ ul.reimbursement-list {
flex: 1; flex: 1;
padding: 1.6rem 0 1rem 0; padding: 1.6rem 0 1rem 0;
&.confirmation-eta {
}
&.actions { &.actions {
text-align: right; text-align: right;
} }
+18 -10
View File
@@ -1,6 +1,22 @@
<main id="budget"> <main id="budget">
<div id="aside"> <div id="aside">
<!-- <section id="main&#45;nav"> -->
<!-- <header> -->
<!-- <h2>Budget</h2> -->
<!-- </header> -->
<!-- <div class="content"> -->
<!-- <ul> -->
<!-- <li> -->
<!-- <LinkTo @route="budget.expenses">Expenses</LinkTo> -->
<!-- </li> -->
<!-- <li> -->
<!-- <a href="#">Rewards</a> -->
<!-- </li> -->
<!-- </ul> -->
<!-- </div> -->
<!-- </section> -->
<section id="funds"> <section id="funds">
<header> <header>
<h2>Community funds</h2> <h2>Community funds</h2>
@@ -17,11 +33,7 @@
<header class="with-nav"> <header class="with-nav">
<h2>Proposed Reimbursements</h2> <h2>Proposed Reimbursements</h2>
<nav> <nav>
<button type="button" class="button small green" <LinkTo @route="reimbursements.new" @title="Submit a reimbursement" class="button small green">add</LinkTo>
title="Submit a reimbursement"
{{on "click" this.addReimbursement}}>
add
</button>
</nav> </nav>
</header> </header>
<div class="content"> <div class="content">
@@ -35,11 +47,7 @@
<header class="with-nav"> <header class="with-nav">
<h2>Confirmed Reimbursements</h2> <h2>Confirmed Reimbursements</h2>
<nav> <nav>
<button type="button" class="button small green" <LinkTo @route="reimbursements.new" @title="Submit a reimbursement" class="button small green">add</LinkTo>
title="Submit a reimbursement"
{{on "click" this.addReimbursement}}>
add
</button>
</nav> </nav>
</header> </header>
<div class="content"> <div class="content">
+1 -1
View File
@@ -11,7 +11,7 @@
{{/if}} {{/if}}
</header> </header>
<div class="content"> <div class="content">
<ContributorList @contributorList={{this.kreditsToplistSorted}} <ContributorList @contributorList={{this.kreditsToplist}}
@showUnconfirmedKredits={{this.showUnconfirmedKredits}} @showUnconfirmedKredits={{this.showUnconfirmedKredits}}
@selectedContributorId={{this.selectedContributorId}} @selectedContributorId={{this.selectedContributorId}}
@loading={{this.kredits.syncContributors.isRunning}} /> @loading={{this.kredits.syncContributors.isRunning}} />
-11
View File
@@ -1,11 +0,0 @@
export function floatToBtc(number) {
return Number(number.toFixed(8))
}
export function btcToSats(btc) {
return Math.round(btc * 100_000_000);
}
export function satsToBtc(sats) {
return Math.round((sats / 100_000_000) * 100_000_000) / 100_000_000;
}
-4
View File
@@ -1,4 +0,0 @@
export default function(value) {
const today = new Date().toISOString().split('T')[0];
return value === today;
}
+5 -3
View File
@@ -62,7 +62,9 @@ module.exports = function(environment) {
} }
}, },
corsProxy: 'https://cors.5apps.com/?uri=' corsProxy: 'https://cors.5apps.com/?uri=',
hideVetoedEntriesAfterBlocks: 5760 // 48 hours
}; };
if (environment === 'development') { if (environment === 'development') {
@@ -76,10 +78,10 @@ module.exports = function(environment) {
ENV.githubSignupUrl = 'http://localhost:8888/kredits/signup/github'; ENV.githubSignupUrl = 'http://localhost:8888/kredits/signup/github';
ENV.ipfs = { ENV.ipfs = {
host: '10.1.1.198', host: 'localhost',
port: '5001', port: '5001',
protocol: 'http', protocol: 'http',
gatewayUrl: 'http://10.1.1.198:9090/ipfs' gatewayUrl: 'http://localhost:8080/ipfs'
}; };
// Uncomment if you want to use local akkounts // Uncomment if you want to use local akkounts
+19 -29
View File
@@ -1,12 +1,12 @@
{ {
"name": "kredits-web", "name": "kredits-web",
"version": "2.3.0", "version": "2.1.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "kredits-web", "name": "kredits-web",
"version": "2.3.0", "version": "2.1.1",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.19.1", "@babel/eslint-parser": "^7.19.1",
@@ -14,7 +14,7 @@
"@ember/optional-features": "^1.3.0", "@ember/optional-features": "^1.3.0",
"@glimmer/component": "^1.0.0", "@glimmer/component": "^1.0.0",
"@glimmer/tracking": "^1.0.0", "@glimmer/tracking": "^1.0.0",
"@kredits/contracts": "^7.5.0", "@kredits/contracts": "^7.3.0",
"babel-preset-es2015": "^6.22.0", "babel-preset-es2015": "^6.22.0",
"broccoli-asset-rev": "^3.0.0", "broccoli-asset-rev": "^3.0.0",
"ember-auto-import": "^1.12.1", "ember-auto-import": "^1.12.1",
@@ -3062,18 +3062,17 @@
} }
}, },
"node_modules/@kosmos/schemas": { "node_modules/@kosmos/schemas": {
"version": "3.2.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@kosmos/schemas/-/schemas-3.2.0.tgz", "dev": true,
"integrity": "sha512-GyWXmWcATcakmEdPOpafdckBgWFqcpSh+tB8nm11VGgtgA94pfoFhKZ3t88WELItKfuP/GFHgMiZmdMB3bSkdQ==", "license": "MIT"
"dev": true
}, },
"node_modules/@kredits/contracts": { "node_modules/@kredits/contracts": {
"version": "7.5.0", "version": "7.3.0",
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.5.0.tgz", "resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.3.0.tgz",
"integrity": "sha512-4Jw6lXn9DfZiTnMtWHwGLS5zhxEJZ2ANfAgcr7tZxqRl7Y0ijpoWvPCA+LkSGqRgKspyiw9+7vSVTtyvAyQbPQ==", "integrity": "sha512-7Bo2LFEqGIK39G54AStas1RWouBOp+r7Vcv2vP1uLbY01Usea8SHvd2OjLP6nFgsQa0n/rto9oremHv5IAylrQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@kosmos/schemas": "^3.2.0", "@kosmos/schemas": "^3.1.0",
"ethers": "^5.4.7", "ethers": "^5.4.7",
"ipfs-http-client": "^56.0.3", "ipfs-http-client": "^56.0.3",
"multihashes": "^4.0.3", "multihashes": "^4.0.3",
@@ -6817,9 +6816,7 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001599", "version": "1.0.30001332",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz",
"integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -6829,12 +6826,9 @@
{ {
"type": "tidelift", "type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite" "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
} }
] ],
"license": "CC-BY-4.0"
}, },
"node_modules/capture-exit": { "node_modules/capture-exit": {
"version": "2.0.0", "version": "2.0.0",
@@ -26068,18 +26062,16 @@
} }
}, },
"@kosmos/schemas": { "@kosmos/schemas": {
"version": "3.2.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@kosmos/schemas/-/schemas-3.2.0.tgz",
"integrity": "sha512-GyWXmWcATcakmEdPOpafdckBgWFqcpSh+tB8nm11VGgtgA94pfoFhKZ3t88WELItKfuP/GFHgMiZmdMB3bSkdQ==",
"dev": true "dev": true
}, },
"@kredits/contracts": { "@kredits/contracts": {
"version": "7.5.0", "version": "7.3.0",
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.5.0.tgz", "resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.3.0.tgz",
"integrity": "sha512-4Jw6lXn9DfZiTnMtWHwGLS5zhxEJZ2ANfAgcr7tZxqRl7Y0ijpoWvPCA+LkSGqRgKspyiw9+7vSVTtyvAyQbPQ==", "integrity": "sha512-7Bo2LFEqGIK39G54AStas1RWouBOp+r7Vcv2vP1uLbY01Usea8SHvd2OjLP6nFgsQa0n/rto9oremHv5IAylrQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@kosmos/schemas": "^3.2.0", "@kosmos/schemas": "^3.1.0",
"ethers": "^5.4.7", "ethers": "^5.4.7",
"ipfs-http-client": "^56.0.3", "ipfs-http-client": "^56.0.3",
"multihashes": "^4.0.3", "multihashes": "^4.0.3",
@@ -29058,9 +29050,7 @@
} }
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001599", "version": "1.0.30001332",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz",
"integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==",
"dev": true "dev": true
}, },
"capture-exit": { "capture-exit": {
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "kredits-web", "name": "kredits-web",
"version": "2.3.0", "version": "2.1.1",
"private": true, "private": true,
"description": "Contribution dashboard of the Kosmos project", "description": "Contribution dashboard of the Kosmos project",
"repository": "https://github.com/67P/kredits-web", "repository": "https://github.com/67P/kredits-web",
@@ -30,7 +30,7 @@
"@ember/optional-features": "^1.3.0", "@ember/optional-features": "^1.3.0",
"@glimmer/component": "^1.0.0", "@glimmer/component": "^1.0.0",
"@glimmer/tracking": "^1.0.0", "@glimmer/tracking": "^1.0.0",
"@kredits/contracts": "^7.5.0", "@kredits/contracts": "^7.3.0",
"babel-preset-es2015": "^6.22.0", "babel-preset-es2015": "^6.22.0",
"broccoli-asset-rev": "^3.0.0", "broccoli-asset-rev": "^3.0.0",
"ember-auto-import": "^1.12.1", "ember-auto-import": "^1.12.1",
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+4 -4
View File
@@ -8,10 +8,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="kredits-web/config/environment" content="%7B%22modulePrefix%22%3A%22kredits-web%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_DEFAULT_ASYNC_OBSERVERS%22%3Atrue%2C%22_JQUERY_INTEGRATION%22%3Afalse%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22name%22%3A%22kredits-web%22%2C%22version%22%3A%222.3.0%2B66e1adc7%22%7D%2C%22web3ProviderUrl%22%3A%22https%3A%2F%2Frsk-testnet.kosmos.org%22%2C%22web3ChainId%22%3A31%2C%22web3NetworkName%22%3A%22RSK%20Testnet%22%2C%22githubConnectUrl%22%3A%22https%3A%2F%2Fhal8000.kosmos.chat%2Fkredits%2Fsignup%2Fconnect%2Fgithub%22%2C%22githubSignupUrl%22%3A%22https%3A%2F%2Fhal8000.kosmos.chat%2Fkredits%2Fsignup%2Fgithub%22%2C%22ipfs%22%3A%7B%22host%22%3A%22ipfs.kosmos.org%22%2C%22port%22%3A%225444%22%2C%22protocol%22%3A%22https%22%2C%22gatewayUrl%22%3A%22https%3A%2F%2Fipfs.kosmos.org%2Fipfs%22%7D%2C%22tokens%22%3A%7B%22BTC%22%3A%220x2260fac5e5542a773aa44fbcfedf7c193bc2c599%22%7D%2C%22communityFundsAPI%22%3A%7B%22balances%22%3A%7B%22onchain%22%3A%7B%22icon%22%3A%22icon-btc.png%22%2C%22symbol%22%3A%22BTC%22%2C%22description%22%3A%22BTC%20on%20chain%22%2C%22url%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fbtcpay%2Fonchain_btc_balance%22%7D%2C%22lightning%22%3A%7B%22icon%22%3A%22icon-btc-lightning.png%22%2C%22symbol%22%3A%22BTC%22%2C%22description%22%3A%22BTC%20on%20Lightning%20Network%22%2C%22url%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fbtcpay%2Flightning_btc_balance%22%7D%7D%7D%2C%22corsProxy%22%3A%22https%3A%2F%2Fcors.5apps.com%2F%3Furi%3D%22%2C%22exportApplicationGlobal%22%3Afalse%7D" /> <meta name="kredits-web/config/environment" content="%7B%22modulePrefix%22%3A%22kredits-web%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_DEFAULT_ASYNC_OBSERVERS%22%3Atrue%2C%22_JQUERY_INTEGRATION%22%3Afalse%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22name%22%3A%22kredits-web%22%2C%22version%22%3A%222.1.1%2B5c9fbf50%22%7D%2C%22web3ProviderUrl%22%3A%22https%3A%2F%2Frsk-testnet.kosmos.org%22%2C%22web3ChainId%22%3A31%2C%22web3NetworkName%22%3A%22RSK%20Testnet%22%2C%22githubConnectUrl%22%3A%22https%3A%2F%2Fhal8000.kosmos.chat%2Fkredits%2Fsignup%2Fconnect%2Fgithub%22%2C%22githubSignupUrl%22%3A%22https%3A%2F%2Fhal8000.kosmos.chat%2Fkredits%2Fsignup%2Fgithub%22%2C%22ipfs%22%3A%7B%22host%22%3A%22ipfs.kosmos.org%22%2C%22port%22%3A%225444%22%2C%22protocol%22%3A%22https%22%2C%22gatewayUrl%22%3A%22https%3A%2F%2Fipfs.kosmos.org%2Fipfs%22%7D%2C%22tokens%22%3A%7B%22BTC%22%3A%220x2260fac5e5542a773aa44fbcfedf7c193bc2c599%22%7D%2C%22communityFundsAPI%22%3A%7B%22balances%22%3A%7B%22onchain%22%3A%7B%22icon%22%3A%22icon-btc.png%22%2C%22symbol%22%3A%22BTC%22%2C%22description%22%3A%22BTC%20on%20chain%22%2C%22url%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fbtcpay%2Fonchain_btc_balance%22%7D%2C%22lightning%22%3A%7B%22icon%22%3A%22icon-btc-lightning.png%22%2C%22symbol%22%3A%22BTC%22%2C%22description%22%3A%22BTC%20on%20Lightning%20Network%22%2C%22url%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fbtcpay%2Flightning_btc_balance%22%7D%7D%7D%2C%22corsProxy%22%3A%22https%3A%2F%2Fcors.5apps.com%2F%3Furi%3D%22%2C%22exportApplicationGlobal%22%3Afalse%7D" />
<link integrity="" rel="stylesheet" href="/assets/vendor-ca96b2e19fc9f356e3dbad90c9f3f323.css"> <link integrity="" rel="stylesheet" href="/assets/vendor-ca96b2e19fc9f356e3dbad90c9f3f323.css">
<link integrity="" rel="stylesheet" href="/assets/kredits-web-273a3e2096140c611fc6c314653c5122.css"> <link integrity="" rel="stylesheet" href="/assets/kredits-web-950f3a97cf1dfead67fdfdc4f5dc1cfb.css">
@@ -24,8 +24,8 @@
<body> <body>
<script src="/assets/vendor-fe68375ecc84328a68fb6e2dc6c2ffd0.js" integrity="sha256-R9zoGCHpj2nktDrCaA5bsKl5UIzBz3pi8OxcjZUcUXg= sha512-KgK1Q5VBzvVFUa5DEMaexc2VLg337DOyWnvp/3HvNzcjSFwCRG/dCn3x6EMuxULl1lY/rCVJ2ZgZN0K5NwZDkA==" ></script> <script src="/assets/vendor-4d87b3e0995c5bb18e46836a089900a4.js" integrity="sha256-5WmWY05Kd+n98Sw0GwuaWodmDVBZ2yVGGtC/2owVfQE= sha512-tiGPA5zvfhnSC9LPTmpvXJmOu30yhsdPqSiZJMPGmE/ez/xJLMaM29vjs4Cs74cDf6fX4uYSGRIu1KfOyGpJYA==" ></script>
<script src="/assets/kredits-web-ff25bacd2246c053f7629aa0ac30852d.js" integrity="sha256-ZMtyPPTI2FdCZOW2AhZKoSc3V1F8p7eb5paSnXfUUVE= sha512-lbKnfjHisBjgh4AVaSvDb+7zrtfrMd9PhVj3kUW+UREmA9kl3qLaWECHtIfWz4VNPfzQV9xg5P9hQFmcrPe+ig==" ></script> <script src="/assets/kredits-web-5b714ebc501e0789ddba130f2a3f10e1.js" integrity="sha256-jb10J7E1WRUc8DztQgvbdsKXYRHqXTqjbap4CVh2AaM= sha512-dx+d1T+WrZs0qG1J4puW0hZEzG2Qh+d5iU3XXnkfkF8ya3lMp/L1xdfzh697Ca5x3/Gw7+j7Mb/LSPUfWuNCEQ==" ></script>
</body> </body>
@@ -1,58 +1,13 @@
import { module, test } from 'qunit'; import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit'; import { setupRenderingTest } from 'ember-qunit';
import { click, fillIn, render } from '@ember/test-helpers'; import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars'; import { hbs } from 'ember-cli-htmlbars';
import contributors from '../../../fixtures/contributors';
module('Integration | Component | add-reimbursement', function(hooks) { module('Integration | Component | add-reimbursement', function(hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
hooks.beforeEach(function() { test('it works', async function(assert) {
let kredits = this.owner.lookup('service:kredits');
kredits.set('contributors', contributors);
kredits.set('currentUser', contributors.findBy('id', 3));
});
test('Contributor select menu', async function(assert) {
await render(hbs`<AddReimbursement />`); await render(hbs`<AddReimbursement />`);
assert.ok(true);
assert.equal(this.element.querySelectorAll('select#contributor option').length, contributors.length,
'contains correct amount of items');
assert.equal(this.element.querySelector('select#contributor option:checked').value, "3",
'preselects the connected contributor account');
});
test('Adding expense items', async function(assert) {
await render(hbs`<AddReimbursement />`);
assert.dom(this.element).includesText('New expense item');
await fillIn('form input[name="expense-amount"]', '49');
await fillIn('form input[name="expense-title"]', 'Domain kosmos.org (yearly fee)');
await click('form#add-expense-item input[type="submit"]');
assert.equal(this.element.querySelector('input[name="total-eur"]').value, '49',
'updates the total EUR amount');
assert.equal(this.element.querySelector('input[name="total-usd"]').value, '0',
'does not update the total USD amount');
assert.equal(this.element.querySelector('input[name="total-btc"]').value, '0.00534493',
'updates the total BTC amount');
assert.dom(this.element).doesNotIncludeText('New expense item');
await click('button#add-another-item');
await fillIn('form input[name="expense-amount"]', '29');
await fillIn('select[name="expense-currency"]', 'USD');
await fillIn('form input[name="expense-title"]', 'Domain kosmos.social (yearly fee)');
await click('form#add-expense-item input[type="submit"]');
assert.equal(this.element.querySelector('input[name="total-usd"]').value, '29',
'updates the total USD amount');
assert.equal(this.element.querySelector('input[name="total-eur"]').value, '49',
'does not update the total EUR amount');
assert.equal(this.element.querySelector('input[name="total-btc"]').value, '0.00804268',
'updates the total BTC amount');
}); });
}); });
@@ -18,12 +18,5 @@ module('Integration | Helper | fmt-fiat-currency', function(hooks) {
await render(hbs`{{fmt-fiat-currency this.amount 'USD'}}`); await render(hbs`{{fmt-fiat-currency this.amount 'USD'}}`);
assert.ok(this.element.textContent.trim().match(/USD/), assert.ok(this.element.textContent.trim().match(/USD/),
'using defined currency when given'); '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,4 +39,12 @@ module('Unit | Component | add-reimbursement', function(hooks) {
assert.equal(component.totalEUR, '71'); assert.equal(component.totalEUR, '71');
assert.equal(component.totalUSD, '59'); 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');
});
}); });
+29 -31
View File
@@ -1,31 +1,29 @@
import { isEmpty } from '@ember/utils'; // import { isEmpty, isPresent } from '@ember/utils';
import { module, test } from 'qunit'; // import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit'; // import { setupTest } from 'ember-qunit';
import Contributor from 'kredits-web/models/contributor'; // import Contributor from 'kredits-web/models/contributor';
//
module('Unit | Controller | Dashboard', function(hooks) { // module('Unit | Controller | index', function(hooks) {
setupTest(hooks); // setupTest(hooks);
//
let addFixtures = function(controller) { // let addFixtures = function(controller) {
[ // [
{ github_username: "neo", github_uid: "318", totalKreditsEarned: 10000 }, // { github_username: "neo", github_uid: "318", totalKreditsEarned: 10000 },
{ github_username: "morpheus", github_uid: "843", totalKreditsEarned: 15000 }, // { github_username: "morpheus", github_uid: "843", totalKreditsEarned: 15000 },
{ github_username: "trinity", github_uid: "123", totalKreditsEarned: 5000 }, // { github_username: "trinity", github_uid: "123", totalKreditsEarned: 5000 },
{ github_username: "mouse", github_uid: "696", totalKreditsEarned: 0 } // { github_username: "mouse", github_uid: "696", totalKreditsEarned: 0 }
].forEach(fixture => { // ].forEach(fixture => {
controller.get('kredits.contributors').push(Contributor.create(fixture)); // controller.get('kredits.contributors').push(Contributor.create(fixture));
}); // });
}; // };
//
test('kreditsToplistSorted()', function(assert) { // test('doesn\'t contain people with 0 balance', function(assert) {
const controller = this.owner.lookup('controller:dashboard'); // let controller = this.owner.lookup('controller:index');
addFixtures(controller); // addFixtures(controller);
//
const kreditsToplistSorted = controller.get('kreditsToplistSorted'); // let contributorsSorted = controller.get('contributorsSorted');
//
assert.equal(kreditsToplistSorted.length, 3, // assert.ok(isPresent(contributorsSorted.findBy('github_username', 'neo')));
'contains all contributors with kredits'); // assert.ok(isEmpty(contributorsSorted.findBy('github_username', 'mouse')));
assert.ok(isEmpty(kreditsToplistSorted.findBy('github_username', 'mouse')), // });
'does not contain contributors with 0 kredits'); // });
});
});
+2 -2
View File
@@ -7,7 +7,7 @@ module('Unit | Service | exchange-rates', function(hooks) {
test('#fetchRates', async function(assert) { test('#fetchRates', async function(assert) {
let service = this.owner.lookup('service:exchange-rates'); let service = this.owner.lookup('service:exchange-rates');
await service.fetchRates(); await service.fetchRates();
assert.equal(service.EUR, 9167.57, 'fetches BTCEUR from Bitstamp'); assert.equal(service.btceur, 9167.57, 'fetches BTCEUR from Bitstamp');
assert.equal(service.USD, 10749.70, 'fetches BTCUSD from Bitstamp'); assert.equal(service.btcusd, 10749.70, 'fetches BTCUSD from Bitstamp');
}); });
}); });
-16
View File
@@ -1,16 +0,0 @@
import { floatToBtc, btcToSats, satsToBtc } from 'kredits-web/utils/btc-conversions';
import { module, test } from 'qunit';
module('Unit | Utility | btc-conversions', function() {
test('floatToBtc', function(assert) {
assert.equal(floatToBtc(0.001429007), 0.00142901);
});
test('btcToSats', function(assert) {
assert.equal(btcToSats(0.001429007), 142901);
});
test('satsToBtc', function(assert) {
assert.equal(satsToBtc(142901), 0.00142901);
});
});