Merge pull request #550 from 0xProject/feature/website/crypto-compare-prices

Grab wallet price information by token symbol
This commit is contained in:
Brandon Millman
2018-05-01 10:09:04 -07:00
committed by GitHub
5 changed files with 73 additions and 62 deletions

View File

@@ -461,16 +461,16 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
);
balanceAndAllowanceTupleByAddress[tokenAddress] = balanceAndAllowanceTuple;
}
const pricesByAddress = await this._getPricesByAddressAsync(tokenAddresses);
const priceByAddress = await this._getPriceByAddressAsync(tokenAddresses);
const trackedTokenStateByAddress = _.reduce(
tokenAddresses,
(acc, address) => {
const [balance, allowance] = balanceAndAllowanceTupleByAddress[address];
const price = pricesByAddress[address];
const priceIfExists = _.get(priceByAddress, address);
acc[address] = {
balance,
allowance,
price,
price: priceIfExists,
isLoaded: true,
};
return acc;
@@ -487,16 +487,29 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
private async _refetchTokenStateAsync(tokenAddress: string) {
await this._fetchBalancesAndAllowancesAsync([tokenAddress]);
}
private async _getPricesByAddressAsync(tokenAddresses: string[]): Promise<ItemByAddress<BigNumber>> {
private async _getPriceByAddressAsync(tokenAddresses: string[]): Promise<ItemByAddress<BigNumber>> {
if (_.isEmpty(tokenAddresses)) {
return {};
}
// for each input token address, search for the corresponding symbol in this.props.tokenByAddress, if it exists
// create a mapping from existing symbols -> address
const tokenAddressBySymbol: { [symbol: string]: string } = {};
_.each(tokenAddresses, address => {
const tokenIfExists = _.get(this.props.tokenByAddress, address);
if (!_.isUndefined(tokenIfExists)) {
const symbol = tokenIfExists.symbol;
tokenAddressBySymbol[symbol] = address;
}
});
const tokenSymbols = _.keys(tokenAddressBySymbol);
try {
const websiteBackendPriceInfos = await backendClient.getPriceInfosAsync(tokenAddresses);
const addresses = _.map(websiteBackendPriceInfos, info => info.address);
const prices = _.map(websiteBackendPriceInfos, info => new BigNumber(info.price));
const pricesByAddress = _.zipObject(addresses, prices);
return pricesByAddress;
const priceBySymbol = await backendClient.getPriceInfoAsync(tokenSymbols);
const priceByAddress = _.mapKeys(priceBySymbol, (value, symbol) => _.get(tokenAddressBySymbol, symbol));
const result = _.mapValues(priceByAddress, price => {
const priceBigNumber = new BigNumber(price);
return priceBigNumber;
});
return result;
} catch (err) {
return {};
}

View File

@@ -509,8 +509,7 @@ export interface WebsiteBackendRelayerInfo {
}
export interface WebsiteBackendPriceInfo {
price: string;
address: string;
[symbol: string]: string;
}
export interface WebsiteBackendGasInfo {

View File

@@ -1,16 +1,8 @@
import { BigNumber, logUtils } from '@0xproject/utils';
import * as _ from 'lodash';
import * as queryString from 'query-string';
import {
ArticlesBySection,
ItemByAddress,
WebsiteBackendGasInfo,
WebsiteBackendPriceInfo,
WebsiteBackendRelayerInfo,
} from 'ts/types';
import { ArticlesBySection, WebsiteBackendGasInfo, WebsiteBackendPriceInfo, WebsiteBackendRelayerInfo } from 'ts/types';
import { configs } from 'ts/utils/configs';
import { errorReporter } from 'ts/utils/error_reporter';
import { fetchUtils } from 'ts/utils/fetch_utils';
const ETH_GAS_STATION_ENDPOINT = '/eth_gas_station';
const PRICES_ENDPOINT = '/prices';
@@ -19,52 +11,26 @@ const WIKI_ENDPOINT = '/wiki';
export const backendClient = {
async getGasInfoAsync(): Promise<WebsiteBackendGasInfo> {
const result = await requestAsync(ETH_GAS_STATION_ENDPOINT);
const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, ETH_GAS_STATION_ENDPOINT);
return result;
},
async getPriceInfosAsync(tokenAddresses: string[]): Promise<WebsiteBackendPriceInfo[]> {
if (_.isEmpty(tokenAddresses)) {
return [];
async getPriceInfoAsync(tokenSymbols: string[]): Promise<WebsiteBackendPriceInfo> {
if (_.isEmpty(tokenSymbols)) {
return {};
}
const joinedTokenAddresses = tokenAddresses.join(',');
const joinedTokenSymbols = tokenSymbols.join(',');
const queryParams = {
tokens: joinedTokenAddresses,
tokens: joinedTokenSymbols,
};
const result = await requestAsync(PRICES_ENDPOINT, queryParams);
const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, PRICES_ENDPOINT, queryParams);
return result;
},
async getRelayerInfosAsync(): Promise<WebsiteBackendRelayerInfo[]> {
const result = await requestAsync(RELAYERS_ENDPOINT);
const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, RELAYERS_ENDPOINT);
return result;
},
async getWikiArticlesBySectionAsync(): Promise<ArticlesBySection> {
const result = await requestAsync(WIKI_ENDPOINT);
const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, WIKI_ENDPOINT);
return result;
},
};
async function requestAsync(endpoint: string, queryParams?: object): Promise<any> {
const query = queryStringFromQueryParams(queryParams);
const url = `${configs.BACKEND_BASE_URL}${endpoint}${query}`;
const response = await fetch(url);
if (response.status !== 200) {
const errorText = `Error requesting url: ${url}, ${response.status}: ${response.statusText}`;
logUtils.log(errorText);
const error = Error(errorText);
// tslint:disable-next-line:no-floating-promises
errorReporter.reportAsync(error);
throw error;
}
const result = await response.json();
return result;
}
function queryStringFromQueryParams(queryParams?: object): string {
// if params are undefined or empty, return an empty string
if (_.isUndefined(queryParams) || _.isEmpty(queryParams)) {
return '';
}
// stringify the formatted object
const stringifiedParams = queryString.stringify(queryParams);
return `?${stringifiedParams}`;
}

View File

@@ -0,0 +1,33 @@
import { logUtils } from '@0xproject/utils';
import * as _ from 'lodash';
import * as queryString from 'query-string';
import { errorReporter } from 'ts/utils/error_reporter';
export const fetchUtils = {
async requestAsync(baseUrl: string, path: string, queryParams?: object): Promise<any> {
const query = queryStringFromQueryParams(queryParams);
const url = `${baseUrl}${path}${query}`;
const response = await fetch(url);
if (response.status !== 200) {
const errorText = `Error requesting url: ${url}, ${response.status}: ${response.statusText}`;
logUtils.log(errorText);
const error = Error(errorText);
// tslint:disable-next-line:no-floating-promises
errorReporter.reportAsync(error);
throw error;
}
const result = await response.json();
return result;
},
};
function queryStringFromQueryParams(queryParams?: object): string {
// if params are undefined or empty, return an empty string
if (_.isUndefined(queryParams) || _.isEmpty(queryParams)) {
return '';
}
// stringify the formatted object
const stringifiedParams = queryString.stringify(queryParams);
return `?${stringifiedParams}`;
}

View File

@@ -11448,9 +11448,9 @@ web3-net@1.0.0-beta.33:
web3-core-method "1.0.0-beta.33"
web3-utils "1.0.0-beta.33"
web3-provider-engine@^13.0.1, web3-provider-engine@^13.6.5:
version "13.6.6"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.6.6.tgz#7d8972ffcd31e103bd2ce8a521b1b7da08cb173f"
web3-provider-engine@^13.3.2:
version "13.8.0"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz#4c7c1ad2af5f1fe10343b8a65495879a2f9c00df"
dependencies:
async "^2.5.0"
clone "^2.0.0"
@@ -11472,9 +11472,9 @@ web3-provider-engine@^13.0.1, web3-provider-engine@^13.6.5:
xhr "^2.2.0"
xtend "^4.0.1"
web3-provider-engine@^13.3.2:
version "13.8.0"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz#4c7c1ad2af5f1fe10343b8a65495879a2f9c00df"
web3-provider-engine@^13.6.5:
version "13.6.6"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.6.6.tgz#7d8972ffcd31e103bd2ce8a521b1b7da08cb173f"
dependencies:
async "^2.5.0"
clone "^2.0.0"