diff --git a/demo/src/demos/assets/index.js b/demo/src/demos/assets/index.js
new file mode 100644
index 0000000000..adde2a6d7c
--- /dev/null
+++ b/demo/src/demos/assets/index.js
@@ -0,0 +1,197 @@
+// @flow
+import React, { Component, useEffect, useState, useMemo } from "react";
+import ReactTable from "react-table";
+import { BigNumber } from "bignumber.js";
+import uniqWith from "lodash/uniqWith";
+import {
+ listTokens,
+ listCryptoCurrencies,
+ isCurrencySupported,
+ getCryptoCurrencyById,
+ getFiatCurrencyByTicker,
+ useCurrenciesByMarketcap,
+ useMarketcapTickers,
+ formatCurrencyUnit
+} from "@ledgerhq/live-common/lib/currencies";
+import {
+ getDailyRatesBatched,
+ formatCounterValueDay
+} from "@ledgerhq/live-common/lib/countervalues";
+
+const usdFiat = getFiatCurrencyByTicker("USD");
+const bitcoin = getCryptoCurrencyById("bitcoin");
+const ethereum = getCryptoCurrencyById("ethereum");
+
+const getRates = getDailyRatesBatched(50);
+
+const columns = [
+ {
+ Header: "Live?",
+ width: 80,
+ accessor: "livesupport"
+ },
+ {
+ Header: "type",
+ width: 120,
+ accessor: "typeText"
+ },
+ {
+ Header: "Name",
+ accessor: "name"
+ },
+ {
+ Header: "Ticker",
+ accessor: "ticker",
+ width: 100
+ },
+ {
+ Header: "extra",
+ id: "extra",
+ accessor: token =>
+ token.type === "TokenCurrency" ? (
+
+ {token.contractAddress}
+
+ ) : (
+ "coinType=" + token.coinType
+ )
+ },
+ {
+ id: "countervalue",
+ Header: p => {
+ const data = p.data.map(d => d._original);
+ const supported = data.filter(d => d.countervalueStatus === "yes");
+ const withExchange = data.filter(d => d.exchange);
+ const percentageSupport = supported.length / data.length;
+ const realPercentageSupport = withExchange.length / data.length;
+ return (
+
+
countervalue
+
+ {supported.length} have marketcap (
+ {Math.floor(percentageSupport * 1000) / 10}%)
+
+
+ {withExchange.length} supported (
+ {Math.floor(realPercentageSupport * 1000) / 10}%)
+
+
+ );
+ },
+ accessor: "countervalueText"
+ }
+];
+
+const counterpartFor = c =>
+ c === bitcoin ? usdFiat : c.type === "CryptoCurrency" ? bitcoin : ethereum;
+
+const Assets = () => {
+ const tokens = listTokens();
+ const currencies = listCryptoCurrencies();
+ const all = useMemo(() => currencies.concat(tokens), [tokens, currencies]);
+ const tickers = useMarketcapTickers() || [];
+ const [rates, setRates] = useState({});
+ const byMarketcap = useCurrenciesByMarketcap(all);
+ const data = byMarketcap.map(t => {
+ let countervalueStatus = "no";
+ let loading = false;
+ let exchange;
+ let formatted = "";
+ if (t.disableCountervalue) {
+ countervalueStatus = "disabled";
+ } else if (tickers.includes(t.ticker)) {
+ countervalueStatus = "yes";
+ const counter = counterpartFor(t);
+ if (rates[counter.ticker]) {
+ const ratePerExchange = (rates[counter.ticker] || {})[t.ticker] || {};
+ exchange = Object.keys(ratePerExchange)[0];
+ if (exchange) {
+ const latest = ratePerExchange[exchange].latest || 0;
+ formatted = formatCurrencyUnit(
+ counter.units[0],
+ BigNumber(latest).times(10 ** t.units[0].magnitude),
+ {
+ showCode: true
+ }
+ );
+ }
+ } else {
+ loading = true;
+ }
+ }
+ const countervalueText =
+ countervalueStatus !== "yes"
+ ? countervalueStatus
+ : loading
+ ? "..."
+ : exchange
+ ? exchange + " @ " + formatted
+ : "no exchange found";
+ const livesupport =
+ t.type === "TokenCurrency" || isCurrencySupported(t) ? "yes" : "no";
+ return {
+ ...t,
+ typeText:
+ t.type === "TokenCurrency"
+ ? "token on " + t.parentCurrency.name
+ : "coin",
+ countervalueStatus,
+ countervalueText,
+ exchange,
+ loading,
+ livesupport
+ };
+ });
+
+ useEffect(() => {
+ if (!tickers) return;
+ const afterDay = formatCounterValueDay(new Date());
+ getRates(
+ () => window.LEDGER_CV_API,
+ uniqWith(
+ all
+ .filter(c => tickers.includes(c.ticker))
+ .map(from => ({
+ from: from.ticker,
+ to: counterpartFor(from).ticker,
+ afterDay
+ })),
+ (a, b) => a.from === b.from && a.to === b.to
+ )
+ ).then(setRates);
+ }, [tickers, all]);
+
+ return (
+
+
+
+ );
+};
+
+export default class Demo extends Component<{}> {
+ static demo = {
+ title: "Assets",
+ url: "/assets"
+ };
+ render() {
+ return ;
+ }
+}
diff --git a/demo/src/demos/index.js b/demo/src/demos/index.js
index 07f527ccc9..412edb66b5 100644
--- a/demo/src/demos/index.js
+++ b/demo/src/demos/index.js
@@ -9,7 +9,7 @@ import explorers from "./explorers";
import apps from "./apps";
import Partners from "./Partners";
import erc20 from "./erc20";
-import tokens from "./tokens";
+import assets from "./assets";
export default {
Countervalues,
@@ -23,5 +23,5 @@ export default {
explorers,
erc20,
apps,
- tokens
+ assets
};
diff --git a/demo/src/demos/tokens/index.js b/demo/src/demos/tokens/index.js
deleted file mode 100644
index c900f61558..0000000000
--- a/demo/src/demos/tokens/index.js
+++ /dev/null
@@ -1,165 +0,0 @@
-// @flow
-import React, { Component, useEffect, useState } from "react";
-import ReactTable from "react-table";
-import uniq from "lodash/uniq";
-import {
- listTokens,
- useCurrenciesByMarketcap,
- useMarketcapTickers
-} from "@ledgerhq/live-common/lib/currencies";
-import {
- getDailyRatesBatched,
- formatCounterValueDay
-} from "@ledgerhq/live-common/lib/countervalues";
-
-const getRates = getDailyRatesBatched(50);
-
-const columns = [
- {
- Header: "by marketcap",
- accessor: null,
- maxWidth: 200
- },
- {
- Header: "Name",
- accessor: "name"
- },
- {
- Header: "Ticker",
- accessor: "ticker"
- },
- {
- Header: "Smart contract address",
- id: "contractAddress",
- accessor: token => (
-
- {token.contractAddress}
-
- )
- },
- {
- id: "countervalue",
- Header: p => {
- const data = p.data.map(d => d._original);
- const supported = data.filter(d => d.countervalueStatus === "yes");
- const withExchange = data.filter(d => d.exchange && d.ethValue);
- const percentageSupport = supported.length / data.length;
- const realPercentageSupport = withExchange.length / data.length;
-
- return (
-
-
countervalue
-
- {supported.length} have marketcap (
- {Math.floor(percentageSupport * 1000) / 10}%)
-
-
- {withExchange.length} supported against ETH (
- {Math.floor(realPercentageSupport * 1000) / 10}%)
-
-
- );
- },
- accessor: "countervalueText"
- }
-];
-
-const Tokens = () => {
- const tokens = listTokens();
- const tickers = useMarketcapTickers() || [];
- const [rates, setRates] = useState({});
- const byMarketcap = useCurrenciesByMarketcap(tokens);
- const data = byMarketcap.map(t => {
- let countervalueStatus = "no";
- let loading = false;
- let exchange;
- let ethValue;
- if (t.disableCountervalue) {
- countervalueStatus = "disabled";
- } else if (tickers.includes(t.ticker)) {
- countervalueStatus = "yes";
- if (rates.ETH) {
- const ratePerExchange = (rates.ETH || {})[t.ticker] || {};
- exchange = Object.keys(ratePerExchange)[0];
- if (exchange) {
- const latest = ratePerExchange[exchange].latest || 0;
- const mul = 10 ** (t.units[0].magnitude - 18);
- ethValue = latest * mul;
- }
- } else {
- loading = true;
- }
- }
- const countervalueText =
- countervalueStatus +
- (countervalueStatus !== "yes"
- ? ""
- : loading
- ? "..."
- : exchange
- ? " @" +
- exchange +
- " Ξ" +
- (ethValue || 0).toLocaleString("en", {
- minimumFractionDigits: 0,
- maximumFractionDigits: 8
- })
- : " but no exchange");
- return {
- ...t,
- countervalueStatus,
- countervalueText,
- ethValue,
- exchange,
- loading
- };
- });
-
- useEffect(() => {
- if (!tickers) return;
- getRates(
- () => window.LEDGER_CV_API,
- uniq(tickers)
- .filter(ticker => tokens.some(t => t.ticker === ticker))
- .map(from => ({
- from,
- to: "ETH",
- afterDay: formatCounterValueDay(new Date())
- }))
- ).then(setRates);
- }, [tickers, tokens]);
-
- return (
-
-
-
- );
-};
-
-export default class Demo extends Component<{}> {
- static demo = {
- title: "Tokens",
- url: "/Tokens"
- };
- render() {
- return ;
- }
-}