aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfragosti <francesco.agosti93@gmail.com>2018-11-30 10:42:25 +0800
committerFred Carlsen <fred@sjelfull.no>2018-12-06 18:56:11 +0800
commitcc235aac3866c44a7b27bb0343390224a02b8c55 (patch)
treea3161e0f1cf6265a64c7d53bd9dd44cc75afb12f
parentec24bf84019ef16c32149040d096e436442828b8 (diff)
downloaddexon-sol-tools-cc235aac3866c44a7b27bb0343390224a02b8c55.tar.gz
dexon-sol-tools-cc235aac3866c44a7b27bb0343390224a02b8c55.tar.zst
dexon-sol-tools-cc235aac3866c44a7b27bb0343390224a02b8c55.zip
feat: implement available token fetching
-rw-r--r--packages/website/package.json2
-rw-r--r--packages/website/ts/components/ui/multi_select.tsx13
-rw-r--r--packages/website/ts/pages/instant/config_generator.tsx107
3 files changed, 116 insertions, 6 deletions
diff --git a/packages/website/package.json b/packages/website/package.json
index f2ca3c2d3..38056bcfd 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -20,6 +20,8 @@
"author": "Fabio Berger",
"license": "Apache-2.0",
"dependencies": {
+ "@0x/asset-buyer": "^3.0.2",
+ "@0x/contract-addresses": "^2.0.0",
"@0x/contract-wrappers": "^4.1.1",
"@0x/json-schemas": "^2.1.2",
"@0x/order-utils": "^3.0.4",
diff --git a/packages/website/ts/components/ui/multi_select.tsx b/packages/website/ts/components/ui/multi_select.tsx
index 329e76bd5..bf80443af 100644
--- a/packages/website/ts/components/ui/multi_select.tsx
+++ b/packages/website/ts/components/ui/multi_select.tsx
@@ -10,7 +10,7 @@ import { Text } from './text';
export interface MultiSelectItemConfig {
value: string;
- displayText: string;
+ displayText: React.ReactNode;
onClick?: () => void;
}
@@ -27,11 +27,16 @@ export class MultiSelect extends React.Component<MultiSelectProps> {
textColor: colors.darkGrey,
};
public render(): React.ReactNode {
- const { items, backgroundColor } = this.props;
+ const { items, backgroundColor, selectedValues } = this.props;
return (
<Container backgroundColor={backgroundColor} borderRadius="4px">
{_.map(items, item => (
- <MultiSelectItem key={item.value} displayText={item.displayText} onClick={item.onClick} />
+ <MultiSelectItem
+ key={item.value}
+ displayText={item.displayText}
+ onClick={item.onClick}
+ isSelected={_.includes(selectedValues, item.value)}
+ />
))}
</Container>
);
@@ -39,7 +44,7 @@ export class MultiSelect extends React.Component<MultiSelectProps> {
}
export interface MultiSelectItemProps {
- displayText: string;
+ displayText: React.ReactNode;
isSelected?: boolean;
onClick?: () => void;
}
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<WebsiteBackendTokenInfo>;
+ availableTokens?: WebsiteBackendTokenInfo[];
+}
+
const SRA_ENDPOINTS = ['https://api.radarrelay.com/0x/v2/', 'https://api.openrelay.xyz/v2/'];
export class ConfigGenerator extends React.Component<ConfigGeneratorProps> {
+ 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 (
<Container>
<ConfigGeneratorSection title="Standard Relayer API Endpoint">
- <Select value={value.orderSource as string} items={this._generateItems()} />
+ <Select value={value.orderSource} items={this._generateItems()} />
+ </ConfigGeneratorSection>
+ <ConfigGeneratorSection title="What tokens can users buy?">
+ {this._renderTokenMultiSelectOrSpinner()}
</ConfigGeneratorSection>
- <ConfigGeneratorSection title="What tokens can users buy?">BLAH</ConfigGeneratorSection>
</Container>
);
}
@@ -40,6 +73,76 @@ export class ConfigGenerator extends React.Component<ConfigGeneratorProps> {
};
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<void> => {
+ const tokenInfos = await backendClient.getTokenInfosAsync();
+ const allKnownTokens = _.reduce(
+ tokenInfos,
+ (acc, tokenInfo) => {
+ acc[tokenInfo.address] = tokenInfo;
+ return acc;
+ },
+ {} as ObjectMap<WebsiteBackendTokenInfo>,
+ );
+ this.setState({ allKnownTokens }, callback);
+ };
+ private _setAvailableAssetsFromOrderProvider = async (): Promise<void> => {
+ 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 (
+ <Container className="flex items-center">
+ <Spinner />
+ </Container>
+ );
+ }
+ const items = _.map(availableTokens, token => {
+ const assetData = assetDataUtils.encodeERC20AssetData(token.address);
+ return {
+ value: assetDataUtils.encodeERC20AssetData(token.address),
+ displayText: (
+ <Text>
+ <b>{token.symbol}</b> - {token.name}
+ </Text>
+ ),
+ onClick: this._handleTokenClick.bind(this, assetData),
+ };
+ });
+ return <MultiSelect items={items} selectedValues={value.availableAssetDatas || []} />;
+ };
}
export interface ConfigGeneratorSectionProps {