From 08cbc64842074aedc59eef2ad386ede4f009538b Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Tue, 27 Jun 2017 15:36:24 -0500 Subject: [PATCH 01/74] receivingAddress is empty string in exchange reducer initial state --- src/client/exchange/reducers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client/exchange/reducers.js b/src/client/exchange/reducers.js index 5ee1208..5440ebe 100644 --- a/src/client/exchange/reducers.js +++ b/src/client/exchange/reducers.js @@ -8,6 +8,7 @@ const initialState: State = { from: 'ETH', to: 'WINGS', amount: '', + receivingAddress: '', isFetchingQuote: false, didInvalidateQuote: false, isFetchingLimit: false, From df45dfbf170458685301d2fb30e895ad81e27c62 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Mon, 26 Jun 2017 18:04:37 -0500 Subject: [PATCH 02/74] listen to getCurrency in selectICOsWithRecentStats selector --- src/client/rankings/selectors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/rankings/selectors.js b/src/client/rankings/selectors.js index aed6420..a4151ee 100644 --- a/src/client/rankings/selectors.js +++ b/src/client/rankings/selectors.js @@ -95,7 +95,7 @@ export const selectFilteredICOs = createSelector( * Append recent stats to ICOs */ export const selectICOsWithRecentStats = createSelector( - [selectFilteredICOs, getRecentPrices], appendRecentStats + [selectFilteredICOs, getRecentPrices, getCurrency], appendRecentStats ); From e7b3a63ce3f3f94a71928111f595a383e7fa1273 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Mon, 26 Jun 2017 18:06:46 -0500 Subject: [PATCH 03/74] make recentPrices reflect current currency --- src/client/rankings/lib/appendRecentStats.js | 32 ++++++-------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/client/rankings/lib/appendRecentStats.js b/src/client/rankings/lib/appendRecentStats.js index 32dcd61..4f14206 100644 --- a/src/client/rankings/lib/appendRecentStats.js +++ b/src/client/rankings/lib/appendRecentStats.js @@ -20,42 +20,28 @@ type RecentPrice = { export default function appendRecentStats( icos: ICO[], - recentPrices: RecentPrice[] + recentPrices: RecentPrice[], + currency: string ) { - let eth = recentPrices.find(r => r.symbol === 'ETH'); - let btc = recentPrices.find(r => r.symbol === 'BTC'); - - eth = eth && eth.recent_prices; - btc = btc && btc.recent_prices; - return icos.map((ico) => { const { price_usd: icoPrice, symbol } = ico; - const recent = recentPrices.find(r => r.symbol === symbol); + const recent = currency === 'USD' + ? recentPrices.find(r => r.symbol === symbol) + : recentPrices.find(r => r.symbol === currency) const data = recent && recent.recent_prices; - return { ...ico, - recentStats: data && calculateRecentStats(data, icoPrice, eth, btc) + recentStats: data && calculateRecentStats(data, icoPrice) }; }); } function calculateRecentStats( recent: $RecentPrices, - currPrice: number, - eth, - btc + currPrice: number ) { return { - prices: { - usd: recent, - eth: mapValues(recent, (v, k) => eth && (v / eth[k])), - btc: mapValues(recent, (v, k) => btc && (v / btc[k])) - }, - roi: { - day: ROI(recent.day, currPrice), - week: ROI(recent.week, currPrice), - month: ROI(recent.month, currPrice) - } + prices: recent, + roi: mapValues(recent, (v, k) => ROI(v, currPrice)) }; } From a0d4cd50a4a3f50b90a6a2ce00853d9f64aa9d01 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Mon, 26 Jun 2017 18:14:14 -0500 Subject: [PATCH 04/74] make icoPrice currency specific in appendRecentStats --- src/client/rankings/lib/appendRecentStats.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/client/rankings/lib/appendRecentStats.js b/src/client/rankings/lib/appendRecentStats.js index 4f14206..9261331 100644 --- a/src/client/rankings/lib/appendRecentStats.js +++ b/src/client/rankings/lib/appendRecentStats.js @@ -24,7 +24,10 @@ export default function appendRecentStats( currency: string ) { return icos.map((ico) => { - const { price_usd: icoPrice, symbol } = ico; + const priceKey = currency === 'USD' + ? 'price_usd' + : `${currency.toLowerCase()}_price_usd` + const { [priceKey]: icoPrice, symbol } = ico; const recent = currency === 'USD' ? recentPrices.find(r => r.symbol === symbol) : recentPrices.find(r => r.symbol === currency) From 09a505436fafe91381e1cf7a29659422bd632434 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Mon, 26 Jun 2017 20:39:59 -0500 Subject: [PATCH 05/74] convert currPrice to correct currency when not USD --- src/client/rankings/lib/appendRecentStats.js | 28 +++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/client/rankings/lib/appendRecentStats.js b/src/client/rankings/lib/appendRecentStats.js index 9261331..b740b3b 100644 --- a/src/client/rankings/lib/appendRecentStats.js +++ b/src/client/rankings/lib/appendRecentStats.js @@ -24,17 +24,27 @@ export default function appendRecentStats( currency: string ) { return icos.map((ico) => { - const priceKey = currency === 'USD' - ? 'price_usd' - : `${currency.toLowerCase()}_price_usd` - const { [priceKey]: icoPrice, symbol } = ico; - const recent = currency === 'USD' - ? recentPrices.find(r => r.symbol === symbol) - : recentPrices.find(r => r.symbol === currency) - const data = recent && recent.recent_prices; + const { price_usd: symbolPrice, symbol } = ico; + const recent = recentPrices.find(r => r.symbol === symbol) + + let data + let currPrice + + if (currency === 'USD') { + currPrice = symbolPrice + data = recent && recent.recent_prices + } else { + const currencyPrice = ico[`${currency.toLowerCase()}_price_usd`] + const currencyRecent = recentPrices.find(r => r.symbol === currency) + const symbolPriceData = recent && recent.recent_prices + const currencyPriceData = currencyRecent && currencyRecent.recent_prices + currPrice = symbolPrice / currencyPrice + data = mapValues(currencyPriceData, (v, k) => symbolPriceData[k] && (symbolPriceData[k] / v)) + } + return { ...ico, - recentStats: data && calculateRecentStats(data, icoPrice) + recentStats: data && calculateRecentStats(data, currPrice) }; }); } From 267a7b3d61ee46cbd5edae391d5479c9f9b64a96 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Tue, 27 Jun 2017 03:30:29 -0700 Subject: [PATCH 06/74] :shirt: Fix lint errors --- src/client/rankings/lib/appendRecentStats.js | 29 +++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/client/rankings/lib/appendRecentStats.js b/src/client/rankings/lib/appendRecentStats.js index b740b3b..6305964 100644 --- a/src/client/rankings/lib/appendRecentStats.js +++ b/src/client/rankings/lib/appendRecentStats.js @@ -4,7 +4,8 @@ import mapValues from 'lodash/mapValues'; type ICO = { ticker: string, - price_usd: number + price_usd: number, + symbol: string }; type $RecentPrices = { @@ -25,21 +26,23 @@ export default function appendRecentStats( ) { return icos.map((ico) => { const { price_usd: symbolPrice, symbol } = ico; - const recent = recentPrices.find(r => r.symbol === symbol) - - let data - let currPrice + const recent = recentPrices.find(r => r.symbol === symbol); + let data; + let currPrice; if (currency === 'USD') { - currPrice = symbolPrice - data = recent && recent.recent_prices + currPrice = symbolPrice; + data = recent && recent.recent_prices; } else { - const currencyPrice = ico[`${currency.toLowerCase()}_price_usd`] - const currencyRecent = recentPrices.find(r => r.symbol === currency) - const symbolPriceData = recent && recent.recent_prices - const currencyPriceData = currencyRecent && currencyRecent.recent_prices - currPrice = symbolPrice / currencyPrice - data = mapValues(currencyPriceData, (v, k) => symbolPriceData[k] && (symbolPriceData[k] / v)) + const currencyPrice = ico[`${currency.toLowerCase()}_price_usd`]; + const currencyRecent = recentPrices.find(r => r.symbol === currency); + const symbolPriceData = recent && recent.recent_prices; + const currencyPriceData = currencyRecent && currencyRecent.recent_prices; + + currPrice = symbolPrice / currencyPrice; + data = mapValues(currencyPriceData, (v, k) => + symbolPriceData && symbolPriceData[k] && (symbolPriceData[k] / v) + ); } return { From 956750723b11063ee805089d0981d89b65af15de Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Tue, 27 Jun 2017 03:47:50 -0700 Subject: [PATCH 07/74] Recover gracefully from a failed fetch --- src/server/lib/graph-worker.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/server/lib/graph-worker.js b/src/server/lib/graph-worker.js index 567fed9..a0fa96e 100644 --- a/src/server/lib/graph-worker.js +++ b/src/server/lib/graph-worker.js @@ -48,9 +48,10 @@ function recursiveFetch(tokens, i) { .then(checkStatus) .then(res => res.json()) .then(json => saveData(json, ticker, symbol, i)) - .catch(err => - winston.error(`Failed to fetch graph for ${ticker}: ${err.message}`) - ); + .catch(err => { + winston.error(`Failed to fetch graph for ${ticker}: ${err.message}`); + recurseOrFinish(ticker, i, true) + }); } /** @@ -81,15 +82,14 @@ function saveData(json, ticker, symbol, i) { * @param {Number} i * @return {Promise | void} */ -function recurseOrFinish(ticker, i) { +function recurseOrFinish(ticker, i, didSkip = false) { // If we are at the last one, kill recursion. if (i === tokens.length - 1) { winston.info('Finished fetching all graphs'); return; } else { - // Keep recursing. - winston.info(`Fetched graph for ${ticker}`); + !didSkip && winston.info(`Fetched graph for ${ticker}`); return recursiveFetch(tokens, i + 1); } } From 45108a68f5fd40e4daa50c8880fc123ba9c2b830 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Tue, 27 Jun 2017 03:48:04 -0700 Subject: [PATCH 08/74] Update bancor ticker --- src/server/lib/ico-data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/lib/ico-data.js b/src/server/lib/ico-data.js index 390bfa6..4369af4 100644 --- a/src/server/lib/ico-data.js +++ b/src/server/lib/ico-data.js @@ -2,7 +2,7 @@ module.exports = [ { id: 'bancor', - ticker: 'bancor-network', + ticker: 'bancor', is_erc20: true, contract_address: '0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C', name: 'Bancor', From 83448737e43df40024f5f3c82c2fc92aa7edee01 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Tue, 27 Jun 2017 22:58:47 -0500 Subject: [PATCH 09/74] pull getAccount functionality out of identify --- src/client/app/lib/getAccount.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/client/app/lib/getAccount.js diff --git a/src/client/app/lib/getAccount.js b/src/client/app/lib/getAccount.js new file mode 100644 index 0000000..fea318b --- /dev/null +++ b/src/client/app/lib/getAccount.js @@ -0,0 +1,21 @@ +/** + * get the coinbase if user is on a web 3 browser. + */ +import Promise from 'bluebird'; + +export default async function getAccount() { + const web3Enabled = ( + window.web3 && + window.web3.eth && + window.web3.eth.getAccounts + ); + + if (web3Enabled) { + const getAccounts = Promise.promisify(window.web3.eth.getAccounts); + const [account] = await getAccounts(); + + return account; + } + + return false; +} From 3a7dbe5133b21e4e6f6b759e02f606cc8b805b70 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Tue, 27 Jun 2017 22:59:57 -0500 Subject: [PATCH 10/74] refactor identify using getAccount --- src/client/app/lib/identify.js | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/client/app/lib/identify.js b/src/client/app/lib/identify.js index 7bb42a8..982d41a 100644 --- a/src/client/app/lib/identify.js +++ b/src/client/app/lib/identify.js @@ -1,20 +1,13 @@ /** - * get the coinbase if user is on a web 3 browser. + * if user is on a web 3 browser + * identify them in analytics via their coinbase */ -import Promise from 'bluebird'; + import getAccount from './getAccount'; -export default function identify() { - if (window.web3 && window.web3.eth && window.web3.eth.getAccounts) { - const getAccountsAsync = Promise.promisify(window.web3.eth.getAccounts); + export default async function identify() { + const account = await getAccount(); - return getAccountsAsync().then((accounts) => { - const account = accounts[0]; - - if (account) { - window.analytics.identify(account); - } - }); - } - - return false; -} + if (account) { + window.analytics.identify(account); + } + } From 0cf51d40b187e78c54eee1835c66019482e0a561 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Tue, 27 Jun 2017 23:01:50 -0500 Subject: [PATCH 11/74] prefill receivingAddress in GetQuote#componentWillMount --- src/client/exchange/components/GetQuote.jsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/client/exchange/components/GetQuote.jsx b/src/client/exchange/components/GetQuote.jsx index 70f8591..febe15e 100644 --- a/src/client/exchange/components/GetQuote.jsx +++ b/src/client/exchange/components/GetQuote.jsx @@ -10,6 +10,7 @@ import CheckIcon from '~/app/components/CheckIcon'; import GetQuoteColumn from './GetQuoteColumn'; import PoweredByShapeshift from './PoweredByShapeshift'; import { fetchValidateAddress, setReceivingAddress } from '../actions'; +import getAccount from '../../app/lib/getAccount'; type Props = { classes: Object, @@ -26,6 +27,12 @@ class GetQuote extends React.Component { props: Props; state = {}; + async componentWillMount() { + const account = await getAccount(); + + this.props.setReceivingAddress(account || ''); + } + handleChangeReceivingAddress = (event) => { event.persist(); const address = event.target.value; From 393d77bc51cf7bd69f321ce73dde817948018841 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Fri, 21 Jul 2017 09:53:43 -0500 Subject: [PATCH 12/74] getAccount -> getAccounts --- src/client/app/lib/{getAccount.js => getAccounts.js} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename src/client/app/lib/{getAccount.js => getAccounts.js} (81%) diff --git a/src/client/app/lib/getAccount.js b/src/client/app/lib/getAccounts.js similarity index 81% rename from src/client/app/lib/getAccount.js rename to src/client/app/lib/getAccounts.js index fea318b..d337a62 100644 --- a/src/client/app/lib/getAccount.js +++ b/src/client/app/lib/getAccounts.js @@ -12,10 +12,10 @@ export default async function getAccount() { if (web3Enabled) { const getAccounts = Promise.promisify(window.web3.eth.getAccounts); - const [account] = await getAccounts(); + const accounts = await getAccounts(); - return account; + return accounts; } - return false; + return []; } From 1603326c91efdfd0897c4d65854f5ed2475fa485 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Fri, 21 Jul 2017 09:54:50 -0500 Subject: [PATCH 13/74] update lib/identity to use getAccounts --- src/client/app/lib/identify.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/client/app/lib/identify.js b/src/client/app/lib/identify.js index 982d41a..586db35 100644 --- a/src/client/app/lib/identify.js +++ b/src/client/app/lib/identify.js @@ -2,10 +2,11 @@ * if user is on a web 3 browser * identify them in analytics via their coinbase */ - import getAccount from './getAccount'; + import getAccounts from './getAccounts'; export default async function identify() { - const account = await getAccount(); + // take first account + const [account] = await getAccounts(); if (account) { window.analytics.identify(account); From e4439e5c30671e58e331ad34a28e8aa5293f8de6 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Fri, 21 Jul 2017 14:11:50 -0500 Subject: [PATCH 14/74] add types pertaining to account fetching --- src/client/exchange/types.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/client/exchange/types.js b/src/client/exchange/types.js index ee7a396..e17378c 100644 --- a/src/client/exchange/types.js +++ b/src/client/exchange/types.js @@ -27,6 +27,13 @@ export type ReceiveShiftAction = { type: types.RECEIVE_SHIFT, payload: { deposit: string, orderId: string } }; +export type RequestAddressesAction = { + type: types.REQUEST_ADDRESSES +}; +export type ReceiveAddressesAction = { + type: types.RECEIVE_ADDRESSES, + addresses: Array +}; export type SetReceivingAddressAction = { type: types.SET_RECEIVING_ADDRESS, address: string @@ -63,6 +70,8 @@ export type Action = | ReceiveLimitAction | RequestShiftAction | ReceiveShiftAction + | RequestAddressesAction + | ReceiveAddressesAction | SetReceivingAddressAction | RequestValidateAddressAction | ReceiveValidateAddressAction @@ -82,6 +91,8 @@ export type State = { isFetchingLimit: boolean, didInvalidateLimit: boolean, limit?: $Limit, + addresses?: Array, + isFetchingAddresses?: boolean, depositAddress?: string, receivingAddress?: string, isFetchingValidateAddress: boolean, From d539710627e60d8663af5636d6c152154b06c9e1 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Fri, 21 Jul 2017 14:12:20 -0500 Subject: [PATCH 15/74] add actions pertaining to account fetching --- src/client/exchange/actions.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/client/exchange/actions.js b/src/client/exchange/actions.js index cfd917a..5716c5c 100644 --- a/src/client/exchange/actions.js +++ b/src/client/exchange/actions.js @@ -10,6 +10,7 @@ import type { RequestOrderStatusAction, ReceiveOrderStatusAction, ErrorValidateAddressAction } from './types'; import * as types from './constants'; +import getAddresses from '../app/lib/getAccounts'; export const initExchange = (toSymbol: string): InitExchangeAction => { @@ -125,6 +126,21 @@ export const fetchLimit = (pair: string): ThunkAction => (dispatch) => { .then(limit => dispatch(receiveLimit(limit))); }; +const requestAddresses = (): RequestAddressesAction => ({ + type: types.REQUEST_ADDRESSES +}); + +const receiveAddresses = (addresses): ReceiveAddressesAction => ({ + type: types.RECEIVE_ADDRESSES, + addresses +}); + +export const fetchAddresses = (): ThunkAction => (dispatch) => { + dispatch(requestAddresses()); + return getAddresses() + .then(addresses => dispatch(receiveAddresses(addresses))); +}; + export const setReceivingAddress = ( address: string ): SetReceivingAddressAction => ({ From 9d8351f0d2d22b130153057442406bfb2da3d512 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Fri, 21 Jul 2017 14:12:41 -0500 Subject: [PATCH 16/74] add constants pertaining to account fetching --- src/client/exchange/constants.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client/exchange/constants.js b/src/client/exchange/constants.js index d90cc62..263ea84 100644 --- a/src/client/exchange/constants.js +++ b/src/client/exchange/constants.js @@ -8,6 +8,8 @@ export const REQUEST_LIMIT = 'exchange/REQUEST_LIMIT'; export const RECEIVE_LIMIT = 'exchange/RECEIVE_LIMIT'; export const REQUEST_SHIFT = 'exchange/REQUEST_SHIFT'; export const RECEIVE_SHIFT = 'exchange/RECEIVE_SHIFT'; +export const REQUEST_ADDRESSES = 'exchange/REQUEST_ADDRESSES'; +export const RECEIVE_ADDRESSES = 'exchange/RECEIVE_ADDRESSES'; export const SET_RECEIVING_ADDRESS = 'exchange/SET_RECEIVING_ADDRESS'; export const REQUEST_VALIDATE_ADDRESS = 'exchange/REQUEST_VALIDATE_ADDRESS'; export const RECEIVE_VALIDATE_ADDRESS = 'exchange/RECEIVE_VALIDATE_ADDRESS'; From 5fe06ee1b5f85525be73e7dd672ad35e7c855854 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Fri, 21 Jul 2017 14:13:43 -0500 Subject: [PATCH 17/74] add reducer logic pertaining to account fetching --- src/client/exchange/reducers.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/client/exchange/reducers.js b/src/client/exchange/reducers.js index 5440ebe..ced7e7a 100644 --- a/src/client/exchange/reducers.js +++ b/src/client/exchange/reducers.js @@ -8,7 +8,9 @@ const initialState: State = { from: 'ETH', to: 'WINGS', amount: '', + addresses: [], receivingAddress: '', + isFetchingAddresses: false, isFetchingQuote: false, didInvalidateQuote: false, isFetchingLimit: false, @@ -79,6 +81,19 @@ const exchangeReducer = ( limit: action.limit }; + case types.REQUEST_ADDRESSES: + return { + ...state, + isFetchingAddresses: true + }; + + case types.RECEIVE_ADDRESSES: + return { + ...state, + isFetchingAddresses: false, + addresses: action.addresses + }; + case types.SET_RECEIVING_ADDRESS: return { ...state, From 326ec8f28a187f6ccac96a8b9d6c1e7098dd8df8 Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Fri, 21 Jul 2017 14:15:15 -0500 Subject: [PATCH 18/74] fetch addresses on GetQuote#componentWillMount --- src/client/exchange/components/GetQuote.jsx | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/client/exchange/components/GetQuote.jsx b/src/client/exchange/components/GetQuote.jsx index febe15e..af80b97 100644 --- a/src/client/exchange/components/GetQuote.jsx +++ b/src/client/exchange/components/GetQuote.jsx @@ -9,12 +9,14 @@ import type { Action, ReduxState } from '~/exchange/types'; import CheckIcon from '~/app/components/CheckIcon'; import GetQuoteColumn from './GetQuoteColumn'; import PoweredByShapeshift from './PoweredByShapeshift'; -import { fetchValidateAddress, setReceivingAddress } from '../actions'; -import getAccount from '../../app/lib/getAccount'; +import { fetchAddresses, fetchValidateAddress, setReceivingAddress } from '../actions'; type Props = { classes: Object, coins: Object, + addresses: Array, + isFetchingAddresses: boolean, + fetchAddresses: () => void, receivingAddress: string, isReceivingAddressValid: boolean, setReceivingAddress: (address: string) => void, @@ -25,12 +27,9 @@ type Props = { class GetQuote extends React.Component { props: Props; - state = {}; async componentWillMount() { - const account = await getAccount(); - - this.props.setReceivingAddress(account || ''); + this.props.fetchAddresses(); } handleChangeReceivingAddress = (event) => { @@ -40,13 +39,18 @@ class GetQuote extends React.Component { this.props.setReceivingAddress(address); - if (address && !this.props.isFetchingValidateAddress) { + if ( + address && + !this.props.isFetchingValidateAddress && + !this.props.isFetchingAddresses + ) { debounce(this.props.fetchValidateAddress, 300)(address, to); } } render() { const { + addresses, classes: c, coins, receivingAddress, isReceivingAddressValid } = this.props; const title = ( @@ -170,10 +174,12 @@ const styled = injectSheet(styles)(GetQuote); ============================================================================= */ const mapStateToProps = (state: {exchange: ReduxState}) => ({ to: state.exchange.to, + addresses: state.exchange.addresses, receivingAddress: state.exchange.receivingAddress, isReceivingAddressValid: state.exchange.isReceivingAddressValid }); const mapDispatchToProps = (dispatch: Dispatch) => ({ + fetchAddresses: () => dispatch(fetchAddresses()), setReceivingAddress: address => dispatch(setReceivingAddress(address)), fetchValidateAddress: (address, symbol) => dispatch(fetchValidateAddress(address, symbol)), From 73ed12200f89dac315dffa4a730388b93958b05a Mon Sep 17 00:00:00 2001 From: Ron Gierlach Date: Fri, 21 Jul 2017 14:16:18 -0500 Subject: [PATCH 19/74] use to list available addresses --- src/client/exchange/components/GetQuote.jsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/client/exchange/components/GetQuote.jsx b/src/client/exchange/components/GetQuote.jsx index af80b97..7343ec5 100644 --- a/src/client/exchange/components/GetQuote.jsx +++ b/src/client/exchange/components/GetQuote.jsx @@ -79,16 +79,21 @@ class GetQuote extends React.Component {
+ {addresses.map(address => ( + + ))} {isReceivingAddressValid && }
); @@ -156,6 +161,7 @@ const styles = { borderRadius: '3px', padding: '4px 0', width: '45%', + textOverflow: 'ellipsis', borderBottom: '1px solid hsl(0, 0%, 84%)', alignSelf: 'flex-end', '&.is-valid': { From fb44b7b1dfb4873561c8fe1d8f51c73b6c768ecb Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 28 Jun 2017 03:11:41 -0700 Subject: [PATCH 20/74] Less logs --- src/server/app.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/server/app.js b/src/server/app.js index 8eab8fd..6c1abbc 100755 --- a/src/server/app.js +++ b/src/server/app.js @@ -61,10 +61,6 @@ winston.add(winston.transports.Loggly, { exitOnError: false }); -app.use(expressWinston.logger({ - winstonInstance: winston -})); - /** * GraphQL */ From d77bea6b00d6a1cf0e2a8d9262e2be6d77f586e7 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 28 Jun 2017 03:12:09 -0700 Subject: [PATCH 21/74] Performance optimizations --- src/server/schema/resolvers/icos.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/server/schema/resolvers/icos.js b/src/server/schema/resolvers/icos.js index 348a08b..92be3f2 100644 --- a/src/server/schema/resolvers/icos.js +++ b/src/server/schema/resolvers/icos.js @@ -5,6 +5,7 @@ import { normalize as normalizeICO } from 'lib/icos'; import icoData from 'lib/ico-data'; import { fetchETHPrice, fetchBTCPrice } from 'shared/lib/exchanges/gdax'; import { cache } from 'app'; +import Ticker from '~/models/ticker'; import PriceHistory from 'models/price-history'; import * as shapeshift from 'shared/lib/shapeshift'; @@ -32,6 +33,7 @@ export default async function icos() { } catch (err) { winston.error('Failed to fetch shapeshift coins: %s', err.message); } + cache.set('shapeshiftCoins', shapeshiftCoins); } // Get the current ETH price @@ -42,10 +44,14 @@ export default async function icos() { try { ethPrice = await fetchETHPrice(); } catch (e) { - const ticker = tickers.find(t => t.symbol === 'ETH'); + try { + const ticker = await Ticker.findOne({ ticker: 'ethereum' }).exec(); - ethPrice = ticker.price_usd; - winston.info('Fetched fallback ETH price (%s) from db.', ethPrice); + ethPrice = ticker.price_usd; + winston.info('Fetched fallback ETH price (%s) from db.', ethPrice); + } catch (err) { + winston.error('Failed to fetch ETH price in ICO resolver.'); + } } cache.set('ethPrice', ethPrice); } @@ -54,14 +60,17 @@ export default async function icos() { try { btcPrice = await fetchBTCPrice(); } catch (e) { - const ticker = tickers.find(t => t.symbol === 'BTC'); + try { + const ticker = await Ticker.findOne({ ticker: 'bitcoin' }).exec(); - btcPrice = ticker.price_usd; - winston.info('Fetched fallback BTC price (%s) from db.', btcPrice); + btcPrice = ticker.price_usd; + winston.info('Fetched fallback BTC price (%s) from db.', btcPrice); + } catch (err) { + winston.error('Failed to fetch BTC price in ICO resolver.'); + } } cache.set('btcPrice', btcPrice); } - return results.map(ico => normalizeICO(ico, ethPrice, btcPrice, shapeshiftCoins) ); From 71994673c7fd5963e40b6d1f3418cf3957255196 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 28 Jun 2017 03:54:14 -0700 Subject: [PATCH 22/74] Add ecosystem config. --- ecosystem.config.js | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 ecosystem.config.js diff --git a/ecosystem.config.js b/ecosystem.config.js new file mode 100644 index 0000000..5f152f6 --- /dev/null +++ b/ecosystem.config.js @@ -0,0 +1,48 @@ +module.exports = { + + /** + * Application configuration section + * http://pm2.keymetrics.io/docs/usage/application-declaration/ + */ + apps: [ + { + name: 'ICOStats', + script: 'server.js', + instances: 0, + exec_mode: 'cluster', + cwd: '/usr/app', + env: { + COMMON_VARIABLE: 'true' + }, + env_production: { + NODE_ENV: 'production' + } + } + ], + + /** + * Deployment section + * http://pm2.keymetrics.io/docs/usage/deployment/ + */ + deploy: { + production: { + user: 'root', + host: ['165.227.1.111', '165.227.9.59', '138.68.56.123'], + ref: 'origin/master', + repo: 'https://github.com/icostats/icostats.git', + path: '/usr/app', + 'post-deploy': 'yarn install && pm2 reload ecosystem.config.js --env production' + }, + dev: { + user: 'root', + host: '165.227.5.48', + ref: 'origin/master', + repo: 'https://github.com/icostats/icostats.git', + path: '/usr/app', + 'post-deploy': 'yarn install && pm2 reload ecosystem.config.js --env dev', + env: { + NODE_ENV: 'dev' + } + } + } +}; From 0122292e0ea0141d309b247e13fe106c92acc394 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 28 Jun 2017 03:55:53 -0700 Subject: [PATCH 23/74] Update pm2 scrippt. --- ecosystem.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index 5f152f6..8919dad 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -6,7 +6,7 @@ module.exports = { */ apps: [ { - name: 'ICOStats', + name: 'server', script: 'server.js', instances: 0, exec_mode: 'cluster', @@ -31,7 +31,7 @@ module.exports = { ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', - 'post-deploy': 'yarn install && pm2 reload ecosystem.config.js --env production' + 'post-deploy': 'yarn install && npm run build && pm2 reload ecosystem.config.js --env production' }, dev: { user: 'root', @@ -39,7 +39,7 @@ module.exports = { ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', - 'post-deploy': 'yarn install && pm2 reload ecosystem.config.js --env dev', + 'post-deploy': 'yarn install && npm run build && pm2 reload ecosystem.config.js --env dev', env: { NODE_ENV: 'dev' } From bbaa7569dd09c224a4707c129bb801725f75e7a5 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 28 Jun 2017 04:07:57 -0700 Subject: [PATCH 24/74] pm2 --- ecosystem.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ecosystem.config.js b/ecosystem.config.js index 8919dad..98394be 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -31,6 +31,7 @@ module.exports = { ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', + 'post-setup': 'pwd && ls -la && cd /usr/app && git pull origin master', 'post-deploy': 'yarn install && npm run build && pm2 reload ecosystem.config.js --env production' }, dev: { @@ -39,6 +40,7 @@ module.exports = { ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', + 'post-setup': 'pwd && ls -la && cd /usr/app && git pull origin master', 'post-deploy': 'yarn install && npm run build && pm2 reload ecosystem.config.js --env dev', env: { NODE_ENV: 'dev' From a2e9d75433ca4a696e9cb39ce442161203874a4c Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 28 Jun 2017 04:18:37 -0700 Subject: [PATCH 25/74] pm2 --- ecosystem.config.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index 98394be..ec62f78 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -31,8 +31,7 @@ module.exports = { ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', - 'post-setup': 'pwd && ls -la && cd /usr/app && git pull origin master', - 'post-deploy': 'yarn install && npm run build && pm2 reload ecosystem.config.js --env production' + 'post-deploy': 'cd /usr/app && git pull && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env production' }, dev: { user: 'root', @@ -40,8 +39,7 @@ module.exports = { ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', - 'post-setup': 'pwd && ls -la && cd /usr/app && git pull origin master', - 'post-deploy': 'yarn install && npm run build && pm2 reload ecosystem.config.js --env dev', + 'post-deploy': 'cd /usr/app && git pull && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env dev', env: { NODE_ENV: 'dev' } From 6e3e15877990b91097b53a5464f540863a45bbda Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 28 Jun 2017 20:32:53 -0700 Subject: [PATCH 26/74] Add SNT --- public/img/logos/status.svg | 18 ++++++++++++++++++ src/server/lib/ico-data.js | 20 ++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 public/img/logos/status.svg diff --git a/public/img/logos/status.svg b/public/img/logos/status.svg new file mode 100644 index 0000000..072be9f --- /dev/null +++ b/public/img/logos/status.svg @@ -0,0 +1,18 @@ + + + + Shape + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/server/lib/ico-data.js b/src/server/lib/ico-data.js index 4369af4..feca398 100644 --- a/src/server/lib/ico-data.js +++ b/src/server/lib/ico-data.js @@ -1,5 +1,25 @@ /* eslint-disable */ module.exports = [ + { + id: 'status', + ticker: 'status', + name: 'Status', + is_erc20: true, + contract_address: '0x744d70FDBE2Ba4CF95131626614a1763DF805B9E', + symbol: 'SNT', + eth_price_at_launch: 364.96, + btc_price_at_launch: 2648.93, + raise: 109488000, + raise_by_currency: { + eth: 300000 + }, + amount_sold_in_ico: 750000000, + implied_token_price: 0.145984, + total_supply: 6804870174.87, + start_date: '06/20/2017', + supported_changelly: false, + icon_ext: 'svg' + }, { id: 'bancor', ticker: 'bancor', From 5fd63a68be13cba42264f0546ee96ab3af95af6a Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 28 Jun 2017 20:39:47 -0700 Subject: [PATCH 27/74] Remove deleted server --- ecosystem.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index ec62f78..3b51194 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -27,7 +27,7 @@ module.exports = { deploy: { production: { user: 'root', - host: ['165.227.1.111', '165.227.9.59', '138.68.56.123'], + host: ['165.227.1.111', '165.227.9.59'], ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', From f150ff1a9b4a0e17c9923c63d154eee087138ff1 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 28 Jun 2017 20:42:52 -0700 Subject: [PATCH 28/74] pm2 --- ecosystem.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index 3b51194..10d733c 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -33,7 +33,7 @@ module.exports = { path: '/usr/app', 'post-deploy': 'cd /usr/app && git pull && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env production' }, - dev: { + staging: { user: 'root', host: '165.227.5.48', ref: 'origin/master', From 9a17d93d540a1761f075881e873a2e06f550b0f2 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 01:46:30 -0700 Subject: [PATCH 29/74] Fix SNT stats --- ecosystem.config.js | 1 + src/server/lib/ico-data.js | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index 10d733c..f856c2a 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -39,6 +39,7 @@ module.exports = { ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', + 'pre-setup': 'npm install -g yarn', 'post-deploy': 'cd /usr/app && git pull && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env dev', env: { NODE_ENV: 'dev' diff --git a/src/server/lib/ico-data.js b/src/server/lib/ico-data.js index feca398..8535ba8 100644 --- a/src/server/lib/ico-data.js +++ b/src/server/lib/ico-data.js @@ -13,8 +13,18 @@ module.exports = [ raise_by_currency: { eth: 300000 }, - amount_sold_in_ico: 750000000, - implied_token_price: 0.145984, + // Total supply of SNT: 6804870174 + // --- Breakdown --- + // Devs: 20% + // Reserve: 29% + // SGT: 6.9% + // - Formula: + // 10& * (Total SGT supply / Max SGT Supply) + // = 10% * (346447013 / 500000000) + // = .069 + // Contributors: 44.1% (100 - 20 - 29 - 6.9) + amount_sold_in_ico: 3000947746, + implied_token_price: 0.03648, total_supply: 6804870174.87, start_date: '06/20/2017', supported_changelly: false, From bcf6759137d56358d1c4d776f5cddb79a13ab5ac Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 01:49:30 -0700 Subject: [PATCH 30/74] Update staging IP --- ecosystem.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index f856c2a..f86ae4d 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -35,7 +35,7 @@ module.exports = { }, staging: { user: 'root', - host: '165.227.5.48', + host: '165.227.6.170', ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', From 5526a8f32374031674759234265258dc9731952f Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 01:51:45 -0700 Subject: [PATCH 31/74] PM2 Deploy --- ecosystem.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index f86ae4d..2ab180e 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -10,7 +10,7 @@ module.exports = { script: 'server.js', instances: 0, exec_mode: 'cluster', - cwd: '/usr/app', + cwd: '/usr/app/current', env: { COMMON_VARIABLE: 'true' }, @@ -40,7 +40,7 @@ module.exports = { repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', 'pre-setup': 'npm install -g yarn', - 'post-deploy': 'cd /usr/app && git pull && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env dev', + 'post-deploy': 'yarn install && npm run build && pm2 reload ./ecosystem.config.js --env dev', env: { NODE_ENV: 'dev' } From 47529c5056066e9a6f0f1a79ac48e8b6fe1a60d0 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 02:10:05 -0700 Subject: [PATCH 32/74] pm2 --- ecosystem.config.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index 2ab180e..225c572 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -10,7 +10,6 @@ module.exports = { script: 'server.js', instances: 0, exec_mode: 'cluster', - cwd: '/usr/app/current', env: { COMMON_VARIABLE: 'true' }, @@ -40,7 +39,7 @@ module.exports = { repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', 'pre-setup': 'npm install -g yarn', - 'post-deploy': 'yarn install && npm run build && pm2 reload ./ecosystem.config.js --env dev', + 'post-deploy': 'cd /usr/app/current && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env dev', env: { NODE_ENV: 'dev' } From 4e99f80902bc9333e4165f5b7f4bd55fbbf51082 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 02:12:07 -0700 Subject: [PATCH 33/74] pm2 --- ecosystem.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index 225c572..8468fc9 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -38,7 +38,7 @@ module.exports = { ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', - 'pre-setup': 'npm install -g yarn', + 'pre-setup': 'npm install -g yarn pm2', 'post-deploy': 'cd /usr/app/current && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env dev', env: { NODE_ENV: 'dev' From 1c18b7fda40396db67b9c1dfba61f01ce1128fc6 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 02:23:59 -0700 Subject: [PATCH 34/74] pm2 --- ecosystem.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index 8468fc9..596d283 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -39,7 +39,7 @@ module.exports = { repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', 'pre-setup': 'npm install -g yarn pm2', - 'post-deploy': 'cd /usr/app/current && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env dev', + 'post-deploy': 'cp /usr/app/.env . && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env staging', env: { NODE_ENV: 'dev' } From b4bbbc8c15a7026c413a44675cb9741eb3b8aa9e Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 02:25:01 -0700 Subject: [PATCH 35/74] pm2 --- ecosystem.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index 596d283..d01b4cc 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -30,7 +30,7 @@ module.exports = { ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', - 'post-deploy': 'cd /usr/app && git pull && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env production' + 'post-deploy': 'cd /usr/app && git pull && yarn install && npm run build && pm2 startOrReload ./ecosystem.config.js --env production' }, staging: { user: 'root', @@ -39,7 +39,7 @@ module.exports = { repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', 'pre-setup': 'npm install -g yarn pm2', - 'post-deploy': 'cp /usr/app/.env . && yarn install && npm run build && pm2 reload ./ecosystem.config.js --env staging', + 'post-deploy': 'cp /usr/app/.env . && yarn install && npm run build && pm2 startOrReload ./ecosystem.config.js --env staging', env: { NODE_ENV: 'dev' } From f80bbc8a07eaac13b47599021400765baf187a37 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 02:29:18 -0700 Subject: [PATCH 36/74] pm2 --- ecosystem.config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index d01b4cc..f14a323 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -30,7 +30,8 @@ module.exports = { ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', - 'post-deploy': 'cd /usr/app && git pull && yarn install && npm run build && pm2 startOrReload ./ecosystem.config.js --env production' + 'pre-setup': 'npm install -g yarn pm2', + 'post-deploy': 'cp /usr/app/.env . && yarn install && npm run build && pm2 startOrReload ./ecosystem.config.js --env production' }, staging: { user: 'root', From cdadf087d45c4403fd226db4375803c85a5df4ff Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 02:40:49 -0700 Subject: [PATCH 37/74] pm2 --- ecosystem.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index f14a323..f56ed57 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -26,7 +26,7 @@ module.exports = { deploy: { production: { user: 'root', - host: ['165.227.1.111', '165.227.9.59'], + host: ['165.227.1.111'], ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', From 87c4800f03732bdf8cd35519b3efaae4301f1b03 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 02:47:16 -0700 Subject: [PATCH 38/74] pm2 --- ecosystem.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index f56ed57..e5cd79d 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -26,7 +26,7 @@ module.exports = { deploy: { production: { user: 'root', - host: ['165.227.1.111'], + host: ['165.227.9.59'], ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', From bc08120efc5dc029778e86fd66a3adc842022651 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 03:14:17 -0700 Subject: [PATCH 39/74] pm2 --- ecosystem.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index e5cd79d..f14a323 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -26,7 +26,7 @@ module.exports = { deploy: { production: { user: 'root', - host: ['165.227.9.59'], + host: ['165.227.1.111', '165.227.9.59'], ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', From 1a122ea01b444f127a153a2c04926d6321ceed38 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Thu, 29 Jun 2017 17:00:49 -0700 Subject: [PATCH 40/74] Add ICO Alerts link --- src/client/app/components/Navigation.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/client/app/components/Navigation.jsx b/src/client/app/components/Navigation.jsx index fe205d9..9fd698b 100644 --- a/src/client/app/components/Navigation.jsx +++ b/src/client/app/components/Navigation.jsx @@ -175,6 +175,12 @@ const Navigation = ({ classes, onClickFeedback, isNavOpen = true }: Props) => ( className={classes.menuItem} activeClassName={classes.activeMenuItem} >Compare + Upcoming ICOs {/* Date: Sat, 8 Jul 2017 16:21:40 -0700 Subject: [PATCH 41/74] add(ico data) : Added Aeternity, Darcrus, ETH, IOTA, MYST, QTUM, QRL data. --- public/img/logos/aeternity.png | Bin 0 -> 17379 bytes public/img/logos/darcrus.png | Bin 0 -> 2278 bytes public/img/logos/ethereum.png | Bin 0 -> 16979 bytes public/img/logos/iota.png | Bin 0 -> 16379 bytes public/img/logos/mysterium.png | Bin 0 -> 6065 bytes public/img/logos/qtum.png | Bin 0 -> 4227 bytes public/img/logos/quantum-resistant-ledger.png | Bin 0 -> 3268 bytes src/server/lib/ico-data.js | 127 ++++++++++++++++++ 8 files changed, 127 insertions(+) create mode 100644 public/img/logos/aeternity.png create mode 100644 public/img/logos/darcrus.png create mode 100644 public/img/logos/ethereum.png create mode 100644 public/img/logos/iota.png create mode 100644 public/img/logos/mysterium.png create mode 100644 public/img/logos/qtum.png create mode 100644 public/img/logos/quantum-resistant-ledger.png diff --git a/public/img/logos/aeternity.png b/public/img/logos/aeternity.png new file mode 100644 index 0000000000000000000000000000000000000000..812e82d7c281ac165c5a936571fbd6b94150c272 GIT binary patch literal 17379 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 Lu<)e+n$7%f_ literal 0 HcmV?d00001 diff --git a/public/img/logos/ethereum.png b/public/img/logos/ethereum.png new file mode 100644 index 0000000000000000000000000000000000000000..d09c29ee88fb33c27ba115535b0ce8b29cd97ea8 GIT binary patch literal 16979 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 Z!0r8>m;8R(t*v;xxH+$Mk~sv%{TnU)4)y>5 literal 0 HcmV?d00001 diff --git a/public/img/logos/iota.png b/public/img/logos/iota.png new file mode 100644 index 0000000000000000000000000000000000000000..002692f3d55a63a23da6ff7ee431c010b9e39922 GIT binary patch literal 16379 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 literal 0 HcmV?d00001 diff --git a/public/img/logos/mysterium.png b/public/img/logos/mysterium.png new file mode 100644 index 0000000000000000000000000000000000000000..3557f25c4f4d1bf21112089e64b7a4d9a89595cd GIT binary patch literal 6065 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 ykp774)+73(dZ;(Q3!1e{kyNH0MX0AP^!vvs68 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 literal 0 HcmV?d00001 diff --git a/src/server/lib/ico-data.js b/src/server/lib/ico-data.js index 8535ba8..0ba87bb 100644 --- a/src/server/lib/ico-data.js +++ b/src/server/lib/ico-data.js @@ -1,5 +1,132 @@ /* eslint-disable */ module.exports = [ + { + id: 'darcrus', + is_erc20: false, + name: 'Darcrus', + symbol: 'DAR', + eth_price_at_launch: 7.92, + btc_price_at_launch: 824.23, + raise: 285203, + amount_sold_in_ico: 14055048, + implied_token_price: 0.020, + start_date: '12/21/2016', // ref. https://trello.com/c/Osc4Bt1X/90-issue-32-coins-to-list + ticker: 'darcrus', + supported_changelly: true + }, + { + id: 'qtum', + is_erc20: false, + name: 'QTUM', + symbol: 'QTUM', + eth_price_at_launch: 22.18, + btc_price_at_launch: 1181.17, + raise: 14887694.5638, // 11,156.766 BTC and 77,081.031 ETH $13178037.29622 + $1709657.26758 + amount_sold_in_ico: 51000000, // ref https://qtum.org/en/crowdsale + implied_token_price: 0.292, + start_date: '03/12/2017', // ref. https://tokenmarket.net/blockchain/bitcoin/assets/qtum/ + ticker: 'qtum', + supported_changelly: false + }, + { + id: 'quantum-resistant-ledger', + is_erc20: true, + name: 'Quantum Resistant Ledger', + symbol: 'QRL', + eth_price_at_launch: 205.55, + btc_price_at_launch: 2252.71, + raise: 4000000, // Unknown BTC and ETH amount https://medium.com/the-quantum-resistant-ledger/without-you-there-is-no-qrl-182f7962e870 + amount_sold_in_ico: 52000000, // ref https://steemit.com/qrl/@kevinternet/qrl-quantum-resistant-ledger-price-forecast + implied_token_price: 0.077, // ref https://steemit.com/qrl/@kevinternet/qrl-quantum-resistant-ledger-price-forecast + start_date: '05/01/2017', // ref. https://tokenmarket.net/blockchain/blockchain/assets/quantum-resistant/ + ticker: 'quantum-resistant-ledger', + supported_changelly: false + }, + { + id: 'mysterium', + is_erc20: true, + name: 'Mysterium', + symbol: 'MYST', + eth_price_at_launch: 205.55, + btc_price_at_launch: 2252.71, + raise: 14106690.95, // 68629 ETH + amount_sold_in_ico: 80000000, // ref https://twitter.com/MysteriumNet/status/869678853404454914 + implied_token_price: 0.157, // Token supply was 90m while 80m tokens were distributed on ICO. + start_date: '05/30/2017', // ref. https://www.smithandcrown.com/sale/mysterium2/ + ticker: 'mysterium', + supported_changelly: false + }, + { + id: 'iota', + is_erc20: false, + name: 'IOTA', + symbol: 'MIOTA', + eth_price_at_launch: 0.883399, + btc_price_at_launch: 324.99, + raise: 434511.63, // 1337 BTC + amount_sold_in_ico: 999999999, // ref https://bitcointalk.org/index.php?topic=1262688.0 + implied_token_price: 0.0004, + start_date: '11/25/2015', // ref. https://bitcointalk.org/index.php?topic=1262688.0 https://medium.com/@cryptojudgement/iota-promise-of-a-bright-crypto-future-6b7517349e32 + ticker: 'iota', + supported_changelly: false + }, + // No ICO info yet. + // { + // id: 'adtoken', + // is_erc20: true, + // name: 'adToken', + // symbol: 'ADT', + // eth_price_at_launch: 0, // 2000 ETH = 1 BTC + // btc_price_at_launch: 0, + // raise: 0, // 25000 BTC + // amount_sold_in_ico: 0, // Found approx amount ref https://blog.ethereum.org/2014/08/08/ether-sale-a-statistical-overview/ + // implied_token_price:0, + // start_date: '07/22/2014', // ref. https://blog.ethereum.org/2014/07/22/launching-the-ether-sale/ + // ticker: 'adtoken', + // supported_changelly: false + // }, + { + id: 'ethereum', + is_erc20: false, + name: 'Ethereum', + symbol: 'ETH', + eth_price_at_launch: 0.31142, // 2000 ETH = 1 BTC + btc_price_at_launch: 622.84, + raise: 15571000, // 25000 BTC + amount_sold_in_ico: 50000000, // Found approx amount ref https://blog.ethereum.org/2014/08/08/ether-sale-a-statistical-overview/ + implied_token_price: 0.248, + start_date: '07/22/2014', // ref. https://blog.ethereum.org/2014/07/22/launching-the-ether-sale/ + ticker: 'ethereum', + supported_changelly: true + }, + // { + // id: 'aeternity-two', + // is_erc20: false, + // name: 'Aeternity Phase II', + // symbol: 'AE', + // eth_price_at_launch: 185.94, + // btc_price_at_launch: 2183.63, + // raise: 21844271.49391, // 104,148.741 ETH, 1,135.199 BTC raised // $19365416.90154 + $2478854.59237 + // amount_sold_in_ico: 88139450.839, // ref https://wallet.aeternity.com/ + // implied_token_price: 0.248, + // start_date: '05/29/2017', // ref. https://tokenmarket.net/blockchain/aeternity/assets/aeternity/ + // ticker: 'aeternity', + // supported_changelly: false + // }, + { + id: 'aeternity', + is_erc20: false, + name: 'Aeternity Phase I', + symbol: 'AE', + eth_price_at_launch: 45.88, + btc_price_at_launch: 1129.90, + raise: 5940998.795, // 121,396.731 ETH, 328.628 BTC raised // $5569682.01828 + $371316.7772 https://wallet.aeternity.com/ + amount_sold_in_ico: 139089935.082, // ref https://wallet.aeternity.com/ + implied_token_price: 0.043, // raise/amount_sold_in_ico + start_date: '04/03/2017', // ref. https://www.smithandcrown.com/aeternity-token-sale-ico-oracle-machine/ + ticker: 'aeternity', + supported_changelly: false + }, { id: 'status', ticker: 'status', From b07eddde7a08795af08b5a6d09d1b42790264dab Mon Sep 17 00:00:00 2001 From: Phily Austria Date: Sat, 8 Jul 2017 17:52:50 -0700 Subject: [PATCH 42/74] add(ico data) : Added adToken. --- public/img/logos/adtoken.png | Bin 0 -> 3430 bytes src/server/lib/ico-data.js | 29 ++++++++++++++--------------- 2 files changed, 14 insertions(+), 15 deletions(-) create mode 100644 public/img/logos/adtoken.png diff --git a/public/img/logos/adtoken.png b/public/img/logos/adtoken.png new file mode 100644 index 0000000000000000000000000000000000000000..029c40b00b495aedbd9866823981006c237ecb17 GIT binary patch literal 3430 zcmaJ^c|6p4A0Mi5HF8zM#!lltXNDQgOu5Fmjod}qjG5oeh&jv*2CK+XEIC5th(T>c zq(eyuxf7d22NK%Fx;M4fz$DWFcYsWd2EcO=45Hwua0_$TApu@Qzy$bYn1C6~;^75m@V|KRqVtv+0f+tN!VfZo z|2wIpBv+UPmi}8ZZL?@&ZpLO(CYGs8l%`fjSc3>@(YOY zkI!f4hS%4hhd*BxEr9CNdUtiyk2OG-DfG4+d5@*e>$G`nLD zldEt+TQuj*G9x6d^tGZ+rJnP5U3CF37FI#|$D7^>XCw%y|V)sud zjOyd{v<>+_ll@Q#zGh^5l}-ops$}n?!bS-9$DyBdxl>neUktxAlNSvk_3etJ!{43Z zLmoPKBBWz>g0E}9-%74s?LHDQXt+^ThFnQ6{sn=bchPp?lX9yc3fDR^bnlEI>=Idb zp_rOH+*7Iff!I;RlB=-Wx5%c#Tby!>ag6rtt^UoFUD+S=7k-%5Il0LPFN}g7*A8;5 zQKmQajdb-51ywC$n3i)oa_zP9(Do;SHs<6?#C zc4JSyq$VPC?GFUi2Ax)%{qZ+5{<3rN)QbmE!p!o!RUT`aT^wZo4vd1kF~%`0SMA7Q zc#mWKHR*AVTwBzyp8%&<=YtypDV|viD~G|gkA}kdzxB9xrZLDX_UVpDID_mjck5}1tl#=G24{BaU|Ud0|GdAJ_IlFsnw_*btM$vruFzSH73Ufz z6Krqo`wo0g0^>C~SpO{c;_&kOjC@DV$Oi4pIvMMMwsby|NYG8B=fjVUm2|CqJzS@-!Z)e%2eS0l#0aQYo>}E%!;F1aPGdS> z;QC8iVzUoHzEM|ere7JO8=?iQMFr{=1`03V^hF@KKe@9E5&x^&LzVTVN8b(XDT&XT zG=rBX2)(_jb_Pn#vC*mR?Z#y4v;4Wq8A6oZK{43$lxA`|5oOdmk?zneMuP}YvKbHT zHRU3%;dOL7dXU1Qu{IBjV<|gK&BB5o?(`LYx^3&p`}Vvt#zE@F_BZ9@ep*H^na9M`Rqt<%s?TR+&>74t%j+wiV^e@j@M^?1^T?67 zp{VK>!0G1bel-TJJX^cczv$JoB04VCSXoT7z%g&a!(nF7)#i+*uzN=P26gT8>`4Qy zJ89{1N!w?iRO!1qOq-tU8}fuq&s}fzs+4)J9XdX)QDQOicyG-7354r}Y zah|LQ0AI1kH~k{e`bu@PRrRi4^3@_-^0LMK?G0g7PX^m}f_qlI3~MudUqG|p=MeNO zBz-b_(k#zhOonDia}ByCU+O_270Z>S7uNdZcdjcD$SW!_IQqqlUiqZ`=G|E)>58d5noYy%u`4Ou1zD_QKa?rFpKEI{WvR z=^Oo2qf+lPfcw57EJ<-?xK`4dz7B;-rnh+?CpfNPlMZWM8@-|SXH1Gjh7*vNO>+fI z3p;0H4I%d0RTfJh0}G}XMjJ*D377ZbqPUXTUEJD|FvxTF3=VHQ9s z|3u#hDf6OV?Hjb(GLmvw7N1{Y0*X&d+l-eubj2n)Ou1%4ofTkNWMbZ~)}(FEj_ot~qbb;z=eOyXFN7`KIy)^B(FcwuE@9*E+7h+_-S8CRW zx0qQ7zF>sLIeIBxC>aPMyJ`s+#g>_C=HYO@Y_Q*hTWi60hFs{oB?yWFfpEwIQG^A-QP(#N;PI{Sg;WeBPM_ZRL;8E}qR|DzXj6qZ*-i$jHqD%ShY)_7api}V z_9)3F5P0aB`F%aw=l8VaR>+@l|M6zWm-SO)57;{w8(Vr~rJ*M~>TDGeeU?Gf!Ha&` zGiZpC60JZwLGzs3FYW2~+lj7|)1~?*BcG>NH@8DU;WaIKYEr#fTQ4668y8|V!T-#^ E0HHhIn*aa+ literal 0 HcmV?d00001 diff --git a/src/server/lib/ico-data.js b/src/server/lib/ico-data.js index 0ba87bb..3e603cb 100644 --- a/src/server/lib/ico-data.js +++ b/src/server/lib/ico-data.js @@ -70,21 +70,20 @@ module.exports = [ ticker: 'iota', supported_changelly: false }, - // No ICO info yet. - // { - // id: 'adtoken', - // is_erc20: true, - // name: 'adToken', - // symbol: 'ADT', - // eth_price_at_launch: 0, // 2000 ETH = 1 BTC - // btc_price_at_launch: 0, - // raise: 0, // 25000 BTC - // amount_sold_in_ico: 0, // Found approx amount ref https://blog.ethereum.org/2014/08/08/ether-sale-a-statistical-overview/ - // implied_token_price:0, - // start_date: '07/22/2014', // ref. https://blog.ethereum.org/2014/07/22/launching-the-ether-sale/ - // ticker: 'adtoken', - // supported_changelly: false - // }, + { + id: 'adtoken', + is_erc20: true, + name: 'adToken', + symbol: 'ADT', + eth_price_at_launch: 262.38, + btc_price_at_launch: 2508.52, + raise: 10000000, + amount_sold_in_ico: 1000000000, + implied_token_price:0, + start_date: '06/26/2017', // ref. http://www.blockchaindailynews.com/MetaX-Completes-10-Million-adToken-ADT-Sale_a25622.html + ticker: 'adtoken', + supported_changelly: false + }, { id: 'ethereum', is_erc20: false, From 845aeeffa43bcef663f7a285c8fae8cb500183e4 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Mon, 10 Jul 2017 15:09:53 -0700 Subject: [PATCH 43/74] Prefer coinmarketcap. --- src/shared/lib/exchange.service.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/shared/lib/exchange.service.js b/src/shared/lib/exchange.service.js index 2f3a782..13af11c 100644 --- a/src/shared/lib/exchange.service.js +++ b/src/shared/lib/exchange.service.js @@ -197,12 +197,22 @@ class ExchangeService { } async fetchUSDPrice(symbol: string) { + + // Try coinmarketcap first. + try { + const map = await coinmarketcap.fetchBoundPriceMap(); + const fetcher = map[`${symbol}-USD`]; + const price = await fetcher(); + + return price; + } catch (err) { winston.warn(err.message); } + // Try direct to USD try { const price = await this.fetchPrice(symbol, 'USD'); return price; - } catch (e) {} + } catch (e) { winston.warn(e.message); } // Nope, go through BTC try { @@ -210,7 +220,7 @@ class ExchangeService { const btcPrice = await fetchBTCPrice(); return price * btcPrice; - } catch (e) {} + } catch (e) { winston.warn(e.message); } // Nope, try ETH try { @@ -225,15 +235,6 @@ class ExchangeService { ); } - // Nope, try coinmarketcap - try { - const map = await coinmarketcap.fetchBoundPriceMap(); - const fetcher = map[`${symbol}-USD`]; - const price = await fetcher(); - - return price; - } catch (err) {} - winston.error(`ExchangeService: Failed to find ${symbol} on any exchange!`); return null; } From 166b9d5c0cb1670006c19fb36e5f84d232030f9f Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Mon, 10 Jul 2017 15:12:47 -0700 Subject: [PATCH 44/74] typo --- src/server/lib/price-worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/lib/price-worker.js b/src/server/lib/price-worker.js index af22561..d2790fd 100644 --- a/src/server/lib/price-worker.js +++ b/src/server/lib/price-worker.js @@ -38,7 +38,7 @@ async function recursiveFetchPrice(symbols, index) { } } catch (err) { winston.error( - `Price worker failed to fetch price for ${symbol}: err.message` + `Price worker failed to fetch price for ${symbol}: ${err.message}` ); } const nextIndex = (index === symbols.length - 1) ? 0 : (index + 1); From caba40f157a92233202baa9db69daddaa0314323 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Mon, 10 Jul 2017 15:17:14 -0700 Subject: [PATCH 45/74] public API --- src/server/app.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/server/app.js b/src/server/app.js index 6c1abbc..2b1f867 100755 --- a/src/server/app.js +++ b/src/server/app.js @@ -66,11 +66,9 @@ winston.add(winston.transports.Loggly, { */ app.use('/graphql', bodyParser.json(), graphqlExpress({ schema })); -if (process.env.NODE_ENV !== 'production') { - app.use('/graphiql', graphiqlExpress({ - endpointURL: '/graphql' - })); -} +app.use('/graphiql', graphiqlExpress({ + endpointURL: '/graphql' +})); /** * Serve files in the /public directory as static files. From 65e62124db6745a0d1f60979a09d72603351184c Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Mon, 10 Jul 2017 15:57:11 -0700 Subject: [PATCH 46/74] Revert "Less logs" This reverts commit a5fd84b0af4f8333d09b5ba2cd4422de617b270e. --- src/server/app.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/server/app.js b/src/server/app.js index 2b1f867..fe0ef35 100755 --- a/src/server/app.js +++ b/src/server/app.js @@ -61,6 +61,10 @@ winston.add(winston.transports.Loggly, { exitOnError: false }); +app.use(expressWinston.logger({ + winstonInstance: winston +})); + /** * GraphQL */ From 9704efb7bd71352e3fab1e18cdcb51b020c95e50 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 12 Jul 2017 02:20:30 -0700 Subject: [PATCH 47/74] Logging --- src/server/lib/price-worker.js | 17 +++++++++-- src/server/lib/ticker-worker.js | 6 ++-- src/server/schema/resolvers/icos.js | 46 ++++++++++++++++++++++++++--- 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/server/lib/price-worker.js b/src/server/lib/price-worker.js index d2790fd..cc10898 100644 --- a/src/server/lib/price-worker.js +++ b/src/server/lib/price-worker.js @@ -8,7 +8,16 @@ import icoData from '~/lib/ico-data'; import getExchangeService from 'shared/lib/exchange.service'; import PriceHistory from '~/models/price-history'; -const FIVE_SECONDS = 5000; +const ONE_SECOND = 1000; +const FIVE_SECONDS = ONE_SECOND * 5; +const TEN_MINUTES = ONE_SECOND * 60 * 10; + +// Delay between fetching each price. +const DELAY_EACH = FIVE_SECONDS; + +// Delay between fetching the whole list of prices. +const DELAY_ALL = TEN_MINUTES; + let ref; const exchangeService = getExchangeService(); @@ -30,6 +39,9 @@ async function recursiveFetchPrice(symbols, index) { try { const price = await exchangeService.fetchUSDPrice(symbol); + const time = Date.now() - ts; + + winston.info(`Price Worker: Fetched price for ${symbol} in ${time}ms`); if (typeof price !== 'number' || isNaN(price)) { throw new Error(`Got an invalid price for ${symbol}`); @@ -42,8 +54,9 @@ async function recursiveFetchPrice(symbols, index) { ); } const nextIndex = (index === symbols.length - 1) ? 0 : (index + 1); + const delay = (nextIndex === 0) ? DELAY_ALL : DELAY_EACH; - setTimeout(() => recursiveFetchPrice(symbols, nextIndex), FIVE_SECONDS); + setTimeout(() => recursiveFetchPrice(symbols, nextIndex), delay); } async function savePrice(price, symbol, ts) { diff --git a/src/server/lib/ticker-worker.js b/src/server/lib/ticker-worker.js index 594bed8..0aeab58 100644 --- a/src/server/lib/ticker-worker.js +++ b/src/server/lib/ticker-worker.js @@ -7,7 +7,9 @@ import Ticker from 'models/ticker'; import icoData from 'lib/ico-data'; import winston from 'winston'; -const FIVE_SECONDS = 5000; +const ONE_SECOND = 1000; +const ONE_MINUTE = ONE_SECOND * 60; +const FIVE_MINUTES = ONE_MINUTE * 5; let ref; export default function initTickerWorker() { @@ -35,7 +37,7 @@ async function recursiveSyncTicker(tickers, index) { winston.error(`Failed to fetch ticker for ${ticker}: ${err.message}`); } - setTimeout(() => recursiveSyncTicker(tickers, nextIndex), FIVE_SECONDS); + setTimeout(() => recursiveSyncTicker(tickers, nextIndex), FIVE_MINUTES); } async function fetchTicker(ticker) { diff --git a/src/server/schema/resolvers/icos.js b/src/server/schema/resolvers/icos.js index 92be3f2..61d1009 100644 --- a/src/server/schema/resolvers/icos.js +++ b/src/server/schema/resolvers/icos.js @@ -9,8 +9,14 @@ import Ticker from '~/models/ticker'; import PriceHistory from 'models/price-history'; import * as shapeshift from 'shared/lib/shapeshift'; +const ONE_HOUR = 60 * 60; +const ONE_DAY = ONE_HOUR * 24; + export default async function icos() { + const startAll = Date.now(); const priceHistories = await PriceHistory.find().lean().exec(); + const endPriceHistories = Date.now(); + const msPriceHistories = endPriceHistories - startAll; const pricesBySymbol = priceHistories.reduce((obj, model) => ({ ...obj, [model.symbol]: model.latest @@ -24,16 +30,25 @@ export default async function icos() { id: data.id })); + winston.info(`Querying mongo for PriceHistory for icos resolver took ${msPriceHistories}ms`); + // get shapeshift info let shapeshiftCoins = cache.get('shapeshiftCoins'); if (!shapeshiftCoins) { + const start = Date.now(); + + winston.warn('Shapeshift data not in cache - refetching'); try { shapeshiftCoins = await shapeshift.getCoins(); + const end = Date.now(); + const ms = end - start; + + winston.info(`Fetched shapeshift coin list in ${ms}ms`); } catch (err) { winston.error('Failed to fetch shapeshift coins: %s', err.message); } - cache.set('shapeshiftCoins', shapeshiftCoins); + cache.set('shapeshiftCoins', shapeshiftCoins, ONE_DAY); } // Get the current ETH price @@ -41,8 +56,15 @@ export default async function icos() { let btcPrice = cache.get('btcPrice'); if (!ethPrice) { + const start = Date.now(); + + winston.warn('ETH price not in cache - refetching'); try { ethPrice = await fetchETHPrice(); + const end = Date.now(); + const ms = end - start; + + winston.info(`Fetched ETH price in ${ms}ms`); } catch (e) { try { const ticker = await Ticker.findOne({ ticker: 'ethereum' }).exec(); @@ -53,12 +75,19 @@ export default async function icos() { winston.error('Failed to fetch ETH price in ICO resolver.'); } } - cache.set('ethPrice', ethPrice); + cache.set('ethPrice', ethPrice, ONE_HOUR); } if (!btcPrice) { + const start = Date.now(); + + winston.warn('BTC price not in cache - refetching'); try { btcPrice = await fetchBTCPrice(); + const end = Date.now(); + const ms = end - start; + + winston.info(`Fetched BTC price in ${ms}ms`); } catch (e) { try { const ticker = await Ticker.findOne({ ticker: 'bitcoin' }).exec(); @@ -69,9 +98,18 @@ export default async function icos() { winston.error('Failed to fetch BTC price in ICO resolver.'); } } - cache.set('btcPrice', btcPrice); + cache.set('btcPrice', btcPrice, ONE_HOUR); } - return results.map(ico => + + const startNormalize = Date.now(); + const res = results.map(ico => normalizeICO(ico, ethPrice, btcPrice, shapeshiftCoins) ); + const endNormalize = Date.now(); + const msNormalize = endNormalize - startNormalize; + + winston.info(`Normalized ICOs in ${msNormalize}ms`); + winston.info(`ICO resolver took ${startAll - Date.now()}ms`); + + return res; } From c226d7f1727b701a56e41ae5a75ae10437aa286f Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 12 Jul 2017 02:59:08 -0700 Subject: [PATCH 48/74] pm2 --- ecosystem.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index f14a323..cfbe8cd 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -26,7 +26,7 @@ module.exports = { deploy: { production: { user: 'root', - host: ['165.227.1.111', '165.227.9.59'], + host: ['165.227.10.250'], //['165.227.1.111', '165.227.9.59'], ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', From 977a89c4b51385afeb4726b04a59222ccabb4547 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 12 Jul 2017 03:14:03 -0700 Subject: [PATCH 49/74] Performance Optimization --- src/server/schema/resolvers/icos.js | 31 ++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/server/schema/resolvers/icos.js b/src/server/schema/resolvers/icos.js index 61d1009..ca7ee0e 100644 --- a/src/server/schema/resolvers/icos.js +++ b/src/server/schema/resolvers/icos.js @@ -9,14 +9,31 @@ import Ticker from '~/models/ticker'; import PriceHistory from 'models/price-history'; import * as shapeshift from 'shared/lib/shapeshift'; -const ONE_HOUR = 60 * 60; +const ONE_MINUTE = 60; +const ONE_HOUR = ONE_MINUTE * 60; const ONE_DAY = ONE_HOUR * 24; export default async function icos() { const startAll = Date.now(); - const priceHistories = await PriceHistory.find().lean().exec(); - const endPriceHistories = Date.now(); - const msPriceHistories = endPriceHistories - startAll; + + let priceHistories = cache.get('priceHistories'); + + if (!priceHistories) { + winston.warn(`Price histories not in cache: Querying mongo for new data`); + try { + priceHistories = await PriceHistory.find().lean().exec(); + const endPriceHistories = Date.now(); + const msPriceHistories = endPriceHistories - startAll; + + winston.info(`Querying mongo for PriceHistory for icos resolver took ${msPriceHistories}ms`); + + cache.set('priceHistories', ethPrice, ONE_MINUTE * 10); + + } catch (err) { + winston.error(`Failed to get price histories from mongo: ${err.message}`); + } + } + const pricesBySymbol = priceHistories.reduce((obj, model) => ({ ...obj, [model.symbol]: model.latest @@ -30,8 +47,6 @@ export default async function icos() { id: data.id })); - winston.info(`Querying mongo for PriceHistory for icos resolver took ${msPriceHistories}ms`); - // get shapeshift info let shapeshiftCoins = cache.get('shapeshiftCoins'); @@ -45,10 +60,12 @@ export default async function icos() { const ms = end - start; winston.info(`Fetched shapeshift coin list in ${ms}ms`); + + cache.set('shapeshiftCoins', shapeshiftCoins, ONE_DAY); } catch (err) { winston.error('Failed to fetch shapeshift coins: %s', err.message); + shapeshiftCoins = {}; } - cache.set('shapeshiftCoins', shapeshiftCoins, ONE_DAY); } // Get the current ETH price From 8d9e33017397825841828d07f1438b941aa27945 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 12 Jul 2017 03:16:38 -0700 Subject: [PATCH 50/74] typo --- src/server/schema/resolvers/icos.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/schema/resolvers/icos.js b/src/server/schema/resolvers/icos.js index ca7ee0e..f6821bc 100644 --- a/src/server/schema/resolvers/icos.js +++ b/src/server/schema/resolvers/icos.js @@ -27,7 +27,7 @@ export default async function icos() { winston.info(`Querying mongo for PriceHistory for icos resolver took ${msPriceHistories}ms`); - cache.set('priceHistories', ethPrice, ONE_MINUTE * 10); + cache.set('priceHistories', priceHistories, ONE_MINUTE * 10); } catch (err) { winston.error(`Failed to get price histories from mongo: ${err.message}`); From f8f97810b3c36a9f42bd9321e16b0417bc0e620e Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 12 Jul 2017 03:51:23 -0700 Subject: [PATCH 51/74] dont include huge price array --- src/server/schema/resolvers/icos.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/schema/resolvers/icos.js b/src/server/schema/resolvers/icos.js index f6821bc..981643f 100644 --- a/src/server/schema/resolvers/icos.js +++ b/src/server/schema/resolvers/icos.js @@ -21,7 +21,7 @@ export default async function icos() { if (!priceHistories) { winston.warn(`Price histories not in cache: Querying mongo for new data`); try { - priceHistories = await PriceHistory.find().lean().exec(); + priceHistories = await PriceHistory.find().select('-prices').lean().exec(); const endPriceHistories = Date.now(); const msPriceHistories = endPriceHistories - startAll; From 13439ea22d8c17f441101e99b1c933ccf6322544 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 12 Jul 2017 03:56:17 -0700 Subject: [PATCH 52/74] pm2 --- ecosystem.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecosystem.config.js b/ecosystem.config.js index cfbe8cd..f14a323 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -26,7 +26,7 @@ module.exports = { deploy: { production: { user: 'root', - host: ['165.227.10.250'], //['165.227.1.111', '165.227.9.59'], + host: ['165.227.1.111', '165.227.9.59'], ref: 'origin/master', repo: 'https://github.com/icostats/icostats.git', path: '/usr/app', From c01e4c8f6541e943c55e94ecf60efdff5477fc29 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Wed, 12 Jul 2017 11:27:40 -0700 Subject: [PATCH 53/74] Fix adtoken ICO price --- src/server/lib/ico-data.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/server/lib/ico-data.js b/src/server/lib/ico-data.js index 3e603cb..a7025cf 100644 --- a/src/server/lib/ico-data.js +++ b/src/server/lib/ico-data.js @@ -77,9 +77,12 @@ module.exports = [ symbol: 'ADT', eth_price_at_launch: 262.38, btc_price_at_launch: 2508.52, - raise: 10000000, + raise: 8746000.0017492, + raise_by_currency: { + eth: 33333.33334 + }, amount_sold_in_ico: 1000000000, - implied_token_price:0, + implied_token_price: 0.0087, start_date: '06/26/2017', // ref. http://www.blockchaindailynews.com/MetaX-Completes-10-Million-adToken-ADT-Sale_a25622.html ticker: 'adtoken', supported_changelly: false From 58ee83b206f07db2372aff0e890988ac97de1cc7 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 01:33:41 -0700 Subject: [PATCH 54/74] Don't ignore console test. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6a9ed01..a99486b 100755 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,3 @@ public/bundle.js server.js dist/ yarn-error.log -tests/shared/__console.test.js From 7c934177ce0605fb41bb3d4a8ed8ea09337b1cbb Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 01:40:29 -0700 Subject: [PATCH 55/74] Restore console utility test. --- tests/shared/__console.test.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/shared/__console.test.js diff --git a/tests/shared/__console.test.js b/tests/shared/__console.test.js new file mode 100644 index 0000000..d22168f --- /dev/null +++ b/tests/shared/__console.test.js @@ -0,0 +1,30 @@ +/** + * This has no real test. Its just used as a sort of REPL. Node console is not + * ideal if you want to interact with the codebase because there is a lot of + * syntax which is not supported in node REPL (like import statements and + * async/await syntax). + * + * Usage: + * 1. Change `describe.skip` to `describe.only` so only this file is evaluated + * by mocha. + * 2. Run `make test` + * + * NOTE DO NOT COMMIT ANY CHANGES TO THIS FILE + */ +/* eslint-disable */ +import { expect } from 'chai'; +import getExchangeService from 'shared/lib/exchange.service'; + + +describe.skip('Console', function () { + this.timeout(100000); + it('Console', async function () { + const exchangeService = getExchangeService(); + const priceMap = await exchangeService.fetchBoundPriceMap() + const price = await exchangeService.fetchUSDPrice('DICE'); + + console.log('price', price); + + expect(price).to.be(12); + }); +}); From 4433a51c33bf56e6f97be2549cee2548d586646e Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 06:59:06 -0700 Subject: [PATCH 56/74] Typo in makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8dcdcaf..49ecbbb 100755 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ serve: docker exec -it ${NAME}_web_1 npm start ## Runs webpack (development) -make webpack: +webpack: docker exec -it ${NAME}_web_1 npm run dev ## start docker shell From 50308fcc04c5b457f4ec95485da7cc7824ce98e6 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:50:57 -0700 Subject: [PATCH 57/74] Compress logos --- public/img/logos/adtoken.png | Bin 3430 -> 2172 bytes public/img/logos/aeternity.png | Bin 17379 -> 1338 bytes public/img/logos/darcrus.png | Bin 2278 -> 1118 bytes public/img/logos/ethereum.png | Bin 16979 -> 1060 bytes public/img/logos/iota.png | Bin 16379 -> 834 bytes public/img/logos/mysterium.png | Bin 6065 -> 4051 bytes public/img/logos/qtum.png | Bin 4227 -> 2426 bytes public/img/logos/quantum-resistant-ledger.png | Bin 3268 -> 1597 bytes 8 files changed, 0 insertions(+), 0 deletions(-) diff --git a/public/img/logos/adtoken.png b/public/img/logos/adtoken.png index 029c40b00b495aedbd9866823981006c237ecb17..85ac82476a9ae29bc5bf3f3cb98ff970773f43b7 100644 GIT binary patch delta 2160 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 E0HHhIn*aa+ diff --git a/public/img/logos/aeternity.png b/public/img/logos/aeternity.png index 812e82d7c281ac165c5a936571fbd6b94150c272..b0c012c209c77837c5fd6420185f1a9bcdba239e 100644 GIT binary patch delta 1328 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 Q@c;k-07*qoM6N<$f{Gm*X8-^I literal 2278 zcmaJ@c~leU7EfKl4S^ET>N6y=SeRrc$z&rakOT=DKsG^8%uEJ|kcA|gs6ZboXh22K zR;maO>c-K!fZ!HTG$o{Dg<*mbfy=H4niy%$fZF{0EBoTmj^k`a*|G`=Fw<+y`HLPP*s{l8pP#tX&{|OrvtbKpxvOWkg91A6{IN?qjA00 z*6PBr|I_%awl-pe8l#0_TGcuYiq|87G6u$T_xFxQ6>&Da5RDu!iZn&2Lf0uUrA{pL zA>%hxnOw$W(4}Ak1H=HB&6WZPmnj9LbPgMUWlS~~k%3G$4363P9G=Bt2m}0K2o^8{ zAV|dKG9j*?KSv1r2|);k{Kv3jrB)|ZqS%;kIqv%-7W`W*PoTl1I+Z3urAis=g3u(D zPNhv!sYwFCXw_jVO!8PESISg+?ZVMQeTZ9#Y2@oMS%5~RAid8tPyQJeObkX5EP)9y zU`PgVKqdp=G7t!0vLOUzNE7G@T$KC~FZ)XdKXfWC!6Q+R5#q`4fuVB|6p+GF7=R#* z1#nSB24DyaVlg0ug`xzjhK|>vC?>K`_fjIFLFzJPuM;`VC#0> zJ-z4VlY&8#o6Y`+w5zUu%N=LM1*ODY3`N4P@OY`*zLJ!xxUC~F3DXqts?nwLr(FNaqql}XXHAVPJ7l_ z&ksndW$8y{Pb2# zRr1kcAG=fQbAzD;$}4*)%d8ZX4ldceNq(rR-2%G#XB4?Cp-V$7#@6M;8ZqDNqB+&X z&a?Pu$9k--N3B~2jf1D$Xe&e4bf)xDT`X;m?yr@5HLne<&57{iOWEy?nH!X%!>7)V z)N%k~$I$JvMbFX;{M#hm`^^J}7vbj?ntFPA_yd(*Nu8DZx_ZufAZ^Yr`(u~^k1A)J z{f_5l-aTJL(IH#c6;CdF>RiyaL?EZw{(H|aooBDH?gytA9-7!vmhMOc>W*!(p62+j znqhw&YHM}R_@Qy5xn{@fsOi5STlLj}j^-kt6UhmwKO9Wd-;JzwIk|H|UY>5cM=wlo zuX{`FI!NYP%HN8X^D8b#Mr-GWOftXnlEtJ)@t2Md48PpfTEcwOyr4yYEOnRY($Mc+ zA%7UEz9a7<#ZbpLJMYaCo-4f~VrALvS&6jnxN+vn=AWDSXR_}&4R$-&@`LElCcT`M zpTBDFQm3l_pm!n{SP5(&8(4d}FejwjF%Wu3{U6in9Am09xxz!MPH9>mU&fy3# zqWfs^Pv5Uzadcj^Zu{HR$rU>)2G@`_(RR-~%r7~l%xjv!LLS>b*LwFIX|**2yatK; zw=Z)08=AK6JrYDShF>`uUMCb!D=&TFRQWG>=i6@n>~qTp4_$z>^v-eH>Njy+?}Y|r zneSNtJZTV{M8KoM<6_Q%4wpFsZ!PU`-GfU`%Hy|gbg(&JDBWx93f|dUt4dhs_cULL zvi5)7i0()~Q2$jZV%HZN-?)>kn3Bsgb`r|xyL)abuY{fZ$2-pTZCP9J6nw6@`p=MY z-k}q@O&ybWc^G~DVk^>&w+AW>-cUKER!q;BceI8`PiO2(BR=en3Uy^1t&3Ve+;1xC z%$V=^IM8OJp~)>eYu`NQn9SdnETt!p?T>{IzP0`e7MCDtwo~6O3->@PUf!`kl5@Vgti{Rh5hW$u((r_H z7~Dzk$aEZDaPzk>ErK^`7h^|K=6g4JrrGohHn(tYN6o6OI9;?-k}A8fXT#!-0n;n!m{z=?j&uJ=tC`G6f`vUnV`m(&9~{e;#5{ Lu<)e+n$7%f_ diff --git a/public/img/logos/ethereum.png b/public/img/logos/ethereum.png index d09c29ee88fb33c27ba115535b0ce8b29cd97ea8..b71378c26de406e8b3a93ba6f405b5b5d769e767 100644 GIT binary patch delta 1048 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 Z!0r8>m;8R(t*v;xxH+$Mk~sv%{TnU)4)y>5 diff --git a/public/img/logos/iota.png b/public/img/logos/iota.png index 002692f3d55a63a23da6ff7ee431c010b9e39922..6818b089444457bd233065f82ea8ec39e1a74708 100644 GIT binary patch delta 822 zcmV-61IhgRf5HZk8Gi%-00BX^>DK@N0|`k)K~zW$1;Ke}76bqX(D!ZM+>y@7j>tK6 zblIkEm90xGyk=!Fp|XUqq%jn-!W0axK2> zu|^3C!(Zw0DyT$%oCVwB@ieD(QmFk0DoBPNl|6D_yl+qJ*FvG z48TG=Omjd505BV%SHA#2wQ4a3Oe;aVVXG`exfX&IdQjd*fK?Kau=?x=51keIbU_h(e0k|H~BHFy*GG0*-O9hC1 z#sZ+*zeedrZ;5zIL6>3OE&-~PEBMDxibZ^fM$zvh4}aS0W#=%W)=`H5Zp0#N##3TR!I#ekWOtBep835o@!D#_Mdl&!! z0001hVG(}<002OV$FyU;qo%93%0vJ#-RF*J1pokmjUviS*NtXtj1z$J006c)4-R@AYefKe8dQ!>^TlBR003Cx2~0NC48U1K zI>0(_s&yp*002;Gx!K^N7!P*YuSTccx&QzG0090I&w+>`KtwdCci1=P0ssI2uvMH! z8!w&}aW$Y%L{tI*001;t<2JwpE;wZh0Ez(cKVD1*xjQVxe*gdg07*qoM6N<$f^3FH Ak^lez literal 16379 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 diff --git a/public/img/logos/mysterium.png b/public/img/logos/mysterium.png index 3557f25c4f4d1bf21112089e64b7a4d9a89595cd..c0c086255ebc970e5202fb0954227843d5be74aa 100644 GIT binary patch literal 4051 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 FV1m?-`IGFQcF|S@Oo9eegUK;*WWku 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 literal 3268 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 From 27de0e6164483f50fa75cae9f667dc7145512240 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:51:35 -0700 Subject: [PATCH 58/74] fix(exchange): Dropdowns dont work --- .../exchange/components/ExchangeSelect.jsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/client/exchange/components/ExchangeSelect.jsx b/src/client/exchange/components/ExchangeSelect.jsx index f4023a8..d7555af 100644 --- a/src/client/exchange/components/ExchangeSelect.jsx +++ b/src/client/exchange/components/ExchangeSelect.jsx @@ -18,7 +18,7 @@ type Props = { }, active: string, which: string, - onSelect: (which: string, symbol: string) => void, + onSelectCoin: (which: string, symbol: string) => void, onClose: () => void, inputRef: (c: HTMLDivElement) => void }; @@ -44,8 +44,20 @@ class ExchangeSelect extends React.Component { } } + handleSelectCoin = (event: MouseEvent) => { + if (!(event.currentTarget instanceof HTMLDivElement)) return; + const el: HTMLDivElement = event.currentTarget; + const symbol = el.getAttribute('data-symbol'); + const { which, onSelectCoin, onClose, active } = this.props; + + if (symbol && symbol !== active) { + onSelectCoin(which, symbol); + onClose(); + } + } + render() { - const { which, classes, coins, active, onSelect } = this.props; + const { classes, coins, active } = this.props; return (
(
onSelect(coin.symbol, which)} + data-symbol={coin.symbol} + onClick={this.handleSelectCoin} className={classNames(classes.item, { 'is-active': active === coin.symbol })} From fb19ee0d13495987069ebd2b8e0f507b4bed652b Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:52:00 -0700 Subject: [PATCH 59/74] Fix(sorting): Current price sort doesn't work --- src/client/rankings/lib/sort.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/client/rankings/lib/sort.js b/src/client/rankings/lib/sort.js index 2094e98..3d88721 100644 --- a/src/client/rankings/lib/sort.js +++ b/src/client/rankings/lib/sort.js @@ -1,5 +1,11 @@ +/** + * Logic for sorting. To be used as a callback for Array.prototype.sort + * @flow + */ +/* eslint-disable max-params, complexity, max-statements */ import * as utils from '~/app/utils'; import moment from 'moment'; +import type { $ICO, $Currency } from 'shared/types.flow'; /** * Handles sorting logic for ranking. @@ -9,9 +15,15 @@ import moment from 'moment'; * @param {Boolean} ascending * @return {Number} */ -export default function handleSort(_a, _b, sortBy, ascending, currency, startDate) { - let a = _a[sortBy]; - let b = _b[sortBy]; +export default function handleSort( +_a: $ICO, +_b: $ICO, +sortBy: string, +ascending: boolean, +currency: $Currency +) { + let a = _a[sortBy] || _a; + let b = _b[sortBy] || _b; if (sortBy.includes('.')) { a = sortBy.split('.').reduce((p, c) => p[c], _a); @@ -22,8 +34,8 @@ export default function handleSort(_a, _b, sortBy, ascending, currency, startDat case 'name': { a = a.toLowerCase(); b = b.toLowerCase(); - if (a < b) return ascending ? 1 : -1; - if (a > b) return ascending ? -1 : 1; + if (a < b) return ascending ? -1 : 1; + if (a > b) return ascending ? 1 : -1; return 0; } case 'start_date': { @@ -31,8 +43,8 @@ export default function handleSort(_a, _b, sortBy, ascending, currency, startDat const ma = moment(a, format); const mb = moment(b, format); - if (ma < mb) return ascending ? 1 : -1; - if (ma > mb) return ascending ? -1 : 1; + if (ma < mb) return ascending ? -1 : 1; + if (ma > mb) return ascending ? 1 : -1; return 0; } case 'ico_price': { From 5515130da7f4a03e111fed9219b8c6c46f99853a Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:52:34 -0700 Subject: [PATCH 60/74] add(tokens): EOS, Voise --- public/img/logos/eos.png | Bin 0 -> 1657 bytes public/img/logos/voise.png | Bin 0 -> 3506 bytes src/server/lib/ico-data.js | 31 +++++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 public/img/logos/eos.png create mode 100644 public/img/logos/voise.png diff --git a/public/img/logos/eos.png b/public/img/logos/eos.png new file mode 100644 index 0000000000000000000000000000000000000000..0861f92bf5c758a73b16dcf0b1f05e88ee2c8078 GIT binary patch literal 1657 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

5Ui>Dq+zN4*Z@M zG_J6LS0(xagc)*9_ z<&Dz_X+lpli=JY2yms`$5Qc{MIi=?Gl#kRa5h6TD-*+DfKyW}bPof0X!O3^P|H~OO zLK!se$M#Q3ukAuvE&}c}+|DM)2LcUkrMVN(5D!3bpmzqthWOO7-qb}$>Xkf75}vlg z#dT=tBFL3m){_27seaiT10`ud8DS18;7o54P6#F4WnAi}@u}f9dRk#qg02)%3AKc5 zpz1_O@@`5DCw%j!ia!PQhu$oV@(Muy#u!1hK3z`as3yiJe63gKbECb2P@Lc@@Ysv)GF~aDo5PUD&(~_w zRR?n-p!iHi@D)Uj@x9|LCbI<9gb8{96r57-(7uA;O*I*G?S%3r%iR_NQtLJFffDcl z1Io<`wWM6`fOo{rF%UceaUgMp60(5c&8Wi9 z4o7jeLw^Kbc>-ulCv3O`^Ctcfsyz!vzEqfZ+=uQDWTsaryDz&4y)MYRo(MU>_421; z2zy}BdO)^SKyl241^NStOh7jE)*mL+mce~x2vimb+o9rhA)qCRsCX&J!;L^Lvt^^h z327~u<-$#UeP;74z-4#@V@}9A?Y?yUeBiYJuy{c=`9+BaS^7=)H^D;pg>a}4_=wTh?S&T zs=Sv60~5DXny+Q>4c1g!`R)51B7&axMT#FF^VT{M;RZ(2i=T0Yr*Ew>Exw zIUW>;7)#z-lM!xmO?1#A!~)Dh9Or3w`EU~`&1s2c_yF`F&jt6ktIR;#JAi8Ul$-ly z+dd_f;rxD6Qhb)QCt`?;p$(2e&A{bqT#1JXDV7L-Y_aVlYYJ)IVNGcxAWi{(%c2`C zm^-ReX1Ze#E6>Az_l`*YGjY_NS(quO?ZJ%PV{p|xQ%AZJAuKLRq>=Uxks9DF5T zTEhzf0}=3QC1?|_$qsr^3lKaX5UPt-T!3B++G!QgCx3VE0k1*cWB@QW*O>C%6q1kR zulXVcH3#Zes3(g+_2eQdYOKym zbD@@O4iNNNNEhC$&{A_7fiO;X{)SZQ>?%!q2uSQJa4?;IOX>oxds|G!^I+Z8P>+NN z!Ja9*@T%(;FI+6Q0XtO0jKXV;pY*C(v@8<*P7UH=NW!g#hj gb@Tdc=Y$UH|D_Z06avm`RR91007*qoM6N<$g7`O{5dZ)H literal 0 HcmV?d00001 diff --git a/src/server/lib/ico-data.js b/src/server/lib/ico-data.js index a7025cf..ff30711 100644 --- a/src/server/lib/ico-data.js +++ b/src/server/lib/ico-data.js @@ -1,5 +1,36 @@ /* eslint-disable */ module.exports = [ + { + id: 'eos', + is_erc20: true, + contract_address: '0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0', + name: 'EOS', + symbol: 'EOS', + ticker: 'eos', + eth_price_at_launch: 262.38, + btc_price_at_launch: 2508.52, + raise: 185000000, + amount_sold_in_ico: 200000000, + start_date: '06/26/2017', + supported_changelly: false + }, + { + /** + * Sources: + * Voise team member + */ + id: 'voise', + is_erc20: true, + name: 'Voise', + symbol: 'VSM', + eth_price_at_launch: 248.04, + btc_price_at_launch: 2628.94, + raise: 715835, + amount_sold_in_ico: 825578, + start_date: '06/05/2017', + ticker: 'voise', + supported_changelly: false + }, { id: 'darcrus', is_erc20: false, From a5aeb6a0c5e9bea6a94a7215d12237f33e31eac8 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:52:58 -0700 Subject: [PATCH 61/74] Refactor ICO Data --- src/server/lib/ico-data.js | 1134 ++++-------------------------------- 1 file changed, 107 insertions(+), 1027 deletions(-) diff --git a/src/server/lib/ico-data.js b/src/server/lib/ico-data.js index ff30711..9cdd3ee 100644 --- a/src/server/lib/ico-data.js +++ b/src/server/lib/ico-data.js @@ -40,40 +40,57 @@ module.exports = [ btc_price_at_launch: 824.23, raise: 285203, amount_sold_in_ico: 14055048, - implied_token_price: 0.020, - start_date: '12/21/2016', // ref. https://trello.com/c/Osc4Bt1X/90-issue-32-coins-to-list + start_date: '12/21/2016', ticker: 'darcrus', supported_changelly: true }, { + /** + * Sources: + * https://qtum.org/en/crowdsale + * https://tokenmarket.net/blockchain/bitcoin/assets/qtum/ + */ id: 'qtum', is_erc20: false, name: 'QTUM', symbol: 'QTUM', eth_price_at_launch: 22.18, btc_price_at_launch: 1181.17, - raise: 14887694.5638, // 11,156.766 BTC and 77,081.031 ETH $13178037.29622 + $1709657.26758 - amount_sold_in_ico: 51000000, // ref https://qtum.org/en/crowdsale - implied_token_price: 0.292, - start_date: '03/12/2017', // ref. https://tokenmarket.net/blockchain/bitcoin/assets/qtum/ + // 11,156.766 BTC + 77,081.031 ETH = $13178037.29622 + $1709657.26758 + raise: 14887694.5638, + raise_by_currency: { + btc: 11156.766, + eth: 77081.031 + }, + amount_sold_in_ico: 51000000, + start_date: '03/12/2017', ticker: 'qtum', supported_changelly: false }, { + /** + * Sources: + * https://steemit.com/qrl/@kevinternet/qrl-quantum-resistant-ledger-price-forecast + * https://tokenmarket.net/blockchain/blockchain/assets/quantum-resistant/ + */ id: 'quantum-resistant-ledger', is_erc20: true, name: 'Quantum Resistant Ledger', symbol: 'QRL', eth_price_at_launch: 205.55, btc_price_at_launch: 2252.71, - raise: 4000000, // Unknown BTC and ETH amount https://medium.com/the-quantum-resistant-ledger/without-you-there-is-no-qrl-182f7962e870 - amount_sold_in_ico: 52000000, // ref https://steemit.com/qrl/@kevinternet/qrl-quantum-resistant-ledger-price-forecast - implied_token_price: 0.077, // ref https://steemit.com/qrl/@kevinternet/qrl-quantum-resistant-ledger-price-forecast - start_date: '05/01/2017', // ref. https://tokenmarket.net/blockchain/blockchain/assets/quantum-resistant/ + raise: 4000000, // Unknown BTC and ETH amount + amount_sold_in_ico: 52000000, + start_date: '05/01/2017', ticker: 'quantum-resistant-ledger', supported_changelly: false }, { + /** + * Sources: + * https://twitter.com/MysteriumNet/status/869678853404454914 + * https://www.smithandcrown.com/sale/mysterium2/ + */ id: 'mysterium', is_erc20: true, name: 'Mysterium', @@ -81,27 +98,37 @@ module.exports = [ eth_price_at_launch: 205.55, btc_price_at_launch: 2252.71, raise: 14106690.95, // 68629 ETH - amount_sold_in_ico: 80000000, // ref https://twitter.com/MysteriumNet/status/869678853404454914 - implied_token_price: 0.157, // Token supply was 90m while 80m tokens were distributed on ICO. - start_date: '05/30/2017', // ref. https://www.smithandcrown.com/sale/mysterium2/ + amount_sold_in_ico: 80000000, + start_date: '05/30/2017', ticker: 'mysterium', supported_changelly: false }, { + /** + * Sources: + * https://bitcointalk.org/index.php?topic=1262688.0 + * https://bitcointalk.org/index.php?topic=1262688.0 https://medium.com/@cryptojudgement/iota-promise-of-a-bright-crypto-future-6b7517349e32 + */ id: 'iota', is_erc20: false, name: 'IOTA', symbol: 'MIOTA', eth_price_at_launch: 0.883399, btc_price_at_launch: 324.99, - raise: 434511.63, // 1337 BTC - amount_sold_in_ico: 999999999, // ref https://bitcointalk.org/index.php?topic=1262688.0 - implied_token_price: 0.0004, - start_date: '11/25/2015', // ref. https://bitcointalk.org/index.php?topic=1262688.0 https://medium.com/@cryptojudgement/iota-promise-of-a-bright-crypto-future-6b7517349e32 + raise: 434511.63, + raise_by_currency: { + btc: 1337 + }, + amount_sold_in_ico: 999999999, + start_date: '11/25/2015', ticker: 'iota', supported_changelly: false }, { + /** + * Sources: + * http://www.blockchaindailynews.com/MetaX-Completes-10-Million-adToken-ADT-Sale_a25622.html + */ id: 'adtoken', is_erc20: true, name: 'adToken', @@ -113,54 +140,77 @@ module.exports = [ eth: 33333.33334 }, amount_sold_in_ico: 1000000000, - implied_token_price: 0.0087, - start_date: '06/26/2017', // ref. http://www.blockchaindailynews.com/MetaX-Completes-10-Million-adToken-ADT-Sale_a25622.html + start_date: '06/26/2017', // ref. ticker: 'adtoken', supported_changelly: false }, { + /** + * Sources: + * https://blog.ethereum.org/2014/07/22/launching-the-ether-sale/ + * https://blog.ethereum.org/2014/08/08/ether-sale-a-statistical-overview/ + * + * Notes: + * - ICO price was 2000 ETH for 1 BTC + */ id: 'ethereum', is_erc20: false, name: 'Ethereum', symbol: 'ETH', eth_price_at_launch: 0.31142, // 2000 ETH = 1 BTC btc_price_at_launch: 622.84, - raise: 15571000, // 25000 BTC - amount_sold_in_ico: 50000000, // Found approx amount ref https://blog.ethereum.org/2014/08/08/ether-sale-a-statistical-overview/ - implied_token_price: 0.248, - start_date: '07/22/2014', // ref. https://blog.ethereum.org/2014/07/22/launching-the-ether-sale/ + raise: 15571000, + amount_sold_in_ico: 50000000, + start_date: '07/22/2014', ticker: 'ethereum', - supported_changelly: true + supported_changelly: true, + raise_by_currency: { + btc: 25000 + } }, - // { - // id: 'aeternity-two', - // is_erc20: false, - // name: 'Aeternity Phase II', - // symbol: 'AE', - // eth_price_at_launch: 185.94, - // btc_price_at_launch: 2183.63, - // raise: 21844271.49391, // 104,148.741 ETH, 1,135.199 BTC raised // $19365416.90154 + $2478854.59237 - // amount_sold_in_ico: 88139450.839, // ref https://wallet.aeternity.com/ - // implied_token_price: 0.248, - // start_date: '05/29/2017', // ref. https://tokenmarket.net/blockchain/aeternity/assets/aeternity/ - // ticker: 'aeternity', - // supported_changelly: false - // }, { + /** + * Sources: + * https://wallet.aeternity.com/ + * https://www.smithandcrown.com/aeternity-token-sale-ico-oracle-machine/ + * https://wallet.aeternity.com/ + */ id: 'aeternity', is_erc20: false, name: 'Aeternity Phase I', symbol: 'AE', eth_price_at_launch: 45.88, btc_price_at_launch: 1129.90, - raise: 5940998.795, // 121,396.731 ETH, 328.628 BTC raised // $5569682.01828 + $371316.7772 https://wallet.aeternity.com/ - amount_sold_in_ico: 139089935.082, // ref https://wallet.aeternity.com/ - implied_token_price: 0.043, // raise/amount_sold_in_ico - start_date: '04/03/2017', // ref. https://www.smithandcrown.com/aeternity-token-sale-ico-oracle-machine/ + // (121,396.731 ETH + 328.628 BTC) = ($5569682.01828 + $371316.7772) + raise: 5940998.795, + raise_by_currency: { + eth: 121396.731, + btc: 328.628 + }, + amount_sold_in_ico: 139089935.082, // ref + start_date: '04/03/2017', // ref. ticker: 'aeternity', supported_changelly: false }, { + /** + * Source: + * Calculated by reading contract on etherscan + * + * NOTE The amount of tokens distributed to ICO participants was not static, + * it was determined by a formula within the smart contract. + * + * Total supply of SNT: 6804870174 + * --- Breakdown --- + * Devs: 20% + * Reserve: 29% + * SGT: 6.9% + * - Formula to calculate SGT percentage: + * = 10% * (Total SGT supply / Max SGT Supply) + * = 10% * (346447013 / 500000000) + * = .069 + * Contributors: 44.1% (100 - 20 - 29 - 6.9) + */ id: 'status', ticker: 'status', name: 'Status', @@ -173,19 +223,7 @@ module.exports = [ raise_by_currency: { eth: 300000 }, - // Total supply of SNT: 6804870174 - // --- Breakdown --- - // Devs: 20% - // Reserve: 29% - // SGT: 6.9% - // - Formula: - // 10& * (Total SGT supply / Max SGT Supply) - // = 10% * (346447013 / 500000000) - // = .069 - // Contributors: 44.1% (100 - 20 - 29 - 6.9) amount_sold_in_ico: 3000947746, - implied_token_price: 0.03648, - total_supply: 6804870174.87, start_date: '06/20/2017', supported_changelly: false, icon_ext: 'svg' @@ -204,8 +242,6 @@ module.exports = [ eth: 396720 }, amount_sold_in_ico: 39600000, - implied_token_price: 3.864, - total_supply: 79300000, start_date: '06/12/2017', supported_changelly: false }, @@ -223,7 +259,6 @@ module.exports = [ eth: 56565 }, amount_sold_in_ico: 125000000, - implied_token_price: 0.1198, start_date: '06/07/2017', // or june 3 for presale supported_changelly: false }, @@ -240,7 +275,6 @@ module.exports = [ eth: 32529.87 }, amount_sold_in_ico: 70000000, - implied_token_price: 0.103630872, start_date: '05/31/2017', ticker: 'patientory', supported_changelly: false @@ -255,7 +289,6 @@ module.exports = [ btc_price_at_launch: 2271.35, raise: 35000000, amount_sold_in_ico: 1000000000, - implied_token_price: 0.035, start_date: '05/31/2017', ticker: 'basic-attention-token', supported_changelly: false, @@ -270,7 +303,6 @@ module.exports = [ btc_price_at_launch: 288, raise: 269029.44, // 934.13 BTC amount_sold_in_ico: 13521238.01, - implied_token_price: 0.0199, start_date: '07/29/2015', ticker: 'bitcrystals', supported_changelly: true @@ -285,7 +317,6 @@ module.exports = [ btc_price_at_launch: 744.60, raise: 841350.21, // 77687 ETH amount_sold_in_ico: 9525397, - implied_token_price: 0.088, start_date: '11/01/2016', ticker: 'swarm-city', supported_changelly: true @@ -300,7 +331,6 @@ module.exports = [ btc_price_at_launch: 667.81, raise: 1005487.65, amount_sold_in_ico: 850000, - implied_token_price: 1.18, start_date: '06/21/2016', ticker: 'pluton', icon_ext: 'svg', @@ -316,7 +346,6 @@ module.exports = [ btc_price_at_launch: 1223.99, raise: 10000000, amount_sold_in_ico: 10000000, - implied_token_price: 1, start_date: '04/10/2017', ticker: 'bcap', supported_changelly: false @@ -330,7 +359,6 @@ module.exports = [ btc_price_at_launch: 667.66, raise: 610908, // 915 BTC raised amount_sold_in_ico: 84000000, - implied_token_price: 0.007, start_date: '06/20/2016', ticker: 'stratis', supported_changelly: true @@ -346,8 +374,6 @@ module.exports = [ raise: 311162.77, total_amount_of_tokens: 7001622.64879, amount_sold_in_ico: 4501622, - ownership_pct: 0.6429, - implied_token_price: 0.069, start_date: '02/13/2017', ticker: 'etheroll', supported_changelly: false @@ -362,8 +388,6 @@ module.exports = [ raise: 5163000, total_amount_of_tokens: 184190414, amount_sold_in_ico: 131038286, - ownership_pct: 0.7114, - implied_token_price: 0.0394, start_date: '04/06/2017', ticker: 'humaniq', supported_changelly: false @@ -375,41 +399,12 @@ module.exports = [ name: 'Waves', eth_price_at_launch: 7.44, btc_price_at_launch: 377, - status: 'Completed', - type: 'Decentralized Applications Platform', raise: 16010008, total_amount_of_tokens: 100000000, amount_sold_in_ico: 85000000, - ownership_pct: '85.00%', - project_valuation: '$18,835,304', - implied_token_price: 0.19, - implied_token_price_check: '$0.19', start_date: '4/12/2016', ico_end_date: '2016-05-31', - today: '2017-05-18', - month: 'May16', - days: '352', - months: '11.73333333', - years: '0.9643835616', ticker: 'waves', - available_supply: '100,000,000.00', - total_supply: '100,000,000.00', - market_cap: '$95,394,700', - implied_project_valuation: '$95,394,700', - token_raise: '$0.19', - token_now: '$0.95', - total_return: '406.47%', - eth_raise: '$13.37', - eth_now: '$85.09', - eth_return: '540.01%', - btc_raise: '$533.70', - btc_now: '$1,751.87', - bitcoin_return: '228.25%', - excess_return_eth: '-133.55%', - excess_return_btc: '178.22%', - token: '15.05%', - eth: '17.34%', - btc: '10.82%', supported_changelly: true }, { @@ -419,42 +414,13 @@ module.exports = [ contract_address: '0xaaaf91d9b90df800df4f55c205fd6989c977e73a', btc_price_at_launch: 1315, name: 'Tokencard', - status: 'Completed', - type: 'Banking', raise: 12700000, total_amount_of_tokens: 39406760, amount_sold_in_ico: 23644056, - ownership_pct: '60.00%', - project_valuation: '$21,166,667', - implied_token_price: 0.54, - implied_token_price_check: '$0.54', start_date: '5/2/2017', ico_end_date: '2017-05-02', eth_price_at_launch: 80.64, - today: '2017-05-18', - month: 'May17', - days: '16', - months: '0.5333333333', - years: '0.04383561644', ticker: 'tokencard', - available_supply: '23,644,056.00', - total_supply: '39,406,760.00', - market_cap: '$25,063,409', - implied_project_valuation: '$41,772,348', - token_raise: '$0.54', - token_now: '$1.06', - total_return: '97.35%', - eth_raise: '$78.91', - eth_now: '$85.09', - eth_return: '8.44%', - btc_raise: '$1,460.62', - btc_now: '$1,751.87', - bitcoin_return: '19.94%', - excess_return_eth: '88.91%', - excess_return_btc: '77.41%', - token: '264.13%', - eth: '15.41%', - btc: '41.29%', supported_changelly: false }, { @@ -463,42 +429,13 @@ module.exports = [ name: 'Gnosis', is_erc20: true, btc_price_at_launch: 1155.05, - status: 'Completed', - type: 'Prediction Market', raise: 10682516, total_amount_of_tokens: '10,000,000', amount_sold_in_ico: 418760, - ownership_pct: '4.19%', - project_valuation: '$298,500,000', - implied_token_price: 29.85, - implied_token_price_check: '$29.85', start_date: '4/24/2017', ico_end_date: '2017-04-24', eth_price_at_launch: 49.19, - today: '2017-05-18', - month: 'Apr17', - days: '24', - months: '0.8', - years: '0.06575342466', ticker: 'gnosis-gno', - available_supply: '1,104,590.00', - total_supply: '10,000,000.00', - market_cap: '$115,848,295', - implied_project_valuation: '$1,048,790,004', - token_raise: '$29.85', - token_now: '$104.88', - total_return: '251.35%', - eth_raise: '$49.99', - eth_now: '$85.09', - eth_return: '71.17%', - btc_raise: '$1,252.79', - btc_now: '$1,751.87', - bitcoin_return: '39.84%', - excess_return_eth: '180.18%', - excess_return_btc: '211.52%', - token: '391.65%', - eth: '96.23%', - btc: '52.95%', supported_changelly: true }, { @@ -507,42 +444,13 @@ module.exports = [ name: 'iEx.ec', is_erc20: true, btc_price_at_launch: 1127.85, - status: 'Completed', - type: 'Computing', raise: 10682516, total_amount_of_tokens: '87,000,000', amount_sold_in_ico: 60000000, - ownership_pct: '68.97%', - project_valuation: '$17,630,496', - implied_token_price: 0.20, - implied_token_price_check: '$0.20', start_date: '4/19/2017', ico_end_date: '2017-04-19', eth_price_at_launch: 49.5, - today: '2017-05-18', - month: 'Apr17', - days: '29', - months: '0.9666666667', - years: '0.07945205479', ticker: 'rlc', - available_supply: '78,070,793.00', - total_supply: '86,999,785.00', - market_cap: '$44,069,792', - implied_project_valuation: '$49,110,074', - token_raise: '$0.20', - token_now: '$0.56', - total_return: '178.55%', - eth_raise: '$49.78', - eth_now: '$85.09', - eth_return: '71.90%', - btc_raise: '$1,201.38', - btc_now: '$1,751.87', - bitcoin_return: '45.82%', - excess_return_eth: '106.66%', - excess_return_btc: '132.73%', - token: '192.85%', - eth: '75.47%', - btc: '48.53%', supported_changelly: true }, { @@ -551,42 +459,13 @@ module.exports = [ name: 'Iconomi', is_erc20: true, btc_price_at_launch: 510.91, - status: 'Completed', - type: 'Investing', raise: 10682516, total_amount_of_tokens: '100,000,000', amount_sold_in_ico: 85000000, - ownership_pct: '85.00%', - project_valuation: '$12,567,666', - implied_token_price: 0.13, - implied_token_price_check: '$0.13', start_date: '08/25/2016', ico_end_date: '2016-09-26', eth_price_at_launch: 10.99, - today: '2017-05-18', - month: 'Sep16', - days: '234', - months: '7.8', - years: '0.6410958904', ticker: 'iconomi', - available_supply: '87,000,000.00', - total_supply: '100,000,000.00', - market_cap: '$49,470,810', - implied_project_valuation: '$56,863,000', - token_raise: '$0.13', - token_now: '$0.57', - total_return: '352.45%', - eth_raise: '$12.96', - eth_now: '$85.09', - eth_return: '560.26%', - btc_raise: '$605.25', - btc_now: '$1,751.87', - bitcoin_return: '189.45%', - excess_return_eth: '-207.81%', - excess_return_btc: '163.01%', - token: '21.68%', - eth: '27.71%', - btc: '14.81%', supported_changelly: false }, { @@ -596,42 +475,13 @@ module.exports = [ is_erc20: true, btc_price_at_launch: 661.99, contract_address: '0xa74476443119A942dE498590Fe1f2454d7D4aC0d', - status: 'Completed', - type: 'Computing', raise: 8596000, total_amount_of_tokens: '1,000,000,000', amount_sold_in_ico: 820000000, - ownership_pct: '82.00%', - project_valuation: '$10,482,927', - implied_token_price: 0.01, - implied_token_price_check: '$0.01', start_date: '11/11/2016', ico_end_date: '2016-11-13', eth_price_at_launch: 10.46, - today: '2017-05-18', - month: 'Nov16', - days: '186', - months: '6.2', - years: '0.5095890411', ticker: 'golem-network-tokens', - available_supply: '820,000,000.00', - total_supply: '1,000,000,000.00', - market_cap: '$184,025,220', - implied_project_valuation: '$224,421,000', - token_raise: '$0.01', - token_now: '$0.22', - total_return: '2040.82%', - eth_raise: '$10.10', - eth_now: '$85.09', - eth_return: '747.23%', - btc_raise: '$697.19', - btc_now: '$1,751.87', - bitcoin_return: '151.28%', - excess_return_eth: '1293.60%', - excess_return_btc: '1889.55%', - token: '65.04%', - eth: '41.70%', - btc: '16.26%', supported_changelly: true }, { @@ -641,42 +491,13 @@ module.exports = [ is_erc20: true, contract_address: '0xe7775a6e9bcf904eb39da2b68c5efb4f9360e08c', btc_price_at_launch: 952.99, - status: 'Completed', - type: 'Investing', raise: 7963120, total_amount_of_tokens: '', amount_sold_in_ico: 7963120, - ownership_pct: '', - project_valuation: '', - implied_token_price: 1, - implied_token_price_check: '', start_date: '3/27/2017', ico_end_date: '2017-04-28', eth_price_at_launch: 50.54, - today: '2017-05-18', - month: 'Apr17', - days: '20', - months: '0.6666666667', - years: '0.05479452055', ticker: 'taas', - available_supply: '', - total_supply: '', - market_cap: '', - implied_project_valuation: '', - token_raise: '', - token_now: '', - total_return: '', - eth_raise: '', - eth_now: '', - eth_return: '', - btc_raise: '', - btc_now: '', - bitcoin_return: '', - excess_return_eth: '', - excess_return_btc: '', - token: '', - eth: '', - btc: '', supported_changelly: false }, { @@ -687,85 +508,27 @@ module.exports = [ contract_address: '0xaec2e87e0a235266d9c5adc9deb4b2e29b54d009', eth_price_at_launch: 13.3, btc_price_at_launch: 550.48, - status: 'Completed', - type: 'Media', raise: 7500000, total_amount_of_tokens: '1,000,000,000', amount_sold_in_ico: 500000000, - ownership_pct: '50.00%', - project_valuation: '$15,000,000', - implied_token_price: 0.015, - implied_token_price_check: '$0.02', start_date: '10/5/2016', ico_end_date: '2016-10-29', - today: '2017-05-18', - month: 'Oct16', - days: '201', - months: '6.7', - years: '0.5506849315', ticker: 'singulardtv', - available_supply: '600,000,000.00', - total_supply: '1,000,000,000.00', - market_cap: '$66,799,200', - implied_project_valuation: '$111,332,000', - token_raise: '$0.02', - token_now: '$0.11', - total_return: '642.21%', - eth_raise: '$10.73', - eth_now: '$85.09', - eth_return: '697.48%', - btc_raise: '$708.61', - btc_now: '$1,751.87', - bitcoin_return: '147.23%', - excess_return_eth: '-55.27%', - excess_return_btc: '494.99%', - token: '35.44%', - eth: '36.80%', - btc: '14.68%', supported_changelly: true }, { name: 'Lisk', symbol: 'LSK', is_erc20: false, - status: 'Completed', - type: 'Decentralized Applications Platform', raise: 6500000, total_amount_of_tokens: '100,000,000', amount_sold_in_ico: 85000000, - ownership_pct: '85.00%', - project_valuation: '$7,647,059', - implied_token_price: 0.08, - implied_token_price_check: '$0.08', start_date: '2/22/2016', ico_end_date: '2016-03-21', eth_price_at_launch: 1.12, btc_price_at_launch: 393.98, - today: '2017-05-18', - month: 'Mar16', - days: '423', - months: '14.1', - years: '1.15890411', ticker: 'lisk', id: 'lisk', - available_supply: '106,751,935.00', - total_supply: '106,751,935.00', - market_cap: '$60,156,957', - implied_project_valuation: '$60,156,957', - token_raise: '$0.08', - token_now: '$0.56', - total_return: '636.91%', - eth_raise: '$10.98', - eth_now: '$85.09', - eth_return: '679.33%', - btc_raise: '$409.61', - btc_now: '$1,751.87', - bitcoin_return: '327.69%', - excess_return_eth: '-42.41%', - excess_return_btc: '309.22%', - token: '15.44%', - eth: '15.86%', - btc: '11.02%', supported_changelly: true }, { @@ -774,43 +537,14 @@ module.exports = [ name: 'Matchpool', is_erc20: true, contract_address: '0xf7b098298f7c69fc14610bf71d5e02c60792894c', - status: 'Completed', - type: 'Social Network', raise: 5700000, total_amount_of_tokens: '100,000,000', amount_sold_in_ico: 60000000, - ownership_pct: '60.00%', - project_valuation: '$9,500,000', - implied_token_price: 0.10, - implied_token_price_check: '$0.10', start_date: '4/2/2017', ico_end_date: '2017-04-04', eth_price_at_launch: 50.75, btc_price_at_launch: 1030.59, - today: '2017-05-18', - month: 'Apr17', - days: '44', - months: '1.466666667', - years: '0.1205479452', ticker: 'guppy', - available_supply: '75,000,000.00', - total_supply: '98,855,150.00', - market_cap: '$11,732,925', - implied_project_valuation: '$15,464,801', - token_raise: '$0.10', - token_now: '$0.16', - total_return: '64.67%', - eth_raise: '$43.81', - eth_now: '$85.09', - eth_return: '95.32%', - btc_raise: '$1,148.10', - btc_now: '$1,751.87', - bitcoin_return: '52.59%', - excess_return_eth: '-30.65%', - excess_return_btc: '12.08%', - token: '41.17%', - eth: '58.23%', - btc: '33.93%', supported_changelly: true }, { @@ -819,43 +553,14 @@ module.exports = [ name: 'DigixDAO', is_erc20: true, contract_address: '0xe0b7927c4af23765cb51314a0e0521a9645f0e2a', - status: 'Completed', - type: 'Investing', raise: 5500000, total_amount_of_tokens: '2,000,000', amount_sold_in_ico: 1700000, - ownership_pct: '85.00%', - project_valuation: '$6,470,588', - implied_token_price: 3.24, - implied_token_price_check: '$3.24', start_date: '3/1/2016', ico_end_date: '2016-03-01', eth_price_at_launch: 7.7, btc_price_at_launch: 396.49, - today: '2017-05-18', - month: 'Mar16', - days: '443', - months: '14.76666667', - years: '1.21369863', ticker: 'digixdao', - available_supply: '2,000,000.00', - total_supply: '2,000,000.00', - market_cap: '$87,905,400', - implied_project_valuation: '$87,905,400', - token_raise: '$3.24', - token_now: '$43.95', - total_return: '1258.54%', - eth_raise: '$6.72', - eth_now: '$85.09', - eth_return: '1173.36%', - btc_raise: '$433.62', - btc_now: '$1,751.87', - bitcoin_return: '304.01%', - excess_return_eth: '85.17%', - excess_return_btc: '954.53%', - token: '19.62%', - eth: '19.04%', - btc: '10.06%', supported_changelly: true }, { @@ -864,133 +569,46 @@ module.exports = [ name: 'FirstBlood', is_erc20: true, contract_address: '0xAf30D2a7E90d7DC361c8C4585e9BB7D2F6f15bc7', - status: 'Completed', - type: 'Gaming', raise: 5500000, total_amount_of_tokens: '85,558,364', amount_sold_in_ico: 85558364, - ownership_pct: '100.00%', - project_valuation: '$5,500,000', - implied_token_price: 0.06, - implied_token_price_check: '$0.06', start_date: '9/25/2016', ico_end_date: '2016-09-27', eth_price_at_launch: 12.93, btc_price_at_launch: 535.95, - today: '2017-05-18', - month: 'Sep16', - days: '233', - months: '7.766666667', - years: '0.6383561644', ticker: 'firstblood', - available_supply: '85,558,371.00', - total_supply: '93,468,691.00', - market_cap: '$32,573,098', - implied_project_valuation: '$35,584,652', - token_raise: '$0.06', - token_now: '$0.38', - total_return: '492.24%', - eth_raise: '$13.07', - eth_now: '$85.09', - eth_return: '554.71%', - btc_raise: '$605.13', - btc_now: '$1,751.87', - bitcoin_return: '189.50%', - excess_return_eth: '-62.47%', - excess_return_btc: '302.74%', - token: '26.14%', - eth: '27.71%', - btc: '14.89%', supported_changelly: false }, { name: 'ChronoBank', symbol: 'TIME', - status: 'Completed', is_erc20: true, contract_address: '0x6531f133e6DeeBe7F2dcE5A0441aA7ef330B4e53', - type: 'HR/Recruitment', raise: 5400000, total_amount_of_tokens: '710,113', amount_sold_in_ico: 710113, - ownership_pct: '100.00%', - project_valuation: '$5,400,000', - implied_token_price: 7.60, - implied_token_price_check: '$7.60', start_date: '12/15/2016', ico_end_date: '2017-02-15', eth_price_at_launch: 8.21, btc_price_at_launch: 747.24, - today: '2017-05-18', - month: 'Feb17', - days: '92', - months: '3.066666667', - years: '0.2520547945', ticker: 'chronobank', id: 'chronobank', - available_supply: '710,113.00', - total_supply: '710,113.00', - market_cap: '$12,415,115', - implied_project_valuation: '$12,415,115', - token_raise: '$7.60', - token_now: '$17.48', - total_return: '129.91%', - eth_raise: '$12.91', - eth_now: '$85.09', - eth_return: '562.82%', - btc_raise: '$1,012.45', - btc_now: '$1,751.87', - bitcoin_return: '73.03%', - excess_return_eth: '-432.91%', - excess_return_btc: '56.88%', - token: '31.69%', - eth: '86.53%', - btc: '19.88%', supported_changelly: true }, { name: 'Augur', symbol: 'REP', - status: 'Completed', is_erc20: true, eth_price_at_launch: 1.26, btc_price_at_launch: 434.02, contract_address: '0x48c80F1f4D53D5951e5D5438B54Cba84f29F32a5', - type: 'Prediction Market', raise: 5300000, total_amount_of_tokens: '11,000,000', amount_sold_in_ico: 8800000, - ownership_pct: '80.00%', - project_valuation: '$6,625,000', - implied_token_price: 0.60, - implied_token_price_check: '$0.60', start_date: '8/1/2015', ico_end_date: '2015-10-01', - today: '2017-05-18', - month: 'Oct15', - days: '595', - months: '19.83333333', - years: '1.630136986', ticker: 'augur', id: 'augur', - available_supply: '11,000,000.00', - total_supply: '11,000,000.00', - market_cap: '$174,574,400', - implied_project_valuation: '$174,574,400', - token_raise: '$0.60', - token_now: '$15.87', - total_return: '2535.09%', - eth_raise: '$0.70', - eth_now: '$85.09', - eth_return: '12124.29%', - btc_raise: '$238.10', - btc_now: '$1,751.87', - bitcoin_return: '635.77%', - excess_return_eth: '-9589.20%', - excess_return_btc: '1899.31%', - token: '18.20%', - eth: '27.81%', - btc: '10.74%', supported_changelly: true }, { @@ -999,133 +617,46 @@ module.exports = [ name: 'WeTrust', is_erc20: true, contract_address: '0xcb94be6f13a1182e4a4b6140cb7bf2025d28e41b', - status: 'Completed', - type: 'Financial-Service', raise: 5000000, total_amount_of_tokens: '100,000,000', amount_sold_in_ico: 80000000, - ownership_pct: '80.00%', - project_valuation: '$6,250,000', - implied_token_price: 0.06, - implied_token_price_check: '$0.06', start_date: '3/2/2017', ico_end_date: '2017-04-14', eth_price_at_launch: 17.04, btc_price_at_launch: 1192.549, - today: '2017-05-18', - month: 'Apr17', - days: '34', - months: '1.133333333', - years: '0.09315068493', ticker: 'trust', - available_supply: '92,147,500.00', - total_supply: '100,000,000.00', - market_cap: '$15,689,125', - implied_project_valuation: '$17,026,099', - token_raise: '$0.06', - token_now: '$0.17', - total_return: '172.42%', - eth_raise: '$48.03', - eth_now: '$85.09', - eth_return: '78.16%', - btc_raise: '$1,182.56', - btc_now: '$1,751.87', - bitcoin_return: '48.14%', - excess_return_eth: '94.26%', - excess_return_btc: '124.28%', - token: '145.11%', - eth: '66.80%', - btc: '42.13%', supported_changelly: true }, { name: 'Antshares', symbol: 'ANS', - status: 'Completed', is_erc20: false, - type: 'Real World Assets', raise: 556500, // 2100 BTC @ $265 per BTC total_amount_of_tokens: '', amount_sold_in_ico: 17500000, - ownership_pct: '', - project_valuation: '', - implied_token_price: 0.03, - implied_token_price_check: '', start_date: '10/01/2015', eth_price_at_launch: 12.16, btc_price_at_launch: 579.653, tokens_sold_at_launch: 17500000, raised: 541800, - today: '2017-05-18', - month: 'Sep16', - days: '253', - months: '8.433333333', - years: '0.6931506849', ticker: 'antshares', id: 'antshares', - available_supply: '50,000,000.00', - total_supply: '100,000,000.00', - market_cap: '$23,094,900', - implied_project_valuation: '$46,189,800', - token_raise: '', - token_now: '', - total_return: '', - eth_raise: '', - eth_now: '', - eth_return: '', - btc_raise: '', - btc_now: '', - bitcoin_return: '', - excess_return_eth: '', - excess_return_btc: '', - token: '', - eth: '', - btc: '', supported_changelly: false }, { name: 'Lunyr', symbol: 'LUN', - status: 'Completed', is_erc20: true, contract_address: '0xfa05A73FfE78ef8f1a739473e462c54bae6567D9', - type: 'Wikipedia', raise: 3400000, total_amount_of_tokens: '2,703,356', amount_sold_in_ico: 2108618, - ownership_pct: '78.00%', - project_valuation: '$4,358,974', - implied_token_price: 1.61, - implied_token_price_check: '$1.61', start_date: '3/29/2017', ico_end_date: '2017-04-26', eth_price_at_launch: 50.23, btc_price_at_launch: 962, - today: '2017-05-18', - month: 'Apr17', - days: '22', - months: '0.7333333333', - years: '0.0602739726', ticker: 'lunyr', id: 'lunyr', - available_supply: '2,297,853.00', - total_supply: '2,703,356.00', - market_cap: '$5,565,308', - implied_project_valuation: '$6,547,420', - token_raise: '$1.61', - token_now: '$2.42', - total_return: '50.21%', - eth_raise: '$52.19', - eth_now: '$85.09', - eth_return: '63.96%', - btc_raise: '$1,295.53', - btc_now: '$1,751.87', - bitcoin_return: '35.22%', - excess_return_eth: '-13.75%', - excess_return_btc: '14.98%', - token: '75.50%', - eth: '96.57%', - btc: '51.77%', supported_changelly: false }, { @@ -1134,43 +665,14 @@ module.exports = [ name: 'Melonport', is_erc20: true, contract_address: '0xBEB9eF514a379B997e0798FDcC901Ee474B6D9A1', - status: 'Completed', - type: 'Investment', raise: 2900000, total_amount_of_tokens: '750,000', amount_sold_in_ico: 500000, - ownership_pct: '66.67%', - project_valuation: '$4,350,000', - implied_token_price: 5.80, - implied_token_price_check: '$5.80', start_date: '2/15/2017', ico_end_date: '2017-02-16', eth_price_at_launch: 13.05, btc_price_at_launch: 959.2, - today: '2017-05-18', - month: 'Feb17', - days: '91', - months: '3.033333333', - years: '0.2493150685', ticker: 'melon', - available_supply: '599,400.00', - total_supply: '749,400.00', - market_cap: '$20,856,722', - implied_project_valuation: '$26,076,122', - token_raise: '$5.80', - token_now: '$34.80', - total_return: '499.93%', - eth_raise: '$12.83', - eth_now: '$85.09', - eth_return: '566.95%', - btc_raise: '$1,028.53', - btc_now: '$1,751.87', - bitcoin_return: '70.33%', - excess_return_eth: '-67.02%', - excess_return_btc: '429.60%', - token: '82.00%', - eth: '88.21%', - btc: '19.48%', supported_changelly: true }, { @@ -1178,357 +680,125 @@ module.exports = [ symbol: 'LKK', name: 'Lykke', is_erc20: false, - status: 'Completed', - type: 'Exchange', raise: 2800000, total_amount_of_tokens: '1,285,690,000', amount_sold_in_ico: 50000000, - ownership_pct: '3.89%', - project_valuation: '$71,998,640', - implied_token_price: 0.06, - implied_token_price_check: '$0.06', start_date: '9/16/2016', ico_end_date: '2016-10-09', eth_price_at_launch: 11.94, btc_price_at_launch: 544.68, - today: '2017-05-18', - month: 'Oct16', - days: '221', - months: '7.366666667', - years: '0.6054794521', ticker: 'lykke', - available_supply: '135,772,952.00', - total_supply: '1,285,690,000.00', - market_cap: '$20,972,712', - implied_project_valuation: '$20,972,712', - token_raise: '$0.06', - token_now: '$0.15', - total_return: '175.84%', - eth_raise: '$12.26', - eth_now: '$85.09', - eth_return: '597.96%', - btc_raise: '$618.25', - btc_now: '$1,751.87', - bitcoin_return: '183.36%', - excess_return_eth: '-422.12%', - excess_return_btc: '-7.52%', - token: '14.99%', - eth: '30.56%', - btc: '15.41%', icon_ext: 'svg', supported_changelly: false }, { name: 'Edgeless', symbol: 'EDG', - status: 'Completed', is_erc20: true, contract_address: '0x08711d3b02c8758f2fb3ab4e80228418a7f8e39c', - type: 'Gambling', raise: 2700000, total_amount_of_tokens: '132,046,997', amount_sold_in_ico: 68878821, - ownership_pct: '52.16%', - project_valuation: '$5,176,147', - implied_token_price: 0.04, - implied_token_price_check: '$0.04', start_date: '2/28/2017', ico_end_date: '2017-03-21', eth_price_at_launch: 15.52, btc_price_at_launch: 1117.87, - today: '2017-05-18', - month: 'Mar17', - days: '58', - months: '1.933333333', - years: '0.1589041096', ticker: 'edgeless', id: 'edgeless', - available_supply: '75,573,453.00', - total_supply: '132,046,997.00', - market_cap: '$9,585,283', - implied_project_valuation: '$16,748,048', - token_raise: '$0.04', - token_now: '$0.13', - total_return: '223.56%', - eth_raise: '$42.86', - eth_now: '$85.09', - eth_return: '99.65%', - btc_raise: '$1,085.68', - btc_now: '$1,751.87', - bitcoin_return: '61.36%', - excess_return_eth: '123.91%', - excess_return_btc: '162.20%', - token: '85.11%', - eth: '43.28%', - btc: '28.52%', icon_ext: 'jpg', supported_changelly: true }, { name: 'Wings', symbol: 'WINGS', - status: 'Completed', is_erc20: true, contract_address: '0x667088b212ce3d06a1b553a7221E1fD19000d9aF', - type: 'Decentralized Applications Platform', raise: 2074000, total_amount_of_tokens: '100,000,000', amount_sold_in_ico: 75000000, - ownership_pct: '75.00%', - project_valuation: '$2,765,333', - implied_token_price: 0.03, - implied_token_price_check: '$0.03', start_date: '11/18/2016', ico_end_date: '2017-01-06', eth_price_at_launch: 9.9, btc_price_at_launch: 705.51, - today: '2017-05-18', - month: 'Jan17', - days: '132', - months: '4.4', - years: '0.3616438356', ticker: 'wings', id: 'wings', - available_supply: '89,708,333.00', - total_supply: '100,000,000.00', - market_cap: '$18,695,575', - implied_project_valuation: '$20,840,400', - token_raise: '$0.03', - token_now: '$0.21', - total_return: '653.63%', - eth_raise: '$10.13', - eth_now: '$85.09', - eth_return: '744.72%', - btc_raise: '$937.53', - btc_now: '$1,751.87', - bitcoin_return: '86.86%', - excess_return_eth: '-91.09%', - excess_return_btc: '566.77%', - token: '59.27%', - eth: '63.30%', - btc: '15.50%', supported_changelly: true }, { name: 'Komodo', symbol: 'KMD', is_erc20: false, - status: 'Completed', - type: 'Cryptocurrency', raise: 1983781, total_amount_of_tokens: '', amount_sold_in_ico: 5272740, - ownership_pct: '', - project_valuation: '', - implied_token_price: 0.037, - implied_token_price_check: '', start_date: '10/15/2016', - ico_end_date: '2016-11-14', + ico_end_date: '11/14/2016', eth_price_at_launch: 11.93, btc_price_at_launch: 582.9, - today: '2017-05-18', - month: 'Nov16', - days: '185', - months: '6.166666667', - years: '0.5068493151', ticker: 'komodo', id: 'komodo', - available_supply: '100,936,084.00', - total_supply: '100,936,084.00', - market_cap: '$25,478,892', - implied_project_valuation: '$25,478,892', - token_raise: '', - token_now: '', - total_return: '', - eth_raise: '', - eth_now: '', - eth_return: '', - btc_raise: '', - btc_now: '', - bitcoin_return: '', - excess_return_eth: '', - excess_return_btc: '', - token: '', - eth: '', - btc: '', icon_ext: 'gif', supported_changelly: false }, { name: 'vDice', symbol: 'VSL', - status: 'Completed', is_erc20: true, contract_address: '0x5c543e7AE0A1104f78406C340E9C64FD9fCE5170', - type: 'Gambling', raise: 1800000, total_amount_of_tokens: '33,390,496', amount_sold_in_ico: 33390496, - ownership_pct: '100.00%', - project_valuation: '$1,800,000', - implied_token_price: 0.05, - implied_token_price_check: '$0.05', start_date: '11/15/2016', ico_end_date: '2016-12-15', eth_price_at_launch: 9.99, btc_price_at_launch: 660.06, - today: '2017-05-18', - month: 'Dec16', - days: '154', - months: '5.133333333', - years: '0.4219178082', ticker: 'vslice', id: 'vslice', - available_supply: '33,390,496.00', - total_supply: '33,390,496.00', - market_cap: '$7,929,608', - implied_project_valuation: '$7,929,608', - token_raise: '$0.05', - token_now: '$0.24', - total_return: '340.53%', - eth_raise: '$8.00', - eth_now: '$85.09', - eth_return: '969.63%', - btc_raise: '$778.53', - btc_now: '$1,751.87', - bitcoin_return: '125.02%', - excess_return_eth: '-629.09%', - excess_return_btc: '215.51%', - token: '34.03%', - eth: '59.52%', - btc: '17.37%', supported_changelly: true }, { name: 'Incent', symbol: 'INCNT', is_erc20: false, - status: 'Completed', - type: 'Loyalty Program', raise: 1000000, total_amount_of_tokens: '46,016,625', amount_sold_in_ico: 23008312, - ownership_pct: '50.00%', - project_valuation: '$2,000,000', - implied_token_price: 0.0435, - implied_token_price_check: '$0.04', start_date: '9/1/2016', ico_end_date: '2016-09-01', eth_price_at_launch: 11.63, btc_price_at_launch: 509.749, - today: '2017-05-18', - month: 'Sep16', - days: '259', - months: '8.633333333', - years: '0.7095890411', ticker: 'incent', id: 'incent', - available_supply: '23,008,312.00', - total_supply: '46,016,625.00', - market_cap: '$3,529,682', - implied_project_valuation: '$7,059,364', - token_raise: '$0.04', - token_now: '$0.15', - total_return: '252.97%', - eth_raise: '$12.14', - eth_now: '$85.09', - eth_return: '604.86%', - btc_raise: '$571.60', - btc_now: '$1,751.87', - bitcoin_return: '206.49%', - excess_return_eth: '-351.89%', - excess_return_btc: '46.48%', - token: '15.96%', - eth: '25.69%', - btc: '14.06%', supported_changelly: false }, { name: 'Ark', symbol: 'ARK', - status: 'Completed', is_erc20: false, - type: 'Cryptocurrency', raise: 942593, total_amount_of_tokens: '125,945,480', amount_sold_in_ico: 94695480, - ownership_pct: '75.19%', - project_valuation: '$1,253,654', - implied_token_price: 0.01, - implied_token_price_check: '$0.01', start_date: '11/7/2016', ico_end_date: '2016-12-11', eth_price_at_launch: 10.96, btc_price_at_launch: 556.00, - today: '2017-05-18', - month: 'Dec16', - days: '158', - months: '5.266666667', - years: '0.4328767123', ticker: 'ark', id: 'ark', - available_supply: '94,799,102.00', - total_supply: '126,049,102.00', - market_cap: '$23,711,057', - implied_project_valuation: '$31,527,276', - token_raise: '$0.01', - token_now: '$0.25', - total_return: '2412.76%', - eth_raise: '$8.21', - eth_now: '$85.09', - eth_return: '942.27%', - btc_raise: '$769.57', - btc_now: '$1,751.87', - bitcoin_return: '127.64%', - excess_return_eth: '1470.50%', - excess_return_btc: '2285.12%', - token: '86.01%', - eth: '56.86%', - btc: '17.16%', supported_changelly: false }, { name: 'BlockPay', symbol: 'BLOCKPAY', - status: 'Completed', is_erc20: false, - type: 'Retail', raise: 675000, total_amount_of_tokens: '98,928,316', amount_sold_in_ico: 5428300, - ownership_pct: '5.49%', - project_valuation: '$12,301,570', - implied_token_price: 0.12, - implied_token_price_check: '$0.12', start_date: '8/20/2016', ico_end_date: '2016-09-05', eth_price_at_launch: 10.75, btc_price_at_launch: 515.103, - today: '2017-05-18', - month: 'Sep16', - days: '255', - months: '8.5', - years: '0.698630137', ticker: 'blockpay', id: 'blockpay', - available_supply: '5,428,300.00', - total_supply: '98,928,316.00', - market_cap: '$1,084,439', - implied_project_valuation: '$19,763,411', - token_raise: '$0.12', - token_now: '$0.20', - total_return: '60.66%', - eth_raise: '$11.75', - eth_now: '$85.09', - eth_return: '628.26%', - btc_raise: '$607.56', - btc_now: '$1,751.87', - bitcoin_return: '188.35%', - excess_return_eth: '-567.60%', - excess_return_btc: '-127.69%', - token: '5.82%', - eth: '26.64%', - btc: '13.46%', supported_changelly: false }, { @@ -1537,87 +807,29 @@ module.exports = [ name: 'Virtual Accelerator', is_erc20: true, contract_address: '0x14f37b574242d366558db61f3335289a5035c506', - status: 'Completed', - type: 'Crowdfunding', raise: 645000, total_amount_of_tokens: '16,110,893', amount_sold_in_ico: 16110893, - ownership_pct: '100.00%', - project_valuation: '$645,000', - implied_token_price: 0.04, - implied_token_price_check: '$0.04', start_date: '10/20/2016', ico_end_date: '2016-12-21', eth_price_at_launch: 12.09, btc_price_at_launch: 579.65, - today: '2017-05-18', - month: 'Dec16', - days: '148', - months: '4.933333333', - years: '0.4054794521', ticker: 'hacker-gold', - available_supply: '16,110,893.00', - total_supply: '16,110,893.00', - market_cap: '$765,752', - implied_project_valuation: '$765,752', - token_raise: '$0.04', - token_now: '$0.05', - total_return: '18.72%', - eth_raise: '$7.78', - eth_now: '$85.09', - eth_return: '999.87%', - btc_raise: '$814.76', - btc_now: '$1,751.87', - bitcoin_return: '115.02%', - excess_return_eth: '-981.15%', - excess_return_btc: '-96.30%', - token: '3.59%', - eth: '63.50%', - btc: '17.04%', supported_changelly: false }, { id: 'golos', symbol: 'GOLOS', name: 'Golos', - status: 'Completed', is_erc20: false, - type: 'Media', raise: 462000, total_amount_of_tokens: '', amount_sold_in_ico: 27072000, - ownership_pct: '', - project_valuation: '', - implied_token_price: 0.017, - implied_token_price_check: '', start_date: '11/1/2016', eth_price_at_launch: 10.94, btc_price_at_launch: 659.56, ico_end_date: '2016-12-04', - today: '2017-05-18', - month: 'Dec16', - days: '165', - months: '5.5', - years: '0.4520547945', ticker: 'golos', - available_supply: '122,196,348.00', - total_supply: '122,196,348.00', - market_cap: '$3,316,519', - implied_project_valuation: '$3,316,519', - token_raise: '', - token_now: '', - total_return: '', - eth_raise: '', - eth_now: '', - eth_return: '', - btc_raise: '', - btc_now: '', - bitcoin_return: '', - excess_return_eth: '', - excess_return_btc: '', - token: '', - eth: '', - btc: '', supported_changelly: true }, { @@ -1625,43 +837,14 @@ module.exports = [ symbol: 'SJCX', name: 'Storj', is_erc20: false, - status: 'Completed', - type: 'Computing', raise: 461802, total_amount_of_tokens: '500,000,000', amount_sold_in_ico: 51173144, - ownership_pct: '10.23%', - project_valuation: '$4,512,152', - implied_token_price: 0.01, - implied_token_price_check: '$0.01', start_date: '7/18/2014', ico_end_date: '2014-08-18', eth_price_at_launch: 0.3, btc_price_at_launch: 457, - today: '2017-05-18', - month: 'Aug14', - days: '1004', - months: '33.46666667', - years: '2.750684932', ticker: 'storjcoin-x', - available_supply: '51,173,144.00', - total_supply: '500,000,000.00', - market_cap: '$24,353,913', - implied_project_valuation: '$24,353,913', - token_raise: '', - token_now: '', - total_return: '', - eth_raise: '', - eth_now: '', - eth_return: '', - btc_raise: '', - btc_now: '', - bitcoin_return: '', - excess_return_eth: '', - excess_return_btc: '', - token: '', - eth: '', - btc: '', supported_changelly: false, icon_ext: 'svg' }, @@ -1670,43 +853,14 @@ module.exports = [ symbol: 'NXC', name: 'Beyond the Void', is_erc20: false, - status: 'Completed', - type: 'Gaming', raise: 115500, total_amount_of_tokens: '66,521,587', amount_sold_in_ico: 28904984, - ownership_pct: '43.45%', - project_valuation: '$265,810', - implied_token_price: 0.01548142, - implied_token_price_check: '$0.00', start_date: '11/1/2016', ico_end_date: '2016-11-30', eth_price_at_launch: 10.94, btc_price_at_launch: 659.56, - today: '2017-05-18', - month: 'Nov16', - days: '169', - months: '5.633333333', - years: '0.4630136986', ticker: 'nexium', - available_supply: '66,521,586.00', - total_supply: '66,521,586.00', - market_cap: '$8,621,996', - implied_project_valuation: '$8,621,996', - token_raise: '$0.00', - token_now: '$0.13', - total_return: '3143.66%', - eth_raise: '$8.44', - eth_now: '$85.09', - eth_return: '913.86%', - btc_raise: '$738.04', - btc_now: '$1,751.87', - bitcoin_return: '137.37%', - excess_return_eth: '2229.80%', - excess_return_btc: '3006.30%', - token: '87.05%', - eth: '51.57%', - btc: '16.83%', supported_changelly: false }, { @@ -1714,43 +868,14 @@ module.exports = [ symbol: 'TKS', name: 'Tokes', is_erc20: false, - status: 'Completed', - type: 'Cannabis', raise: 81100, total_amount_of_tokens: '50,000,000', amount_sold_in_ico: 647624, - ownership_pct: '1.30%', - project_valuation: '$6,261,348', - implied_token_price: 0.13, - implied_token_price_check: '$0.13', start_date: '12/2/2016', ico_end_date: '2017-01-16', eth_price_at_launch: 8.4, btc_price_at_launch: 729.976, - today: '2017-05-18', - month: 'Jan17', - days: '122', - months: '4.066666667', - years: '0.3342465753', ticker: 'tokes', - available_supply: '647,624.00', - total_supply: '50,000,000.00', - market_cap: '$530,708', - implied_project_valuation: '$530,708', - token_raise: '$0.13', - token_now: '$0.82', - total_return: '554.39%', - eth_raise: '$9.77', - eth_now: '$85.09', - eth_return: '775.84%', - btc_raise: '$834.87', - btc_now: '$1,751.87', - bitcoin_return: '109.84%', - excess_return_eth: '-221.46%', - excess_return_btc: '444.55%', - token: '59.74%', - eth: '71.54%', - btc: '20.30%', supported_changelly: false }, { @@ -1759,43 +884,14 @@ module.exports = [ name: 'Aragon', is_erc20: true, contract_address: '0x960b236A07cf122663c4303350609A66A7B288C0', - status: 'Completed', - type: 'Digital Jurisdiction', raise: 24750000, total_amount_of_tokens: 39609523, amount_sold_in_ico: 27000000, - ownership_pct: '70%', - project_valuation: '', - implied_token_price: 0.9167, eth_price_at_launch: 96.20, btc_price_at_launch: 1813.23, - implied_token_price_check: '', start_date: '05/17/2017', ico_end_date: '2017-06-16', - today: '2017-05-18', - month: 'Jun17', - days: '-29', - months: '-0.9666666667', - years: '-0.07945205479', ticker: 'aragon', - available_supply: '', - total_supply: '', - market_cap: '', - implied_project_valuation: '', - token_raise: '', - token_now: '', - total_return: '', - eth_raise: '', - eth_now: '', - eth_return: '', - btc_raise: '', - btc_now: '', - bitcoin_return: '', - excess_return_eth: '', - excess_return_btc: '', - token: '', - eth: '', - btc: '', supported_changelly: true }, { @@ -1803,43 +899,27 @@ module.exports = [ symbol: 'XSPEC', name: 'Spectrecoin', is_erc20: false, - status: 'Completed', - type: 'Cryptocurrency', raise: 15427, total_amount_of_tokens: 20316079, amount_sold_in_ico: 19000000, - ownership_pct: '93.52%', - project_valuation: '$16,495', - implied_token_price: 0.0008, - implied_token_price_check: '$0.00', start_date: '11/20/2016', ico_end_date: '2017-01-08', eth_price_at_launch: 9.67, btc_price_at_launch: 688.68, - today: '2017-05-18', - month: 'Jan17', - days: '130', - months: '4.333333333', - years: '0.3561643836', ticker: 'spectrecoin', - available_supply: '20,329,116.00', - total_supply: '20,329,116.00', - market_cap: '$761,516', - implied_project_valuation: '$761,516', - token_raise: '$0.00', - token_now: '$0.04', - total_return: '4513.67%', - eth_raise: '$10.18', - eth_now: '$85.09', - eth_return: '740.57%', - btc_raise: '$924.49', - btc_now: '$1,751.87', - bitcoin_return: '89.50%', - excess_return_eth: '3773.10%', - excess_return_btc: '4424.18%', - token: '145.10%', - eth: '64.34%', - btc: '16.13%', supported_changelly: false - } + }, + // { + // id: 'aeternity-two', + // is_erc20: false, + // name: 'Aeternity Phase II', + // symbol: 'AE', + // eth_price_at_launch: 185.94, + // btc_price_at_launch: 2183.63, + // raise: 21844271.49391, // 104,148.741 ETH, 1,135.199 BTC raised // $19365416.90154 + $2478854.59237 + // amount_sold_in_ico: 88139450.839, // ref https://wallet.aeternity.com/ + // start_date: '05/29/2017', // ref. https://tokenmarket.net/blockchain/aeternity/assets/aeternity/ + // ticker: 'aeternity', + // supported_changelly: false + // }, ]; From 194f596460d42d47a7170b088966b0ebd490d7f8 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:53:51 -0700 Subject: [PATCH 62/74] fix(data): ethereum should show 0% for ROI v.s. ETH --- src/server/lib/icos.js | 22 ++++++++---- src/server/schema/resolvers/icos.js | 54 +++-------------------------- 2 files changed, 20 insertions(+), 56 deletions(-) diff --git a/src/server/lib/icos.js b/src/server/lib/icos.js index 3255811..2ebf78b 100644 --- a/src/server/lib/icos.js +++ b/src/server/lib/icos.js @@ -1,6 +1,6 @@ // @flow /* eslint-disable import/prefer-default-export */ -import type { $ICO } from 'shared/types'; +import type { $ICO, $ICOData } from 'shared/types.flow'; import moment from 'moment'; import { absoluteDifference, relativeDifference } from 'shared/lib/calc'; @@ -21,22 +21,29 @@ const MONTH = 30; const DAY = 1; /** - * Find the change in price since the ICO. + * Calculate the ICO price in USD. + */ +function icoPrice(ico: $ICOData) { + return ico.raise / ico.amount_sold_in_ico; +} + +/** + * Total ROI since ICO in USD. * @param {Object} ico * @return {Number} */ function roiSinceICO(ico) { - const roi = +ico.price_usd / ico.implied_token_price; + const roi = +ico.price_usd / icoPrice(ico); const diff = roi - 1; return diff; } /** - * Return the ROI since ICO, denomianted in ETH. + * Total ROI Since ICO in USD, but denominated in ETH. */ function roiSinceICOEth(ico, ethPrice) { - const exchangeRateLaunch = ico.implied_token_price / ico.eth_price_at_launch; + const exchangeRateLaunch = icoPrice(ico) / ico.eth_price_at_launch; const exchangeRate = ico.price_usd / ethPrice; const roi = exchangeRate / exchangeRateLaunch; const diff = roi - 1; @@ -45,10 +52,10 @@ function roiSinceICOEth(ico, ethPrice) { } /** - * Return the ROI since ICO, denomianted in BTC. + * Total ROI Since ICO in USD, but denominated in BTC. */ function roiSinceICOBtc(ico, btcPrice) { - const exchangeRateLaunch = ico.implied_token_price / ico.btc_price_at_launch; + const exchangeRateLaunch = icoPrice(ico) / ico.btc_price_at_launch; const exchangeRate = ico.price_usd / btcPrice; const roi = exchangeRate / exchangeRateLaunch; const diff = roi - 1; @@ -130,6 +137,7 @@ export const normalize = ( ...ico, eth_price_usd: ethPrice, btc_price_usd: btcPrice, + implied_token_price: icoPrice(ico), roi_since_ico: roiSinceICO(ico), roi_since_ico_eth: roiSinceICOEth(ico, ethPrice), roi_since_ico_btc: roiSinceICOBtc(ico, btcPrice), diff --git a/src/server/schema/resolvers/icos.js b/src/server/schema/resolvers/icos.js index 981643f..fb0e33a 100644 --- a/src/server/schema/resolvers/icos.js +++ b/src/server/schema/resolvers/icos.js @@ -68,55 +68,11 @@ export default async function icos() { } } - // Get the current ETH price - let ethPrice = cache.get('ethPrice'); - let btcPrice = cache.get('btcPrice'); - - if (!ethPrice) { - const start = Date.now(); - - winston.warn('ETH price not in cache - refetching'); - try { - ethPrice = await fetchETHPrice(); - const end = Date.now(); - const ms = end - start; - - winston.info(`Fetched ETH price in ${ms}ms`); - } catch (e) { - try { - const ticker = await Ticker.findOne({ ticker: 'ethereum' }).exec(); - - ethPrice = ticker.price_usd; - winston.info('Fetched fallback ETH price (%s) from db.', ethPrice); - } catch (err) { - winston.error('Failed to fetch ETH price in ICO resolver.'); - } - } - cache.set('ethPrice', ethPrice, ONE_HOUR); - } - - if (!btcPrice) { - const start = Date.now(); - - winston.warn('BTC price not in cache - refetching'); - try { - btcPrice = await fetchBTCPrice(); - const end = Date.now(); - const ms = end - start; - - winston.info(`Fetched BTC price in ${ms}ms`); - } catch (e) { - try { - const ticker = await Ticker.findOne({ ticker: 'bitcoin' }).exec(); - - btcPrice = ticker.price_usd; - winston.info('Fetched fallback BTC price (%s) from db.', btcPrice); - } catch (err) { - winston.error('Failed to fetch BTC price in ICO resolver.'); - } - } - cache.set('btcPrice', btcPrice, ONE_HOUR); - } + // Get the current ETH/BTC price + const eth = priceHistories.find(p => p.symbol === 'ETH'); + const btc = priceHistories.find(p => p.symbol === 'BTC'); + const ethPrice = eth.latest.price_usd; + const btcPrice = btc.latest.price_usd; const startNormalize = Date.now(); const res = results.map(ico => From 56d15a8e5f3f5b9879d3b53ad8a0514d8ea257fd Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:54:39 -0700 Subject: [PATCH 63/74] feat(calc): Util to find compound interest rate --- ...teDifference.js => absolute-difference.js} | 0 src/shared/lib/calc/index.js | 8 ++-- src/shared/lib/calc/interest-rate.js | 21 ++++++++++ ...veDifference.js => relative-difference.js} | 0 tests/shared/calc/interest-rate.test.js | 41 +++++++++++++++++++ 5 files changed, 67 insertions(+), 3 deletions(-) rename src/shared/lib/calc/{absoluteDifference.js => absolute-difference.js} (100%) create mode 100644 src/shared/lib/calc/interest-rate.js rename src/shared/lib/calc/{relativeDifference.js => relative-difference.js} (100%) create mode 100644 tests/shared/calc/interest-rate.test.js diff --git a/src/shared/lib/calc/absoluteDifference.js b/src/shared/lib/calc/absolute-difference.js similarity index 100% rename from src/shared/lib/calc/absoluteDifference.js rename to src/shared/lib/calc/absolute-difference.js diff --git a/src/shared/lib/calc/index.js b/src/shared/lib/calc/index.js index 1b5a2b0..a474bc9 100644 --- a/src/shared/lib/calc/index.js +++ b/src/shared/lib/calc/index.js @@ -1,7 +1,9 @@ -import relativeDifference from './relativeDifference'; -import absoluteDifference from './absoluteDifference'; +import relativeDifference from './relative-difference'; +import absoluteDifference from './absolute-difference'; +import interestRate from './interest-rate'; module.exports = { relativeDifference, - absoluteDifference + absoluteDifference, + interestRate }; diff --git a/src/shared/lib/calc/interest-rate.js b/src/shared/lib/calc/interest-rate.js new file mode 100644 index 0000000..5aef398 --- /dev/null +++ b/src/shared/lib/calc/interest-rate.js @@ -0,0 +1,21 @@ +/** + * Calculates the compound interest rate given a initial amount, final amount, + * and the number of periods. For example, if I invest 1K and after 5 weeks it + * is now worth 5K, I can calculate what my weekly gain is. + * + * @param {Number} a - Initial value + * @param {Number} b - Final value + * @param {Number} numPeriods - Number of periods to calculate the rate for. + * @return The interest rate (or periodic ROI) in decimal. + * @flow + */ +export default function calculateInterestRate( + a: number, + b: number, + numPeriods: number +): number { + const proportion = b / a; + const rate = proportion ** (1 / numPeriods) - 1; + + return rate; +} diff --git a/src/shared/lib/calc/relativeDifference.js b/src/shared/lib/calc/relative-difference.js similarity index 100% rename from src/shared/lib/calc/relativeDifference.js rename to src/shared/lib/calc/relative-difference.js diff --git a/tests/shared/calc/interest-rate.test.js b/tests/shared/calc/interest-rate.test.js new file mode 100644 index 0000000..e28144a --- /dev/null +++ b/tests/shared/calc/interest-rate.test.js @@ -0,0 +1,41 @@ +import { expect } from 'chai'; +import range from 'lodash/range'; +import calculateInterestRate from 'shared/lib/calc/interest-rate'; + +describe('Calculate Interest Rate', function () { + it('should return the compounding interest rate given principal and final value', function () { + // Simulate an initial investment of 1k which is now worth 5K after 5 weeks. + // in this case, if we calculate the weekly interest correctly, that means + // that we should be able to apply it to the initial investment 5 times and + // end up with 5000. + const initial = 1000; + const final = 5000; + const periods = 5; + + // Calculate the interest rate. + const rate = calculateInterestRate(initial, final, periods); + + // Test accuracy by applying the rate to the initial value and see if it + // actually gives us the final amount. A positive rate (e.g. 0.2) means a + // 20% gains per period. + const actual = range(periods).reduce(p => p + (p * rate), initial); + + // It won't be exact, so just check if it is accurate within 0.1% + const difference = Math.abs(final - actual); + const inaccuracy = difference / final; + + expect(inaccuracy).to.be.below(0.001); + }); + + it('should work for decreases in value', function () { + const initial = 5000; + const final = 1000; + const periods = 5; + const rate = calculateInterestRate(initial, final, periods); + const actual = range(periods).reduce(p => p + (p * rate), initial); + const difference = Math.abs(final - actual); + const inaccuracy = difference / final; + + expect(inaccuracy).to.be.below(0.001); + }); +}); From 4a53f8cb5eb6f67723fe26cfc96f2c8a98329d7d Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:54:51 -0700 Subject: [PATCH 64/74] Add flow typings --- src/shared/types.flow.js | 37 +++++++++++++++++++++++++++++++++++++ src/shared/types.js | 16 ---------------- 2 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 src/shared/types.flow.js delete mode 100644 src/shared/types.js diff --git a/src/shared/types.flow.js b/src/shared/types.flow.js new file mode 100644 index 0000000..80c487f --- /dev/null +++ b/src/shared/types.flow.js @@ -0,0 +1,37 @@ +// @flow + +export type $CoinMarketCapTicker = { + ticker: string, + price_usd: number, // raw response is string + symbol: string +} + +export type $Currency = 'USD' | 'ETH' | 'BTC'; + +export type $ICOData = { + eth_price_at_launch: number, + btc_price_at_launch: number, + start_date: string, + id: string, + is_erc20: boolean, + name: string, + symbol: string, + eth_price_at_launch: number, + btc_price_at_launch: number, + raise: number, + amount_sold_in_ico: number, + start_date: string, + ticker: string, + supported_changelly: boolean, + icon_ext?: string, + contract_address?: string +}; + +export type $ICOCalculations = { + implied_token_price: number +}; + +export type $ICO = + & $ICOData + & $CoinMarketCapTicker + & $ICOCalculations; diff --git a/src/shared/types.js b/src/shared/types.js deleted file mode 100644 index 3a53c2c..0000000 --- a/src/shared/types.js +++ /dev/null @@ -1,16 +0,0 @@ -// @flow - -export type $CoinMarketCapTicker = { - ticker: string, - price_usd: number, // raw response is string - symbol: string -} - -export type $ICO = { - ticker: string, - raise: number, - implied_token_price: number, - eth_price_at_launch: number, - btc_price_at_launch: number, - start_date: string -} & $CoinMarketCapTicker; From 8f0bf61555e8a97ef9345429a961a8b1564eb6d2 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:55:07 -0700 Subject: [PATCH 65/74] Remove artifacts --- tests/shared/exchanges/hitbtc.test.js | 2 +- tests/shared/shapeshift.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/shared/exchanges/hitbtc.test.js b/tests/shared/exchanges/hitbtc.test.js index e78dc89..0e562da 100644 --- a/tests/shared/exchanges/hitbtc.test.js +++ b/tests/shared/exchanges/hitbtc.test.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; import hitbtc from 'shared/lib/exchanges/hitbtc'; -describe.only('HitBTC API Integration', function () { +describe('HitBTC API Integration', function () { it('should support fetching listed pairs', async function () { const res = await hitbtc.fetchPairs(); diff --git a/tests/shared/shapeshift.test.js b/tests/shared/shapeshift.test.js index c4422d4..feacb80 100644 --- a/tests/shared/shapeshift.test.js +++ b/tests/shared/shapeshift.test.js @@ -2,7 +2,7 @@ import { expect, assert } from 'chai'; import * as shapeshift from 'shared/lib/shapeshift'; -describe.only('Shapeshift API Integration', function () { +describe('Shapeshift API Integration', function () { describe('Get Coins', function () { it('returns the available coins', async function () { From f4bf6aa69a262755d8f1f8c1df7d4c700a152552 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:56:04 -0700 Subject: [PATCH 66/74] Docs: Instructions to add tokens --- docs/Tokens.md | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ readme.md | 1 + 2 files changed, 98 insertions(+) create mode 100644 docs/Tokens.md diff --git a/docs/Tokens.md b/docs/Tokens.md new file mode 100644 index 0000000..5381233 --- /dev/null +++ b/docs/Tokens.md @@ -0,0 +1,97 @@ +## Adding Tokens + +If you'd like to have a token added, you can create a pull request to add it +without much programming skills. It should be accepted if it meets the following +conditions: + +* The ICO is closed and no longer accepting contributions. +* The token must be trading on an exchange. +* It is listed on [coinmarketcap](https://coinmarketcap.com) +* You add comments which cite sources where the data can be verified. + +## How to Add a Token + +#### 1. Add data + +The tokens which are listed are defined in `src/server/lib/ico-data.js`. It is +just an array of objects, where each object is a token defition. To add a token, +you just add an object to this array. Below is an example of a valid token: + +``` +{ + /** + * Sources: + * http://foo.com/bar + * http://qux.com/baz + */ + id: 'eos', + name: 'EOS', + symbol: 'EOS', + ticker: 'eos', + eth_price_at_launch: 262.38, + btc_price_at_launch: 2508.52, + raise: 185000000, + amount_sold_in_ico: 200000000, + start_date: '06/26/2017', + supported_changelly: false, + is_erc20: true, + // Below keys are optional but recommended + contract_address: '0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0', + raise_by_currency: { + eth: 19303, + btc: 1839 + } +}, +``` + +The first thing you'll noticed is a comment with source links. You must cite +your sources here otherwise the PR will probably be rejected. + +Below are descriptions of the *required* data. You must provide these values. + +| Key | Type | Value | +|-----------------------|-----------|------------------------------------------| +| `id` | string | Up to you to choose this value. It must be unique so make sure no other item uses the same ID. The filename of the logo which you will add later needs to match this ID. | +| `name` | string | Name of the ICO. (e.g. 'Humaniq', 'Bancor', etc) | +| `symbol` | string | Token Symbol (e.g. 'ETH', 'GNT', ...) | +| `ticker` | string | The ID for this asset in coinmarketcap's API. To find this, go to the token's detail page in coinmarketcap. The correct value is in the URL of the page. For example, if you go to the firstblood page the URL is like this: `https://coinmarketcap.com/assets/firstblood/`. The last part is the ID. so for First Bloog, you would user `ticker: 'firstblood'` | +| `eth_price_at_launch` | number | The price of ETH when the ICO started. A good way to find this is on cryptowatch. Use GDAX for the price, unless the token launched before GDAX supported ETH. In this case, kraken is recommended since they have been trading ETH for a lot longer than most other exchanges. | +| `btc_price_at_launch` | number | The price of BTC when the ICO started. Same thing as eth_price_at_launch but for btc. | +| `raise` | number | The USD raised. Most ICO's raise via ETH and/or BTC, so the recommended way to get this is by finding out how much ETH/BTC was raised, and using the prices you just got for eth/btc on launch date and multiply. `raise = (eth_price_at_launch * eth_raised) + (btc_price_at_launch * btc_raised)` | +| `amount_sold_in_ico` | number | The total number of tokens sold in ICO. | +| `start_date` | string | ICO Start date in 'MM/DD/YYYY' format. | +| `supported_changelly` | boolean | Go to changelly.com and check if they support the token. If they do, put `true`. Otherwise put `false`. | +| `is_erc20` | boolean | `true` if the token is ERC-20 compliant. To check this, get the token contract address and look it up [here](https://etherscan.io/token-search). If it shows up, it's ERC-20 compliant. | + +The following keys are optional. If possible, please try to include them as they +will make new features easier to implement in the future: + +| Key | Type | Value | +|-----------------------|-----------|------------------------------------------| +| `contract_address` | string | Contract address for ethereum-based tokens. This is the same address you use to check if the token is ERC-20 compliant. | +| `raise_by_currency` | Object | Object which maps currencies accepted in the ICO to the amount raised in that respective currency. Usually you end up getting this info to calculate the raise. | +| `icon_ext` | string | If the logo is in a format besides .png, define it here. So, if you add a .svg logo, it should be `icon_ext: 'svg'`. | + +Once you've added this to the file, save it and do one last step. + +#### 2. Add the logo + +You must add a logo to `public/img/logos`. The filename must match the `id` of +the ICO you added. So for the above example using 'eos' as the is, the image +should be named `eos.png`. If the logo is a format besides PNG, you must define +the correct extension at `icon_ext`. + +Please make sure to resize all images to 60px wide or less. Once you've done +that, compress them on [compresspng](http://compresspng.com/) to optimize the +file size. + + +#### 3. Don't forget to site your sources! + +Other people will rely on this data, and we must maintain the accuracy of the +data. So please be diligent about citing all your sources! + +#### 4. Open a PR + +Once you've completed the two steps above, you're done! Open a pull request and +it will be merged and deployed after we verify that the data is not invalid. diff --git a/readme.md b/readme.md index 58d256c..cbd5508 100755 --- a/readme.md +++ b/readme.md @@ -1,6 +1,7 @@ # ICO Stats **[How to Contribute](docs/Contributing.md)** +**[How to Add a Token](docs/Tokens.md)** ## Running the app From 4c960494cfec26ea5c15b26fdfb1a37fcf3909bd Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 14 Jul 2017 07:58:39 -0700 Subject: [PATCH 67/74] Typo --- src/client/app/components/Feedback.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client/app/components/Feedback.jsx b/src/client/app/components/Feedback.jsx index 1853966..bea7382 100644 --- a/src/client/app/components/Feedback.jsx +++ b/src/client/app/components/Feedback.jsx @@ -2,7 +2,6 @@ import React from 'react'; import injectSheet from 'react-jss'; import { connect } from 'react-redux'; -import mapValues from 'lodash/mapValues'; import { graphql, compose } from 'react-apollo'; import gql from 'graphql-tag'; import classNames from 'classnames'; @@ -277,7 +276,7 @@ class Feedback extends React.Component {

Date: Fri, 14 Jul 2017 08:13:25 -0700 Subject: [PATCH 68/74] :shirt: --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index cbd5508..b231248 100755 --- a/readme.md +++ b/readme.md @@ -1,6 +1,7 @@ # ICO Stats **[How to Contribute](docs/Contributing.md)** + **[How to Add a Token](docs/Tokens.md)** ## Running the app From b68333ff75906506a4de7eaa0b4df69a72bd160b Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 28 Jul 2017 13:28:49 -0700 Subject: [PATCH 69/74] eslint: allow template literals --- .eslintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc b/.eslintrc index 07f9d69..b2015fa 100755 --- a/.eslintrc +++ b/.eslintrc @@ -91,7 +91,7 @@ "operator-assignment": [1, "never"], "operator-linebreak": 0, "quote-props": 0, - "quotes": [1, "single", "avoid-escape"], + "quotes": [1, "single", { "allowTemplateLiterals": true }], "keyword-spacing": [1, { "before": true, "after": true, From 07333815ef6905bf161ff39ee23f0d57686d5a4d Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 28 Jul 2017 13:29:03 -0700 Subject: [PATCH 70/74] flow: Enable tpe suppression --- .flowconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.flowconfig b/.flowconfig index 0ae30f9..cbbfbc1 100644 --- a/.flowconfig +++ b/.flowconfig @@ -12,3 +12,7 @@ module.name_mapper='^~/\(.*\)' -> '/src/client/\1' module.name_mapper='^~/\(.*\)' -> '/src/server/\1' module.name_mapper='^shared/\(.*\)' -> '/src/shared/\1' module.name_mapper='^settings$' -> '/settings.js' +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe +suppress_type=$FlowTODO +suppress_type=$FlowTodo +suppress_type=$TODO From 1226f794b0ceefbd1c03799af1633e3eb429e006 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 28 Jul 2017 13:29:38 -0700 Subject: [PATCH 71/74] Install GraphQL Optics --- settings.js | 16 +++++++++++++++- src/server/app.js | 23 +++++++++++++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/settings.js b/settings.js index 1787c45..b419dbe 100755 --- a/settings.js +++ b/settings.js @@ -5,6 +5,7 @@ require('dotenv').config(); module.exports = Object.assign({}, settingsPublic, { APP_ROOT: __dirname, APP_PORT: process.env.PORT || 3000, + DEBUG: isDebug(), MONGO_URI: process.env.MONGO_URI || 'mongodb://mongo/app', MONGO_TEST_URI: process.env.MONGO_TEST_URI || 'mongodb://mongo/app_test', MONGO_USERNAME: process.env.MONGO_USERNAME, @@ -14,5 +15,18 @@ module.exports = Object.assign({}, settingsPublic, { SHAPESHIFT_SECRET: process.env.SHAPESHIFT_SECRET, LOGGLY_SUBDOMAIN: 'icostats', LOGGLY_TOKEN: '8b807190-29c8-4a5b-adfb-cfe5621fe18b', - LOGGLY_TAG: process.env.LOGGLY_TAG || 'development' + LOGGLY_TAG: process.env.LOGGLY_TAG || 'development', + OPTICS_API_KEY: process.env.OPTICS_API_KEY || 'service:icostats-dev:UZPcus12V1nCychIBLloUA' }); + +function isDebug() { + if (process.env.NODE_ENV === 'production') { + return false; + } + + if (typeof process.env.DEBUG !== 'undefined') { + return !!process.env.DEBUG; + } + + return true; +} diff --git a/src/server/app.js b/src/server/app.js index fe0ef35..e84ccd9 100755 --- a/src/server/app.js +++ b/src/server/app.js @@ -9,6 +9,7 @@ import 'winston-loggly-bulk'; import mongoose from 'mongoose'; import Promise from 'bluebird'; import { graphqlExpress, graphiqlExpress } from 'graphql-server-express'; +import OpticsAgent from 'optics-agent'; import settings from 'settings'; import schema from 'schema'; import NodeCache from 'node-cache'; @@ -61,14 +62,28 @@ winston.add(winston.transports.Loggly, { exitOnError: false }); -app.use(expressWinston.logger({ - winstonInstance: winston -})); +if (!settings.DEBUG) { + app.use(expressWinston.logger({ + winstonInstance: winston + })); +} + +/** + * Add optics to graphql + */ +OpticsAgent.configureAgent({ apiKey: settings.OPTICS_API_KEY }); +OpticsAgent.instrumentSchema(schema); +app.use(OpticsAgent.middleware()); /** * GraphQL */ -app.use('/graphql', bodyParser.json(), graphqlExpress({ schema })); +app.use('/graphql', bodyParser.json(), graphqlExpress(req => ({ + schema, + context: { + opticsContext: OpticsAgent.context(req) + } +}))); app.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' From 82a0caf7d667e0c2aa2f1f3dbbf99bceea2798ba Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 28 Jul 2017 13:30:08 -0700 Subject: [PATCH 72/74] :shirt: --- src/server/schema/resolvers/icos.js | 2 -- tests/server/_setup.js | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/server/schema/resolvers/icos.js b/src/server/schema/resolvers/icos.js index fb0e33a..afe9abe 100644 --- a/src/server/schema/resolvers/icos.js +++ b/src/server/schema/resolvers/icos.js @@ -3,9 +3,7 @@ import winston from 'winston'; import has from 'lodash/has'; import { normalize as normalizeICO } from 'lib/icos'; import icoData from 'lib/ico-data'; -import { fetchETHPrice, fetchBTCPrice } from 'shared/lib/exchanges/gdax'; import { cache } from 'app'; -import Ticker from '~/models/ticker'; import PriceHistory from 'models/price-history'; import * as shapeshift from 'shared/lib/shapeshift'; diff --git a/tests/server/_setup.js b/tests/server/_setup.js index 8651533..8d2f0fa 100755 --- a/tests/server/_setup.js +++ b/tests/server/_setup.js @@ -1,4 +1,5 @@ /* eslint-disable */ +import 'isomorphic-fetch'; import mongoose from 'mongoose'; import Promise from 'bluebird'; import settings from 'settings'; From 4b77a7e4647f6dcb6fdebca1efa4da29d330f33c Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 28 Jul 2017 13:31:00 -0700 Subject: [PATCH 73/74] Delay between graph fetches --- src/server/lib/graph-worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/lib/graph-worker.js b/src/server/lib/graph-worker.js index a0fa96e..9ae1b36 100644 --- a/src/server/lib/graph-worker.js +++ b/src/server/lib/graph-worker.js @@ -90,6 +90,6 @@ function recurseOrFinish(ticker, i, didSkip = false) { } else { // Keep recursing. !didSkip && winston.info(`Fetched graph for ${ticker}`); - return recursiveFetch(tokens, i + 1); + return setTimeout(() => recursiveFetch(tokens, i + 1), 10000); } } From 717c6e9bf74fb8eeb2333fda74ab80e8322a8593 Mon Sep 17 00:00:00 2001 From: Cooper Maruyama Date: Fri, 28 Jul 2017 13:41:56 -0700 Subject: [PATCH 74/74] Coin traffic --- public/index.html | 1 + public/styles.css | 1 + 2 files changed, 2 insertions(+) diff --git a/public/index.html b/public/index.html index 2a0ce26..6294f7e 100755 --- a/public/index.html +++ b/public/index.html @@ -30,5 +30,6 @@ }); } + diff --git a/public/styles.css b/public/styles.css index ec916ad..7ea5d39 100644 --- a/public/styles.css +++ b/public/styles.css @@ -19,6 +19,7 @@ div { #app { height: 100%; + padding-bottom: 48px; } /* Let's get this party started */ ::-webkit-scrollbar {