aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant
diff options
context:
space:
mode:
Diffstat (limited to 'packages/instant')
-rw-r--r--packages/instant/package.json2
-rw-r--r--packages/instant/public/index.html43
-rw-r--r--packages/instant/src/components/sliding_error.tsx16
-rw-r--r--packages/instant/src/components/zero_ex_instant.tsx61
-rw-r--r--packages/instant/src/index.umd.ts13
-rw-r--r--packages/instant/src/types.ts2
-rw-r--r--packages/instant/src/util/assert.ts44
-rw-r--r--packages/instant/src/util/asset.ts5
-rw-r--r--packages/instant/src/util/error.ts5
9 files changed, 163 insertions, 28 deletions
diff --git a/packages/instant/package.json b/packages/instant/package.json
index be85b5062..977126867 100644
--- a/packages/instant/package.json
+++ b/packages/instant/package.json
@@ -44,7 +44,9 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md",
"dependencies": {
+ "@0x/assert": "^1.0.14",
"@0x/asset-buyer": "^2.1.0",
+ "@0x/json-schemas": "^2.0.0",
"@0x/order-utils": "^2.0.0",
"@0x/types": "^1.2.0",
"@0x/typescript-typings": "^3.0.3",
diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html
index 14555fc64..9f1dfdb64 100644
--- a/packages/instant/public/index.html
+++ b/packages/instant/public/index.html
@@ -6,6 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>0x Instant Dev Environment</title>
<script type="text/javascript" src="/main.bundle.js" charset="utf-8"></script>
+ <script type="text/javascript" src="https://unpkg.com/jsuri@1.3.1/Uri.js" charset="utf-8"></script>
+ <script type="text/javascript" src="https://unpkg.com/bignumber.js@4.1.0/bignumber.js" charset="utf-8"></script>
<style>
#zeroExInstantContainer {
display: flex;
@@ -24,10 +26,47 @@
<body>
<div id="zeroExInstantContainer"></div>
<script>
- zeroExInstant.render({
+ const removeUndefined = (obj) => {
+ for (let k in obj) if (obj[k] === undefined) delete obj[k];
+ return obj;
+ }
+ BigNumber.config({
+ EXPONENTIAL_AT: 1000,
+ DECIMAL_PLACES: 78,
+ });
+ const providedOrder = {
+ senderAddress: '0x0000000000000000000000000000000000000000',
+ makerAddress: '0x14e2f1f157e7dd4057d02817436d628a37120fd1',
+ takerAddress: '0x0000000000000000000000000000000000000000',
+ makerFee: new BigNumber('0'),
+ takerFee: new BigNumber('0'),
+ makerAssetAmount: new BigNumber('100000000000000000000'),
+ takerAssetAmount: new BigNumber('10000000000000000'),
+ makerAssetData: '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa',
+ takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
+ expirationTimeSeconds: new BigNumber('1591858800'),
+ feeRecipientAddress: '0x0000000000000000000000000000000000000000',
+ salt: new BigNumber(
+ '54983920541892966634674340965984367456810207583416050222519063020710969340046',
+ ),
+ signature:
+ '0x1b949656218421c845995457303569a656764afa2b979d41dcefff0009d57ce15001490268bc7caa4269894fd83b741465fc5a7a53eda6ece17eb91fb32655d83703',
+ exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2',
+ };
+ const queryParams = new Uri(window.location.search);
+ const renderOptionsDefaults = {
liquiditySource: 'https://api.radarrelay.com/0x/v2/',
assetData: '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498',
- });
+ }
+ const liquiditySourceOverride = queryParams.getQueryParamValue('liquiditySource');
+ const renderOptionsOverrides = {
+ liquiditySource: liquiditySourceOverride === 'provided' ? [providedOrder] : liquiditySourceOverride,
+ assetData: queryParams.getQueryParamValue('assetData'),
+ networkId: +queryParams.getQueryParamValue('networkId') || undefined,
+ defaultAssetBuyAmount: +queryParams.getQueryParamValue('defaultAssetBuyAmount') || undefined,
+ }
+ const renderOptions = Object.assign({}, renderOptionsDefaults, removeUndefined(renderOptionsOverrides));
+ zeroExInstant.render(renderOptions);
</script>
</body>
diff --git a/packages/instant/src/components/sliding_error.tsx b/packages/instant/src/components/sliding_error.tsx
index 3865a8797..cc9abb7dd 100644
--- a/packages/instant/src/components/sliding_error.tsx
+++ b/packages/instant/src/components/sliding_error.tsx
@@ -4,7 +4,7 @@ import { ColorOption } from '../style/theme';
import { SlideDownAnimation, SlideUpAnimation } from './animations/slide_animations';
-import { Container, Text } from './ui';
+import { Container, Flex, Text } from './ui';
export interface ErrorProps {
icon: string;
@@ -20,12 +20,14 @@ export const Error: React.StatelessComponent<ErrorProps> = props => (
borderRadius="6px"
marginBottom="10px"
>
- <Container marginRight="5px" display="inline" top="3px" position="relative">
- <Text fontSize="20px">{props.icon}</Text>
- </Container>
- <Text fontWeight="500" fontColor={ColorOption.darkOrange}>
- {props.message}
- </Text>
+ <Flex justify="flex-start">
+ <Container marginRight="5px" display="inline" top="3px" position="relative">
+ <Text fontSize="20px">{props.icon}</Text>
+ </Container>
+ <Text fontWeight="500" fontColor={ColorOption.darkOrange}>
+ {props.message}
+ </Text>
+ </Flex>
</Container>
);
diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx
index ffa5a8250..8454de43c 100644
--- a/packages/instant/src/components/zero_ex_instant.tsx
+++ b/packages/instant/src/components/zero_ex_instant.tsx
@@ -1,5 +1,7 @@
import { AssetBuyer } from '@0x/asset-buyer';
-import { ObjectMap } from '@0x/types';
+import { ObjectMap, SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import * as _ from 'lodash';
import * as React from 'react';
import { Provider } from 'react-redux';
@@ -10,7 +12,9 @@ import { store, Store } from '../redux/store';
import { fonts } from '../style/fonts';
import { AssetMetaData, Network } from '../types';
import { assetUtils } from '../util/asset';
+import { errorUtil } from '../util/error';
import { getProvider } from '../util/provider';
+import { web3Wrapper } from '../util/web3_wrapper';
import { ZeroExInstantContainer } from './zero_ex_instant_container';
@@ -21,28 +25,34 @@ export type ZeroExInstantProps = ZeroExInstantRequiredProps & Partial<ZeroExInst
export interface ZeroExInstantRequiredProps {
// TODO: Change API when we allow the selection of different assetDatas
assetData: string;
- // TODO: Allow for a function that returns orders
- liquiditySource: string;
+ liquiditySource: string | SignedOrder[];
}
export interface ZeroExInstantOptionalProps {
+ defaultAssetBuyAmount?: number;
additionalAssetMetaDataMap: ObjectMap<AssetMetaData>;
- network: Network;
+ networkId: Network;
}
export class ZeroExInstant extends React.Component<ZeroExInstantProps> {
private readonly _store: Store;
private static _mergeInitialStateWithProps(props: ZeroExInstantProps, state: State = INITIAL_STATE): State {
- // Create merged object such that properties in props override default settings
- const optionalPropsWithDefaults: ZeroExInstantOptionalProps = {
- additionalAssetMetaDataMap: props.additionalAssetMetaDataMap || {},
- network: props.network || state.network,
- };
- const { network } = optionalPropsWithDefaults;
+ const networkId = props.networkId || state.network;
// TODO: Provider needs to not be hard-coded to injected web3.
- const assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(getProvider(), props.liquiditySource, {
- networkId: network,
- });
+ const provider = getProvider();
+ const assetBuyerOptions = {
+ networkId,
+ };
+ let assetBuyer;
+ if (_.isString(props.liquiditySource)) {
+ assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(
+ provider,
+ props.liquiditySource,
+ assetBuyerOptions,
+ );
+ } else {
+ assetBuyer = AssetBuyer.getAssetBuyerForProvidedOrders(provider, props.liquiditySource, assetBuyerOptions);
+ }
const completeAssetMetaDataMap = {
...props.additionalAssetMetaDataMap,
...state.assetMetaDataMap,
@@ -50,17 +60,26 @@ export class ZeroExInstant extends React.Component<ZeroExInstantProps> {
const storeStateFromProps: State = {
...state,
assetBuyer,
- network,
- selectedAsset: assetUtils.createAssetFromAssetData(props.assetData, completeAssetMetaDataMap, network),
+ network: networkId,
+ selectedAsset: assetUtils.createAssetFromAssetData(props.assetData, completeAssetMetaDataMap, networkId),
+ selectedAssetAmount: _.isUndefined(props.defaultAssetBuyAmount)
+ ? state.selectedAssetAmount
+ : new BigNumber(props.defaultAssetBuyAmount),
assetMetaDataMap: completeAssetMetaDataMap,
};
return storeStateFromProps;
}
constructor(props: ZeroExInstantProps) {
super(props);
- this._store = store.create(ZeroExInstant._mergeInitialStateWithProps(this.props, INITIAL_STATE));
+ const initialAppState = ZeroExInstant._mergeInitialStateWithProps(this.props, INITIAL_STATE);
+ this._store = store.create(initialAppState);
+ }
+
+ public componentDidMount(): void {
// tslint:disable-next-line:no-floating-promises
asyncData.fetchAndDispatchToStore(this._store);
+ // tslint:disable-next-line:no-floating-promises
+ this._flashErrorIfWrongNetwork();
}
public render(): React.ReactNode {
@@ -72,4 +91,14 @@ export class ZeroExInstant extends React.Component<ZeroExInstantProps> {
</Provider>
);
}
+
+ private readonly _flashErrorIfWrongNetwork = async (): Promise<void> => {
+ const msToShowError = 30000; // 30 seconds
+ const network = this._store.getState().network;
+ const networkOfProvider = await web3Wrapper.getNetworkIdAsync();
+ if (network !== networkOfProvider) {
+ const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`;
+ errorUtil.errorFlasher.flashNewError(this._store.dispatch, errorMessage, msToShowError);
+ }
+ };
}
diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts
index f648b37f2..dabd45cae 100644
--- a/packages/instant/src/index.umd.ts
+++ b/packages/instant/src/index.umd.ts
@@ -1,9 +1,22 @@
+import * as _ from 'lodash';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR } from './constants';
import { ZeroExInstant, ZeroExInstantProps } from './index';
+import { assert } from './util/assert';
export const render = (props: ZeroExInstantProps, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => {
+ assert.isHexString('assetData', props.assetData);
+ assert.isValidLiquiditySource('liquiditySource', props.liquiditySource);
+ if (!_.isUndefined(props.additionalAssetMetaDataMap)) {
+ assert.isValidAssetMetaDataMap('additionalAssetMetaDataMap', props.additionalAssetMetaDataMap);
+ }
+ if (!_.isUndefined(props.defaultAssetBuyAmount)) {
+ assert.isNumber('defaultAssetBuyAmount', props.defaultAssetBuyAmount);
+ }
+ if (!_.isUndefined(props.networkId)) {
+ assert.isNumber('networkId', props.networkId);
+ }
ReactDOM.render(React.createElement(ZeroExInstant, props), document.querySelector(selector));
};
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index c63371fb4..e02a815f9 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -44,7 +44,7 @@ export interface ERC20AssetMetaData {
export interface ERC721AssetMetaData {
assetProxyId: AssetProxyId.ERC721;
name: string;
- representationUrl?: string;
+ imageUrl?: string;
primaryColor?: string;
}
diff --git a/packages/instant/src/util/assert.ts b/packages/instant/src/util/assert.ts
new file mode 100644
index 000000000..584d3d4b1
--- /dev/null
+++ b/packages/instant/src/util/assert.ts
@@ -0,0 +1,44 @@
+import { assert as sharedAssert } from '@0x/assert';
+import { schemas } from '@0x/json-schemas';
+import { assetDataUtils } from '@0x/order-utils';
+import { AssetProxyId, ObjectMap, SignedOrder } from '@0x/types';
+import * as _ from 'lodash';
+
+import { AssetMetaData } from '../types';
+
+export const assert = {
+ ...sharedAssert,
+ isValidLiquiditySource(variableName: string, liquiditySource: string | SignedOrder[]): void {
+ if (_.isString(liquiditySource)) {
+ sharedAssert.isUri(variableName, liquiditySource);
+ return;
+ }
+ sharedAssert.doesConformToSchema(variableName, liquiditySource, schemas.signedOrdersSchema);
+ },
+ isValidAssetMetaDataMap(variableName: string, metaDataMap: ObjectMap<AssetMetaData>): void {
+ _.forEach(metaDataMap, (metaData, assetData) => {
+ assert.isHexString(`key ${assetData} of ${variableName}`, assetData);
+ assert.isValidAssetMetaData(`${variableName}.${assetData}`, metaData);
+ const assetDataProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ assert.assert(
+ metaData.assetProxyId === assetDataProxyId,
+ `Expected meta data for assetData ${assetData} to have asset proxy id of ${assetDataProxyId}, but instead got ${
+ metaData.assetProxyId
+ }`,
+ );
+ });
+ },
+ isValidAssetMetaData(variableName: string, metaData: AssetMetaData): void {
+ assert.isHexString(`${variableName}.assetProxyId`, metaData.assetProxyId);
+ if (!_.isUndefined(metaData.primaryColor)) {
+ assert.isString(`${variableName}.primaryColor`, metaData.primaryColor);
+ }
+ if (metaData.assetProxyId === AssetProxyId.ERC20) {
+ assert.isNumber(`${variableName}.decimals`, metaData.decimals);
+ assert.isString(`${variableName}.symbol`, metaData.symbol);
+ } else if (metaData.assetProxyId === AssetProxyId.ERC721) {
+ assert.isString(`${variableName}.name`, metaData.name);
+ assert.isUri(`${variableName}.imageUrl`, metaData.imageUrl);
+ }
+ },
+};
diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts
index 2c5b6325d..630103c7b 100644
--- a/packages/instant/src/util/asset.ts
+++ b/packages/instant/src/util/asset.ts
@@ -18,7 +18,10 @@ export const assetUtils = {
getMetaDataOrThrow: (assetData: string, metaDataMap: ObjectMap<AssetMetaData>, network: Network): AssetMetaData => {
let mainnetAssetData: string | undefined = assetData;
if (network !== Network.Mainnet) {
- mainnetAssetData = assetUtils.getAssociatedAssetDataIfExists(assetData, network);
+ const mainnetAssetDataIfExists = assetUtils.getAssociatedAssetDataIfExists(assetData, network);
+ // Just so we don't fail in the case where we are on a non-mainnet network,
+ // but pass in a valid mainnet assetData.
+ mainnetAssetData = mainnetAssetDataIfExists || assetData;
}
if (_.isUndefined(mainnetAssetData)) {
throw new Error(ZeroExInstantError.AssetMetaDataNotAvailable);
diff --git a/packages/instant/src/util/error.ts b/packages/instant/src/util/error.ts
index 64c1f4885..844a28d8b 100644
--- a/packages/instant/src/util/error.ts
+++ b/packages/instant/src/util/error.ts
@@ -1,4 +1,5 @@
import { AssetBuyerError } from '@0x/asset-buyer';
+import * as _ from 'lodash';
import { Dispatch } from 'redux';
import { Action, actions } from '../redux/actions';
@@ -10,7 +11,6 @@ class ErrorFlasher {
private _timeoutId?: number;
public flashNewError(dispatch: Dispatch<Action>, error: any, delayMs: number = 7000): void {
this._clearTimeout();
-
// dispatch new message
dispatch(actions.setError(error));
@@ -60,6 +60,9 @@ export const errorUtil = {
if (error instanceof Error) {
bestMessage = humanReadableMessageForError(error, asset);
}
+ if (_.isString(error)) {
+ bestMessage = error;
+ }
return {
icon: '😢',
message: bestMessage || 'Something went wrong...',