From f1354632a1a2915159f6d662f90b68fe8c3bab38 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 29 Nov 2018 18:42:25 -0800 Subject: feat: implement available token fetching --- .../website/ts/pages/instant/config_generator.tsx | 107 ++++++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-) (limited to 'packages/website/ts/pages') diff --git a/packages/website/ts/pages/instant/config_generator.tsx b/packages/website/ts/pages/instant/config_generator.tsx index 0dac0f9ec..cd215bc61 100644 --- a/packages/website/ts/pages/instant/config_generator.tsx +++ b/packages/website/ts/pages/instant/config_generator.tsx @@ -1,10 +1,19 @@ +import { StandardRelayerAPIOrderProvider } from '@0x/asset-buyer'; +import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; +import { assetDataUtils } from '@0x/order-utils'; +import { ObjectMap } from '@0x/types'; import * as _ from 'lodash'; import * as React from 'react'; import { Container } from 'ts/components/ui/container'; +import { MultiSelect } from 'ts/components/ui/multi_select'; import { Select, SelectItemConfig } from 'ts/components/ui/select'; +import { Spinner } from 'ts/components/ui/spinner'; import { Text } from 'ts/components/ui/text'; import { colors } from 'ts/style/colors'; +import { WebsiteBackendTokenInfo } from 'ts/types'; +import { backendClient } from 'ts/utils/backend_client'; +import { constants } from 'ts/utils/constants'; import { ZeroExInstantBaseConfig } from '../../../../instant/src/types'; @@ -13,17 +22,41 @@ export interface ConfigGeneratorProps { onConfigChange: (config: ZeroExInstantBaseConfig) => void; } +export interface ConfigGeneratorState { + isLoadingAvailableTokens: boolean; + // Address to token info + allKnownTokens: ObjectMap; + availableTokens?: WebsiteBackendTokenInfo[]; +} + const SRA_ENDPOINTS = ['https://api.radarrelay.com/0x/v2/', 'https://api.openrelay.xyz/v2/']; export class ConfigGenerator extends React.Component { + public state: ConfigGeneratorState = { + isLoadingAvailableTokens: true, + allKnownTokens: {}, + }; + public componentDidMount(): void { + this._setAllKnownTokens(this._setAvailableAssetsFromOrderProvider); + } + public componentDidUpdate(prevProps: ConfigGeneratorProps): void { + if (prevProps.value.orderSource !== this.props.value.orderSource) { + this._setAvailableAssetsFromOrderProvider(); + } + } public render(): React.ReactNode { const { value } = this.props; + if (!_.isString(value.orderSource)) { + throw new Error('ConfigGenerator component only supports string values as an orderSource.'); + } return ( - + + + {this._renderTokenMultiSelectOrSpinner()} - BLAH ); } @@ -40,6 +73,76 @@ export class ConfigGenerator extends React.Component { }; this.props.onConfigChange(newConfig); }; + private readonly _handleTokenClick = (assetData: string) => { + const { value } = this.props; + let newAvailableAssetDatas = []; + if (_.includes(value.availableAssetDatas, assetData)) { + // Add it + newAvailableAssetDatas = [...value.availableAssetDatas, assetData]; + } else { + // Remove it + newAvailableAssetDatas = _.remove(value.availableAssetDatas, assetData); + } + const newConfig = { + ...this.props.value, + availableAssetDatas: newAvailableAssetDatas, + }; + this.props.onConfigChange(newConfig); + }; + private _setAllKnownTokens = async (callback: () => void): Promise => { + const tokenInfos = await backendClient.getTokenInfosAsync(); + const allKnownTokens = _.reduce( + tokenInfos, + (acc, tokenInfo) => { + acc[tokenInfo.address] = tokenInfo; + return acc; + }, + {} as ObjectMap, + ); + this.setState({ allKnownTokens }, callback); + }; + private _setAvailableAssetsFromOrderProvider = async (): Promise => { + const { value } = this.props; + if (!_.isUndefined(value.orderSource) && _.isString(value.orderSource)) { + this.setState({ isLoadingAvailableTokens: true }); + const networkId = constants.NETWORK_ID_MAINNET; + const sraOrderProvider = new StandardRelayerAPIOrderProvider(value.orderSource, networkId); + const etherTokenAddress = getContractAddressesForNetworkOrThrow(networkId).etherToken; + const etherTokenAssetData = assetDataUtils.encodeERC20AssetData(etherTokenAddress); + const assetDatas = await sraOrderProvider.getAvailableMakerAssetDatasAsync(etherTokenAssetData); + const availableTokens = _.compact( + _.map(assetDatas, assetData => { + const address = assetDataUtils.decodeAssetDataOrThrow(assetData).tokenAddress; + return this.state.allKnownTokens[address]; + }), + ); + this.setState({ availableTokens, isLoadingAvailableTokens: false }); + } + }; + private _renderTokenMultiSelectOrSpinner = (): React.ReactNode => { + const { value } = this.props; + const { availableTokens, isLoadingAvailableTokens } = this.state; + if (isLoadingAvailableTokens) { + return ( + + + + ); + } + const items = _.map(availableTokens, token => { + const assetData = assetDataUtils.encodeERC20AssetData(token.address); + return { + value: assetDataUtils.encodeERC20AssetData(token.address), + displayText: ( + + {token.symbol} - {token.name} + + ), + onClick: this._handleTokenClick.bind(this, assetData), + }; + }); + return ; + }; } export interface ConfigGeneratorSectionProps { -- cgit v1.2.3