From 11f1ccf3ff92d5d1e32e0451ffd5069615e29867 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 21:07:48 -0700 Subject: Lay out wallet and relayers --- packages/website/ts/components/portal/portal.tsx | 214 +++++++++++++++++++++++ packages/website/ts/containers/portal.ts | 88 ++++++++++ packages/website/ts/index.tsx | 11 +- 3 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 packages/website/ts/components/portal/portal.tsx create mode 100644 packages/website/ts/containers/portal.ts (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx new file mode 100644 index 000000000..8a9e89a72 --- /dev/null +++ b/packages/website/ts/components/portal/portal.tsx @@ -0,0 +1,214 @@ +import { colors, Styles } from '@0xproject/react-shared'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import * as DocumentTitle from 'react-document-title'; + +import { Blockchain } from 'ts/blockchain'; +import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; +import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; +import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; +import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; +import { TopBar } from 'ts/components/top_bar/top_bar'; +import { FlashMessage } from 'ts/components/ui/flash_message'; +import { Wallet } from 'ts/components/wallet/wallet'; +import { localStorage } from 'ts/local_storage/local_storage'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; +import { utils } from 'ts/utils/utils'; + +export interface PortalProps { + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + dispatcher: Dispatcher; + hashData: HashData; + injectedProviderName: string; + networkId: number; + nodeVersion: string; + orderFillAmount: BigNumber; + providerType: ProviderType; + screenWidth: ScreenWidths; + tokenByAddress: TokenByAddress; + userEtherBalanceInWei: BigNumber; + userAddress: string; + shouldBlockchainErrDialogBeOpen: boolean; + userSuppliedOrderCache: Order; + location: Location; + flashMessage?: string | React.ReactNode; + lastForceTokenStateRefetch: number; + translate: Translate; +} + +interface PortalState { + prevNetworkId: number; + prevNodeVersion: string; + prevUserAddress: string; + prevPathname: string; + isDisclaimerDialogOpen: boolean; + isLedgerDialogOpen: boolean; +} + +const THROTTLE_TIMEOUT = 100; +const TOP_BAR_HEIGHT = 60; + +const styles: Styles = { + root: { + width: '100%', + height: '100%', + backgroundColor: colors.lightestGrey, + }, + body: { + height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, + }, +}; + +export class Portal extends React.Component { + private _blockchain: Blockchain; + private _throttledScreenWidthUpdate: () => void; + constructor(props: PortalProps) { + super(props); + this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); + const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER); + const hasAcceptedDisclaimer = + !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer); + this.state = { + prevNetworkId: this.props.networkId, + prevNodeVersion: this.props.nodeVersion, + prevUserAddress: this.props.userAddress, + prevPathname: this.props.location.pathname, + isDisclaimerDialogOpen: !hasAcceptedDisclaimer, + isLedgerDialogOpen: false, + }; + } + public componentDidMount() { + window.addEventListener('resize', this._throttledScreenWidthUpdate); + window.scrollTo(0, 0); + } + public componentWillMount() { + this._blockchain = new Blockchain(this.props.dispatcher); + } + public componentWillUnmount() { + this._blockchain.destroy(); + window.removeEventListener('resize', this._throttledScreenWidthUpdate); + // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered + // the initialization process always occurs from the same base state. This helps avoid + // initialization inconsistencies (i.e While the portal was unrendered, the user might have + // become disconnected from their backing Ethereum node, changes user accounts, etc...) + this.props.dispatcher.resetState(); + } + public componentWillReceiveProps(nextProps: PortalProps) { + if (nextProps.networkId !== this.state.prevNetworkId) { + // tslint:disable-next-line:no-floating-promises + this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId); + this.setState({ + prevNetworkId: nextProps.networkId, + }); + } + if (nextProps.userAddress !== this.state.prevUserAddress) { + const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress; + // tslint:disable-next-line:no-floating-promises + this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress); + this.setState({ + prevUserAddress: nextProps.userAddress, + }); + } + if (nextProps.nodeVersion !== this.state.prevNodeVersion) { + // tslint:disable-next-line:no-floating-promises + this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion); + } + if (nextProps.location.pathname !== this.state.prevPathname) { + this.setState({ + prevPathname: nextProps.location.pathname, + }); + } + } + public render() { + const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind( + this.props.dispatcher, + ); + const allTokens = _.values(this.props.tokenByAddress); + const trackedTokens = _.filter(allTokens, t => t.isTracked); + return ( +
+ + +
+
+
+ +
+
+ +
+
+ + + + {this.props.blockchainIsLoaded && ( + + )} +
+
+ ); + } + private _onToggleLedgerDialog() { + this.setState({ + isLedgerDialogOpen: !this.state.isLedgerDialogOpen, + }); + } + private _onPortalDisclaimerAccepted() { + localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set'); + this.setState({ + isDisclaimerDialogOpen: false, + }); + } + private _updateScreenWidth() { + const newScreenWidth = utils.getScreenWidth(); + this.props.dispatcher.updateScreenWidth(newScreenWidth); + } +} diff --git a/packages/website/ts/containers/portal.ts b/packages/website/ts/containers/portal.ts new file mode 100644 index 000000000..3f0feb6e9 --- /dev/null +++ b/packages/website/ts/containers/portal.ts @@ -0,0 +1,88 @@ +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { Portal as PortalComponent, PortalProps as PortalComponentProps } from 'ts/components/portal/portal'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + hashData: HashData; + injectedProviderName: string; + networkId: number; + nodeVersion: string; + orderFillAmount: BigNumber; + providerType: ProviderType; + tokenByAddress: TokenByAddress; + lastForceTokenStateRefetch: number; + userEtherBalanceInWei: BigNumber; + screenWidth: ScreenWidths; + shouldBlockchainErrDialogBeOpen: boolean; + userAddress: string; + userSuppliedOrderCache: Order; + flashMessage?: string | React.ReactNode; + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: PortalComponentProps): ConnectedState => { + const receiveAssetToken = state.sideToAssetToken[Side.Receive]; + const depositAssetToken = state.sideToAssetToken[Side.Deposit]; + const receiveAddress = !_.isUndefined(receiveAssetToken.address) + ? receiveAssetToken.address + : constants.NULL_ADDRESS; + const depositAddress = !_.isUndefined(depositAssetToken.address) + ? depositAssetToken.address + : constants.NULL_ADDRESS; + const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0); + const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0); + const hashData = { + depositAmount, + depositTokenContractAddr: depositAddress, + feeRecipientAddress: constants.NULL_ADDRESS, + makerFee: constants.MAKER_FEE, + orderExpiryTimestamp: state.orderExpiryTimestamp, + orderMakerAddress: state.userAddress, + orderTakerAddress: state.orderTakerAddress !== '' ? state.orderTakerAddress : constants.NULL_ADDRESS, + receiveAmount, + receiveTokenContractAddr: receiveAddress, + takerFee: constants.TAKER_FEE, + orderSalt: state.orderSalt, + }; + return { + blockchainErr: state.blockchainErr, + blockchainIsLoaded: state.blockchainIsLoaded, + hashData, + injectedProviderName: state.injectedProviderName, + networkId: state.networkId, + nodeVersion: state.nodeVersion, + orderFillAmount: state.orderFillAmount, + providerType: state.providerType, + screenWidth: state.screenWidth, + shouldBlockchainErrDialogBeOpen: state.shouldBlockchainErrDialogBeOpen, + tokenByAddress: state.tokenByAddress, + lastForceTokenStateRefetch: state.lastForceTokenStateRefetch, + userAddress: state.userAddress, + userEtherBalanceInWei: state.userEtherBalanceInWei, + userSuppliedOrderCache: state.userSuppliedOrderCache, + flashMessage: state.flashMessage, + translate: state.translate, + }; +}; + +const mapDispatchToProps = (dispatch: Dispatch): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const Portal: React.ComponentClass = connect(mapStateToProps, mapDispatchToProps)( + PortalComponent, +); diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index d99187151..7b7a7eb2e 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -34,9 +34,14 @@ import 'less/all.less'; // cause we only want to import the module when the user navigates to the page. // At the same time webpack statically parses for System.import() to determine bundle chunk split points // so each lazy import needs it's own `System.import()` declaration. -const LazyPortal = createLazyComponent('LegacyPortal', async () => - System.import(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'), -); +const LazyPortal = + utils.isDevelopment() || utils.isStaging() + ? createLazyComponent('Portal', async () => + System.import(/* webpackChunkName: "portal" */ 'ts/containers/portal'), + ) + : createLazyComponent('LegacyPortal', async () => + System.import(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'), + ); const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () => System.import(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'), ); -- cgit v1.2.3 From deaa5f3211d75e81dd7e0820686a5f6a9b26f9d4 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 21:45:05 -0700 Subject: Add scrolling to relayer index --- packages/website/ts/components/portal/portal.tsx | 8 +++++++- packages/website/ts/components/relayer_index/relayer_index.tsx | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 8a9e89a72..6939d8905 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -62,6 +62,12 @@ const styles: Styles = { body: { height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, }, + scrollContainer: { + overflowZ: 'hidden', + height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, + WebkitOverflowScrolling: 'touch', + overflow: 'auto', + }, }; export class Portal extends React.Component { @@ -165,7 +171,7 @@ export class Portal extends React.Component { onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} /> -
+
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index 50760c32d..ba0db7c47 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -57,7 +57,7 @@ export class RelayerIndex extends React.Component +
Date: Mon, 23 Apr 2018 22:17:26 -0700 Subject: Add headers to wallet and relayer index --- packages/website/ts/components/portal/portal.tsx | 12 +++++++++++- .../website/ts/components/relayer_index/relayer_index.tsx | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 6939d8905..507860ee6 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -68,6 +68,10 @@ const styles: Styles = { WebkitOverflowScrolling: 'touch', overflow: 'auto', }, + title: { + fontWeight: 'bold', + fontSize: 20, + }, }; export class Portal extends React.Component { @@ -154,7 +158,10 @@ export class Portal extends React.Component { />
-
+
+
+ Your Account +
{ />
+
+ Explore 0x Ecosystem +
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index ba0db7c47..50760c32d 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -57,7 +57,7 @@ export class RelayerIndex extends React.Component +
Date: Mon, 23 Apr 2018 23:47:04 -0700 Subject: Relayer grid spacing tweaks --- packages/website/ts/components/relayer_index/relayer_index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index 50760c32d..1e92dba85 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -32,9 +32,9 @@ const styles: Styles = { }, }; -const CELL_HEIGHT = 260; +const CELL_HEIGHT = 290; const NUMBER_OF_COLUMNS = 4; -const GRID_PADDING = 16; +const GRID_PADDING = 20; export class RelayerIndex extends React.Component { private _isUnmounted: boolean; -- cgit v1.2.3 From 9c827a0298df3e54e8b18e9f38b1d4027d2b5d83 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 23:47:37 -0700 Subject: Top bar expanded display type --- packages/website/ts/components/portal/portal.tsx | 5 ++- packages/website/ts/components/top_bar/top_bar.tsx | 45 ++++++++++++++-------- 2 files changed, 33 insertions(+), 17 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 507860ee6..bf12c924f 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -9,7 +9,7 @@ import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; -import { TopBar } from 'ts/components/top_bar/top_bar'; +import { TopBar, TopBarDisplayType } from 'ts/components/top_bar/top_bar'; import { FlashMessage } from 'ts/components/ui/flash_message'; import { Wallet } from 'ts/components/wallet/wallet'; import { localStorage } from 'ts/local_storage/local_storage'; @@ -51,7 +51,7 @@ interface PortalState { } const THROTTLE_TIMEOUT = 100; -const TOP_BAR_HEIGHT = 60; +const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded); const styles: Styles = { root: { @@ -154,6 +154,7 @@ export class Portal extends React.Component { location={this.props.location} blockchain={this._blockchain} translate={this.props.translate} + displayType={TopBarDisplayType.Expanded} style={{ backgroundColor: colors.lightestGrey }} />
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index 0c32f4c62..eecec92fb 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -19,7 +19,12 @@ import { Deco, Key, ProviderType, WebsiteLegacyPaths, WebsitePaths } from 'ts/ty import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; -interface TopBarProps { +export enum TopBarDisplayType { + Default, + Expanded, +} + +export interface TopBarProps { userAddress?: string; networkId?: number; injectedProviderName?: string; @@ -34,7 +39,7 @@ interface TopBarProps { availableDocVersions?: string[]; menu?: DocsMenu; menuSubsectionsBySection?: MenuSubsectionsBySection; - shouldFullWidth?: boolean; + displayType?: TopBarDisplayType; docsInfo?: DocsInfo; style?: React.CSSProperties; isNightVersion?: boolean; @@ -56,8 +61,7 @@ const styles: Styles = { width: 70, }, topBar: { - backgroundcolor: colors.white, - height: 59, + backgroundColor: colors.white, width: '100%', position: 'relative', top: 0, @@ -78,12 +82,19 @@ const styles: Styles = { }, }; +const DEFAULT_HEIGHT = 59; +const EXPANDED_HEIGHT = 75; + export class TopBar extends React.Component { public static defaultProps: Partial = { - shouldFullWidth: false, + displayType: TopBarDisplayType.Default, style: {}, isNightVersion: false, }; + public static heightForDisplayType(displayType: TopBarDisplayType) { + const result = displayType === TopBarDisplayType.Expanded ? EXPANDED_HEIGHT : DEFAULT_HEIGHT; + return result + 1; + } constructor(props: TopBarProps) { super(props); this.state = { @@ -92,8 +103,9 @@ export class TopBar extends React.Component { } public render() { const isNightVersion = this.props.isNightVersion; - const isFullWidthPage = this.props.shouldFullWidth; - const parentClassNames = `flex mx-auto ${isFullWidthPage ? 'pl2' : 'max-width-4'}`; + const isExpandedDisplayType = this.props.displayType === TopBarDisplayType.Expanded; + const parentClassNames = `flex mx-auto ${isExpandedDisplayType ? 'pl3 py1' : 'max-width-4'}`; + const height = isExpandedDisplayType ? EXPANDED_HEIGHT : DEFAULT_HEIGHT; const developerSectionMenuItems = [ @@ -172,9 +184,11 @@ export class TopBar extends React.Component { , ]; const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {}; - const fullWidthClasses = isFullWidthPage ? 'pr4' : ''; + const fullWidthClasses = isExpandedDisplayType ? 'pr4' : ''; const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png'; - const menuClasses = `col col-${isFullWidthPage ? '4' : '5'} ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`; + const menuClasses = `col col-${ + isExpandedDisplayType ? '4' : '5' + } ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`; const menuIconStyle = { fontSize: 25, color: isNightVersion ? 'white' : 'black', @@ -191,15 +205,15 @@ export class TopBar extends React.Component { ); const popoverContent = {developerSectionMenuItems}; return ( -
+
-
-
+
+
{!this._isViewingPortal() && (
@@ -236,7 +250,7 @@ export class TopBar extends React.Component { path={`${WebsitePaths.Portal}`} isPrimary={true} style={styles.menuItem} - className={`${isFullWidthPage && 'md-hide'}`} + className={`${isExpandedDisplayType && 'md-hide'}`} isNightVersion={isNightVersion} isExternal={false} /> @@ -256,7 +270,7 @@ export class TopBar extends React.Component { />
)} -
+
@@ -505,7 +519,8 @@ export class TopBar extends React.Component { this._isViewingJsonSchemasDocs() || this._isViewingSolCovDocs() || this._isViewingSubprovidersDocs() || - this._isViewingConnectDocs() + this._isViewingConnectDocs() || + this._isViewingPortal() ); } } // tslint:disable:max-file-line-count -- cgit v1.2.3 From b8c611de2b82657a274c55007ffc5d72807eae7f Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 24 Apr 2018 01:04:57 -0700 Subject: ProviderDisplay changes --- .../ts/components/top_bar/provider_display.tsx | 40 +++++++++++++++------- packages/website/ts/components/top_bar/top_bar.tsx | 25 +------------- 2 files changed, 28 insertions(+), 37 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx index 221c34f8c..fa5609014 100644 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ b/packages/website/ts/components/top_bar/provider_display.tsx @@ -1,4 +1,4 @@ -import { colors } from '@0xproject/react-shared'; +import { colors, Styles } from '@0xproject/react-shared'; import * as _ from 'lodash'; import RaisedButton from 'material-ui/RaisedButton'; import * as React from 'react'; @@ -11,9 +11,9 @@ import { ProviderType } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { utils } from 'ts/utils/utils'; -const IDENTICON_DIAMETER = 32; +const IDENTICON_DIAMETER = 24; -interface ProviderDisplayProps { +export interface ProviderDisplayProps { dispatcher: Dispatcher; userAddress: string; networkId: number; @@ -25,6 +25,18 @@ interface ProviderDisplayProps { interface ProviderDisplayState {} +const styles: Styles = { + root: { + height: 24, + backgroundColor: colors.white, + borderBottomRightRadius: 24, + borderBottomLeftRadius: 24, + borderTopRightRadius: 24, + borderTopLeftRadius: 24, + boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`, + }, +}; + export class ProviderDisplay extends React.Component { public render() { const isAddressAvailable = !_.isEmpty(this.props.userAddress); @@ -40,21 +52,23 @@ export class ProviderDisplay extends React.Component +
-
-
{providerTitle}
-
{displayAddress}
-
-
- +
+
{displayAddress}
+ {isProviderMetamask && ( +
+ +
+ )}
); const hasInjectedProvider = diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index eecec92fb..8c842d2a5 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -52,14 +52,6 @@ interface TopBarState { } const styles: Styles = { - address: { - marginRight: 12, - overflow: 'hidden', - paddingTop: 4, - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - width: 70, - }, topBar: { backgroundColor: colors.white, width: '100%', @@ -258,7 +250,7 @@ export class TopBar extends React.Component {
)} {this.props.blockchainIsLoaded && ( -
+
{
); } - private _renderUser() { - const userAddress = this.props.userAddress; - const identiconDiameter = 26; - return ( -
-
- {!_.isEmpty(userAddress) ? userAddress : ''} -
- {userAddress} -
- -
-
- ); - } private _onMenuButtonClick() { this.setState({ isDrawerOpen: !this.state.isDrawerOpen, -- cgit v1.2.3 From 58794fc8e9ac473154ead395452b8e43c10f5cd7 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 21:07:48 -0700 Subject: Lay out wallet and relayers --- packages/website/ts/components/portal/portal.tsx | 214 +++++++++++++++++++++++ packages/website/ts/containers/portal.ts | 88 ++++++++++ packages/website/ts/index.tsx | 11 +- 3 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 packages/website/ts/components/portal/portal.tsx create mode 100644 packages/website/ts/containers/portal.ts (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx new file mode 100644 index 000000000..8a9e89a72 --- /dev/null +++ b/packages/website/ts/components/portal/portal.tsx @@ -0,0 +1,214 @@ +import { colors, Styles } from '@0xproject/react-shared'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import * as DocumentTitle from 'react-document-title'; + +import { Blockchain } from 'ts/blockchain'; +import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; +import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; +import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; +import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; +import { TopBar } from 'ts/components/top_bar/top_bar'; +import { FlashMessage } from 'ts/components/ui/flash_message'; +import { Wallet } from 'ts/components/wallet/wallet'; +import { localStorage } from 'ts/local_storage/local_storage'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; +import { utils } from 'ts/utils/utils'; + +export interface PortalProps { + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + dispatcher: Dispatcher; + hashData: HashData; + injectedProviderName: string; + networkId: number; + nodeVersion: string; + orderFillAmount: BigNumber; + providerType: ProviderType; + screenWidth: ScreenWidths; + tokenByAddress: TokenByAddress; + userEtherBalanceInWei: BigNumber; + userAddress: string; + shouldBlockchainErrDialogBeOpen: boolean; + userSuppliedOrderCache: Order; + location: Location; + flashMessage?: string | React.ReactNode; + lastForceTokenStateRefetch: number; + translate: Translate; +} + +interface PortalState { + prevNetworkId: number; + prevNodeVersion: string; + prevUserAddress: string; + prevPathname: string; + isDisclaimerDialogOpen: boolean; + isLedgerDialogOpen: boolean; +} + +const THROTTLE_TIMEOUT = 100; +const TOP_BAR_HEIGHT = 60; + +const styles: Styles = { + root: { + width: '100%', + height: '100%', + backgroundColor: colors.lightestGrey, + }, + body: { + height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, + }, +}; + +export class Portal extends React.Component { + private _blockchain: Blockchain; + private _throttledScreenWidthUpdate: () => void; + constructor(props: PortalProps) { + super(props); + this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); + const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER); + const hasAcceptedDisclaimer = + !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer); + this.state = { + prevNetworkId: this.props.networkId, + prevNodeVersion: this.props.nodeVersion, + prevUserAddress: this.props.userAddress, + prevPathname: this.props.location.pathname, + isDisclaimerDialogOpen: !hasAcceptedDisclaimer, + isLedgerDialogOpen: false, + }; + } + public componentDidMount() { + window.addEventListener('resize', this._throttledScreenWidthUpdate); + window.scrollTo(0, 0); + } + public componentWillMount() { + this._blockchain = new Blockchain(this.props.dispatcher); + } + public componentWillUnmount() { + this._blockchain.destroy(); + window.removeEventListener('resize', this._throttledScreenWidthUpdate); + // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered + // the initialization process always occurs from the same base state. This helps avoid + // initialization inconsistencies (i.e While the portal was unrendered, the user might have + // become disconnected from their backing Ethereum node, changes user accounts, etc...) + this.props.dispatcher.resetState(); + } + public componentWillReceiveProps(nextProps: PortalProps) { + if (nextProps.networkId !== this.state.prevNetworkId) { + // tslint:disable-next-line:no-floating-promises + this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId); + this.setState({ + prevNetworkId: nextProps.networkId, + }); + } + if (nextProps.userAddress !== this.state.prevUserAddress) { + const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress; + // tslint:disable-next-line:no-floating-promises + this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress); + this.setState({ + prevUserAddress: nextProps.userAddress, + }); + } + if (nextProps.nodeVersion !== this.state.prevNodeVersion) { + // tslint:disable-next-line:no-floating-promises + this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion); + } + if (nextProps.location.pathname !== this.state.prevPathname) { + this.setState({ + prevPathname: nextProps.location.pathname, + }); + } + } + public render() { + const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind( + this.props.dispatcher, + ); + const allTokens = _.values(this.props.tokenByAddress); + const trackedTokens = _.filter(allTokens, t => t.isTracked); + return ( +
+ + +
+
+
+ +
+
+ +
+
+ + + + {this.props.blockchainIsLoaded && ( + + )} +
+
+ ); + } + private _onToggleLedgerDialog() { + this.setState({ + isLedgerDialogOpen: !this.state.isLedgerDialogOpen, + }); + } + private _onPortalDisclaimerAccepted() { + localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set'); + this.setState({ + isDisclaimerDialogOpen: false, + }); + } + private _updateScreenWidth() { + const newScreenWidth = utils.getScreenWidth(); + this.props.dispatcher.updateScreenWidth(newScreenWidth); + } +} diff --git a/packages/website/ts/containers/portal.ts b/packages/website/ts/containers/portal.ts new file mode 100644 index 000000000..3f0feb6e9 --- /dev/null +++ b/packages/website/ts/containers/portal.ts @@ -0,0 +1,88 @@ +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { Portal as PortalComponent, PortalProps as PortalComponentProps } from 'ts/components/portal/portal'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + hashData: HashData; + injectedProviderName: string; + networkId: number; + nodeVersion: string; + orderFillAmount: BigNumber; + providerType: ProviderType; + tokenByAddress: TokenByAddress; + lastForceTokenStateRefetch: number; + userEtherBalanceInWei: BigNumber; + screenWidth: ScreenWidths; + shouldBlockchainErrDialogBeOpen: boolean; + userAddress: string; + userSuppliedOrderCache: Order; + flashMessage?: string | React.ReactNode; + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: PortalComponentProps): ConnectedState => { + const receiveAssetToken = state.sideToAssetToken[Side.Receive]; + const depositAssetToken = state.sideToAssetToken[Side.Deposit]; + const receiveAddress = !_.isUndefined(receiveAssetToken.address) + ? receiveAssetToken.address + : constants.NULL_ADDRESS; + const depositAddress = !_.isUndefined(depositAssetToken.address) + ? depositAssetToken.address + : constants.NULL_ADDRESS; + const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0); + const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0); + const hashData = { + depositAmount, + depositTokenContractAddr: depositAddress, + feeRecipientAddress: constants.NULL_ADDRESS, + makerFee: constants.MAKER_FEE, + orderExpiryTimestamp: state.orderExpiryTimestamp, + orderMakerAddress: state.userAddress, + orderTakerAddress: state.orderTakerAddress !== '' ? state.orderTakerAddress : constants.NULL_ADDRESS, + receiveAmount, + receiveTokenContractAddr: receiveAddress, + takerFee: constants.TAKER_FEE, + orderSalt: state.orderSalt, + }; + return { + blockchainErr: state.blockchainErr, + blockchainIsLoaded: state.blockchainIsLoaded, + hashData, + injectedProviderName: state.injectedProviderName, + networkId: state.networkId, + nodeVersion: state.nodeVersion, + orderFillAmount: state.orderFillAmount, + providerType: state.providerType, + screenWidth: state.screenWidth, + shouldBlockchainErrDialogBeOpen: state.shouldBlockchainErrDialogBeOpen, + tokenByAddress: state.tokenByAddress, + lastForceTokenStateRefetch: state.lastForceTokenStateRefetch, + userAddress: state.userAddress, + userEtherBalanceInWei: state.userEtherBalanceInWei, + userSuppliedOrderCache: state.userSuppliedOrderCache, + flashMessage: state.flashMessage, + translate: state.translate, + }; +}; + +const mapDispatchToProps = (dispatch: Dispatch): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const Portal: React.ComponentClass = connect(mapStateToProps, mapDispatchToProps)( + PortalComponent, +); diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 9535dd222..1b1255214 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -34,9 +34,14 @@ import 'less/all.less'; // cause we only want to import the module when the user navigates to the page. // At the same time webpack statically parses for System.import() to determine bundle chunk split points // so each lazy import needs it's own `System.import()` declaration. -const LazyPortal = createLazyComponent('LegacyPortal', async () => - System.import(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'), -); +const LazyPortal = + utils.isDevelopment() || utils.isStaging() + ? createLazyComponent('Portal', async () => + System.import(/* webpackChunkName: "portal" */ 'ts/containers/portal'), + ) + : createLazyComponent('LegacyPortal', async () => + System.import(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'), + ); const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () => System.import(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'), ); -- cgit v1.2.3 From 14b29172b1713610c80ccf5b7390f7b445b0eb75 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 21:45:05 -0700 Subject: Add scrolling to relayer index --- packages/website/ts/components/portal/portal.tsx | 8 +++++++- packages/website/ts/components/relayer_index/relayer_index.tsx | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 8a9e89a72..6939d8905 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -62,6 +62,12 @@ const styles: Styles = { body: { height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, }, + scrollContainer: { + overflowZ: 'hidden', + height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, + WebkitOverflowScrolling: 'touch', + overflow: 'auto', + }, }; export class Portal extends React.Component { @@ -165,7 +171,7 @@ export class Portal extends React.Component { onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} />
-
+
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index c1ab4227a..e8775e1a5 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -57,7 +57,7 @@ export class RelayerIndex extends React.Component +
Date: Mon, 23 Apr 2018 22:17:26 -0700 Subject: Add headers to wallet and relayer index --- packages/website/ts/components/portal/portal.tsx | 12 +++++++++++- .../website/ts/components/relayer_index/relayer_index.tsx | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 6939d8905..507860ee6 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -68,6 +68,10 @@ const styles: Styles = { WebkitOverflowScrolling: 'touch', overflow: 'auto', }, + title: { + fontWeight: 'bold', + fontSize: 20, + }, }; export class Portal extends React.Component { @@ -154,7 +158,10 @@ export class Portal extends React.Component { />
-
+
+
+ Your Account +
{ />
+
+ Explore 0x Ecosystem +
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index e8775e1a5..c1ab4227a 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -57,7 +57,7 @@ export class RelayerIndex extends React.Component +
Date: Wed, 18 Apr 2018 22:22:39 +0200 Subject: Implement new artifacts format --- packages/abi-gen/src/index.ts | 4 +- packages/contracts/compiler.json | 33 ++++++ packages/contracts/package.json | 5 +- .../contracts/test/multi_sig_with_time_lock.ts | 2 +- ...i_sig_with_time_lock_except_remove_auth_addr.ts | 5 +- packages/contracts/util/artifacts.ts | 24 ++-- packages/contracts/util/types.ts | 16 --- packages/deployer/src/cli.ts | 93 +++++++--------- packages/deployer/src/compiler.ts | 122 ++++++++++----------- packages/deployer/src/deployer.ts | 48 ++++---- packages/deployer/src/index.ts | 1 + packages/deployer/src/utils/types.ts | 53 +++++---- packages/deployer/test/compiler_test.ts | 7 +- packages/deployer/test/deployer_test.ts | 9 +- packages/deployer/test/fixtures/exchange_bin.ts | 2 +- packages/deployer/test/util/constants.ts | 2 +- packages/metacoin/compiler.json | 15 +++ packages/metacoin/package.json | 4 +- packages/sol-cov/src/collect_contract_data.ts | 21 ++-- packages/sol-cov/src/coverage_manager.ts | 10 +- packages/sol-resolver/src/index.ts | 1 + .../sol-resolver/src/resolvers/name_resolver.ts | 11 +- .../src/resolvers/relative_fs_resolver.ts | 26 +++++ packages/typescript-typings/types/solc/index.d.ts | 70 ++++++------ 24 files changed, 313 insertions(+), 271 deletions(-) create mode 100644 packages/contracts/compiler.json create mode 100644 packages/metacoin/compiler.json create mode 100644 packages/sol-resolver/src/resolvers/relative_fs_resolver.ts (limited to 'packages') diff --git a/packages/abi-gen/src/index.ts b/packages/abi-gen/src/index.ts index ecef33b16..7125171b9 100644 --- a/packages/abi-gen/src/index.ts +++ b/packages/abi-gen/src/index.ts @@ -108,8 +108,8 @@ for (const abiFileName of abiFileNames) { ABI = parsedContent; // ABI file } else if (!_.isUndefined(parsedContent.abi)) { ABI = parsedContent.abi; // Truffle artifact - } else if (!_.isUndefined(parsedContent.networks) && !_.isUndefined(parsedContent.networks[args.networkId])) { - ABI = parsedContent.networks[args.networkId].abi; // 0x contracts package artifact + } else if (!_.isUndefined(parsedContent.compilerOutput.abi)) { + ABI = parsedContent.compilerOutput.abi; // 0x artifact } if (_.isUndefined(ABI)) { logUtils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`); diff --git a/packages/contracts/compiler.json b/packages/contracts/compiler.json new file mode 100644 index 000000000..06a9829d5 --- /dev/null +++ b/packages/contracts/compiler.json @@ -0,0 +1,33 @@ +{ + "artifactsDir": "../migrations/src/artifacts", + "contractsDir": "src/contracts", + "compilerSettings": { + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + } + }, + "contracts": [ + "Exchange", + "DummyToken", + "ZRXToken", + "Token", + "WETH9", + "TokenTransferProxy", + "MultiSigWallet", + "MultiSigWalletWithTimeLock", + "MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress", + "MaliciousToken", + "TokenRegistry", + "Arbitrage", + "EtherDelta", + "AccountLevels" + ] +} diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 6d51d71cb..4ca4e2db1 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -16,7 +16,7 @@ "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", "run_mocha": "mocha 'lib/test/**/*.js' --timeout 100000 --bail --exit", "compile:comment": "Yarn workspaces do not link binaries correctly so we need to reference them directly https://github.com/yarnpkg/yarn/issues/3846", - "compile": "node ../deployer/lib/src/cli.js compile --contracts ${npm_package_config_contracts} --contracts-dir src/contracts --artifacts-dir ../migrations/src/artifacts", + "compile": "node ../deployer/lib/src/cli.js compile", "clean": "shx rm -rf ./lib", "generate_contract_wrappers": "node ../abi-gen/lib/index.js --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'", "lint": "tslint --project . 'migrations/**/*.ts' 'test/**/*.ts' 'util/**/*.ts' 'deploy/**/*.ts'", @@ -26,8 +26,7 @@ "test:circleci": "yarn test:coverage" }, "config": { - "abis": "../migrations/src/artifacts/@(DummyToken|TokenTransferProxy|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|Arbitrage|EtherDelta|AccountLevels).json", - "contracts": "Exchange,DummyToken,ZRXToken,Token,WETH9,TokenTransferProxy,MultiSigWallet,MultiSigWalletWithTimeLock,MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,MaliciousToken,TokenRegistry,Arbitrage,EtherDelta,AccountLevels" + "abis": "../migrations/src/artifacts/@(DummyToken|TokenTransferProxy|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|Arbitrage|EtherDelta|AccountLevels).json" }, "repository": { "type": "git", diff --git a/packages/contracts/test/multi_sig_with_time_lock.ts b/packages/contracts/test/multi_sig_with_time_lock.ts index b7604457f..5cc744713 100644 --- a/packages/contracts/test/multi_sig_with_time_lock.ts +++ b/packages/contracts/test/multi_sig_with_time_lock.ts @@ -17,7 +17,7 @@ import { chaiSetup } from './utils/chai_setup'; import { deployer } from './utils/deployer'; import { provider, web3Wrapper } from './utils/web3_wrapper'; -const MULTI_SIG_ABI = artifacts.MultiSigWalletWithTimeLockArtifact.networks[constants.TESTRPC_NETWORK_ID].abi; +const MULTI_SIG_ABI = artifacts.MultiSigWalletWithTimeLockArtifact.compilerOutput.abi; chaiSetup.configure(); const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); diff --git a/packages/contracts/test/multi_sig_with_time_lock_except_remove_auth_addr.ts b/packages/contracts/test/multi_sig_with_time_lock_except_remove_auth_addr.ts index 2f928ede2..06fa30d96 100644 --- a/packages/contracts/test/multi_sig_with_time_lock_except_remove_auth_addr.ts +++ b/packages/contracts/test/multi_sig_with_time_lock_except_remove_auth_addr.ts @@ -17,10 +17,9 @@ import { ContractName, SubmissionContractEventArgs, TransactionDataParams } from import { chaiSetup } from './utils/chai_setup'; import { deployer } from './utils/deployer'; import { provider, web3Wrapper } from './utils/web3_wrapper'; -const PROXY_ABI = artifacts.TokenTransferProxyArtifact.networks[constants.TESTRPC_NETWORK_ID].abi; +const PROXY_ABI = artifacts.TokenTransferProxyArtifact.compilerOutput.abi; const MUTISIG_WALLET_WITH_TIME_LOCK_EXCEPT_REMOVE_AUTHORIZED_ADDRESS_ABI = - artifacts.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressArtifact.networks[constants.TESTRPC_NETWORK_ID] - .abi; + artifacts.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressArtifact.compilerOutput.abi; chaiSetup.configure(); const expect = chai.expect; diff --git a/packages/contracts/util/artifacts.ts b/packages/contracts/util/artifacts.ts index 7c375c1b7..a1d6e5060 100644 --- a/packages/contracts/util/artifacts.ts +++ b/packages/contracts/util/artifacts.ts @@ -1,3 +1,5 @@ +import { ContractArtifact } from '@0xproject/deployer'; + import * as DummyTokenArtifact from '../src/artifacts/DummyToken.json'; import * as ExchangeArtifact from '../src/artifacts/Exchange.json'; import * as MaliciousTokenArtifact from '../src/artifacts/MaliciousToken.json'; @@ -9,17 +11,15 @@ import * as TokenTransferProxyArtifact from '../src/artifacts/TokenTransferProxy import * as EtherTokenArtifact from '../src/artifacts/WETH9.json'; import * as ZRXArtifact from '../src/artifacts/ZRXToken.json'; -import { Artifact } from './types'; - export const artifacts = { - ZRXArtifact: (ZRXArtifact as any) as Artifact, - DummyTokenArtifact: (DummyTokenArtifact as any) as Artifact, - TokenArtifact: (TokenArtifact as any) as Artifact, - ExchangeArtifact: (ExchangeArtifact as any) as Artifact, - EtherTokenArtifact: (EtherTokenArtifact as any) as Artifact, - TokenRegistryArtifact: (TokenRegistryArtifact as any) as Artifact, - MaliciousTokenArtifact: (MaliciousTokenArtifact as any) as Artifact, - TokenTransferProxyArtifact: (TokenTransferProxyArtifact as any) as Artifact, - MultiSigWalletWithTimeLockArtifact: (MultiSigWalletWithTimeLockArtifact as any) as Artifact, - MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressArtifact: (MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressArtifact as any) as Artifact, + ZRXArtifact: (ZRXArtifact as any) as ContractArtifact, + DummyTokenArtifact: (DummyTokenArtifact as any) as ContractArtifact, + TokenArtifact: (TokenArtifact as any) as ContractArtifact, + ExchangeArtifact: (ExchangeArtifact as any) as ContractArtifact, + EtherTokenArtifact: (EtherTokenArtifact as any) as ContractArtifact, + TokenRegistryArtifact: (TokenRegistryArtifact as any) as ContractArtifact, + MaliciousTokenArtifact: (MaliciousTokenArtifact as any) as ContractArtifact, + TokenTransferProxyArtifact: (TokenTransferProxyArtifact as any) as ContractArtifact, + MultiSigWalletWithTimeLockArtifact: (MultiSigWalletWithTimeLockArtifact as any) as ContractArtifact, + MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressArtifact: (MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressArtifact as any) as ContractArtifact, }; diff --git a/packages/contracts/util/types.ts b/packages/contracts/util/types.ts index 321084c42..9bc412433 100644 --- a/packages/contracts/util/types.ts +++ b/packages/contracts/util/types.ts @@ -100,19 +100,3 @@ export enum ContractName { EtherDelta = 'EtherDelta', Arbitrage = 'Arbitrage', } - -export interface Artifact { - contract_name: ContractName; - networks: { - [networkId: number]: { - abi: ContractAbi; - solc_version: string; - keccak256: string; - optimizer_enabled: number; - unlinked_binary: string; - updated_at: number; - address: string; - constructor_args: string; - }; - }; -} diff --git a/packages/deployer/src/cli.ts b/packages/deployer/src/cli.ts index 7f1ae708a..b06168e31 100644 --- a/packages/deployer/src/cli.ts +++ b/packages/deployer/src/cli.ts @@ -13,7 +13,6 @@ import { constants } from './utils/constants'; import { consoleReporter } from './utils/error_reporter'; import { CliOptions, CompilerOptions, DeployerOptions } from './utils/types'; -const DEFAULT_OPTIMIZER_ENABLED = false; const DEFAULT_CONTRACTS_DIR = path.resolve('src/contracts'); const DEFAULT_ARTIFACTS_DIR = path.resolve('src/artifacts'); const DEFAULT_NETWORK_ID = 50; @@ -28,10 +27,8 @@ const DEFAULT_CONTRACTS_LIST = '*'; async function onCompileCommandAsync(argv: CliOptions): Promise { const opts: CompilerOptions = { contractsDir: argv.contractsDir, - networkId: argv.networkId, - optimizerEnabled: argv.shouldOptimize, artifactsDir: argv.artifactsDir, - specifiedContracts: getContractsSetFromList(argv.contracts), + contracts: argv.contracts === '*' ? argv.contracts : argv.contracts.split(','), }; await commands.compileAsync(opts); } @@ -46,10 +43,8 @@ async function onDeployCommandAsync(argv: CliOptions): Promise { const networkId = await web3Wrapper.getNetworkIdAsync(); const compilerOpts: CompilerOptions = { contractsDir: argv.contractsDir, - networkId, - optimizerEnabled: argv.shouldOptimize, artifactsDir: argv.artifactsDir, - specifiedContracts: getContractsSetFromList(argv.contracts), + contracts: argv.contracts === '*' ? argv.contracts : argv.contracts.split(','), }; await commands.compileAsync(compilerOpts); @@ -58,7 +53,7 @@ async function onDeployCommandAsync(argv: CliOptions): Promise { from: argv.account, }; const deployerOpts: DeployerOptions = { - artifactsDir: argv.artifactsDir, + artifactsDir: argv.artifactsDir || DEFAULT_ARTIFACTS_DIR, jsonrpcUrl: argv.jsonrpcUrl, networkId, defaults, @@ -67,82 +62,70 @@ async function onDeployCommandAsync(argv: CliOptions): Promise { const deployerArgs = deployerArgsString.split(','); await commands.deployAsync(argv.contract as string, deployerArgs, deployerOpts); } -/** - * Creates a set of contracts to compile. - * @param contracts Comma separated list of contracts to compile - */ -function getContractsSetFromList(contracts: string): Set { - const specifiedContracts = new Set(); - if (contracts === '*') { - return new Set(['*']); - } - const contractsArray = contracts.split(','); - _.forEach(contractsArray, contractName => { - specifiedContracts.add(contractName); - }); - return specifiedContracts; -} /** * Provides extra required options for deploy command. * @param yargsInstance yargs instance provided in builder function callback. */ function deployCommandBuilder(yargsInstance: any) { return yargsInstance - .option('contract', { - type: 'string', - description: 'name of contract to deploy, exluding .sol extension', - }) - .option('args', { - type: 'string', - description: 'comma separated list of constructor args to deploy contract with', - }) - .demandOption(['contract', 'args']) - .help().argv; -} - -(() => { - const identityCommandBuilder = _.identity; - return yargs - .option('contracts-dir', { - type: 'string', - default: DEFAULT_CONTRACTS_DIR, - description: 'path of contracts directory to compile', - }) .option('network-id', { type: 'number', default: DEFAULT_NETWORK_ID, description: 'mainnet=1, kovan=42, testrpc=50', }) - .option('should-optimize', { - type: 'boolean', - default: DEFAULT_OPTIMIZER_ENABLED, - description: 'enable optimizer', + .option('contract', { + type: 'string', + description: 'name of contract to deploy, exluding .sol extension', }) - .option('artifacts-dir', { + .option('args', { type: 'string', - default: DEFAULT_ARTIFACTS_DIR, - description: 'path to write contracts artifacts to', + description: 'comma separated list of constructor args to deploy contract with', }) .option('jsonrpc-url', { type: 'string', default: DEFAULT_JSONRPC_URL, description: 'url of JSON RPC', }) + .option('account', { + type: 'string', + description: 'account to use for deploying contracts', + }) .option('gas-price', { type: 'string', default: DEFAULT_GAS_PRICE, description: 'gasPrice to be used for transactions', }) - .option('account', { - type: 'string', - description: 'account to use for deploying contracts', - }) + .demandOption(['contract', 'args', 'account']) + .help().argv; +} + +/** + * Provides extra required options for compile command. + * @param yargsInstance yargs instance provided in builder function callback. + */ +function compileCommandBuilder(yargsInstance: any) { + return yargsInstance .option('contracts', { type: 'string', default: DEFAULT_CONTRACTS_LIST, description: 'comma separated list of contracts to compile', }) - .command('compile', 'compile contracts', identityCommandBuilder, consoleReporter(onCompileCommandAsync)) + .help().argv; +} + +(() => { + const identityCommandBuilder = _.identity; + return yargs + .option('contracts-dir', { + type: 'string', + description: 'path of contracts directory to compile', + }) + .option('artifacts-dir', { + type: 'string', + description: 'path to write contracts artifacts to', + }) + .demandCommand(1) + .command('compile', 'compile contracts', compileCommandBuilder, consoleReporter(onCompileCommandAsync)) .command( 'deploy', 'deploy a single contract with provided arguments', diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index a3c8004ec..673bc3186 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -6,6 +6,7 @@ import { FSResolver, NameResolver, NPMResolver, + RelativeFSResolver, Resolver, URLResolver, } from '@0xproject/sol-resolver'; @@ -38,11 +39,25 @@ import { ContractNetworks, ContractSourceData, ContractSpecificSourceData, + ContractVersionData, } from './utils/types'; import { utils } from './utils/utils'; const ALL_CONTRACTS_IDENTIFIER = '*'; const SOLC_BIN_DIR = path.join(__dirname, '..', '..', 'solc_bin'); +const DEFAULT_CONTRACTS_DIR = path.resolve('contracts'); +const DEFAULT_ARTIFACTS_DIR = path.resolve('artifacts'); +const DEFAULT_COMPILER_SETTINGS: solc.CompilerSettings = { + optimizer: { + enabled: false, + }, + outputSelection: { + '*': { + '*': ['abi', 'evm.bytecode.object'], + }, + }, +}; +const CONFIG_FILE = 'compiler.json'; /** * The Compiler facilitates compiling Solidity smart contracts and saves the results @@ -52,26 +67,27 @@ export class Compiler { private _resolver: Resolver; private _nameResolver: NameResolver; private _contractsDir: string; - private _networkId: number; - private _optimizerEnabled: boolean; + private _compilerSettings: solc.CompilerSettings; private _artifactsDir: string; - private _specifiedContracts: Set = new Set(); + private _specifiedContracts: string[] | '*'; /** * Instantiates a new instance of the Compiler class. - * @param opts Options specifying directories, network, and optimization settings. * @return An instance of the Compiler class. */ constructor(opts: CompilerOptions) { - this._contractsDir = opts.contractsDir; - this._networkId = opts.networkId; - this._optimizerEnabled = opts.optimizerEnabled; - this._artifactsDir = opts.artifactsDir; - this._specifiedContracts = opts.specifiedContracts; + const config: CompilerOptions = fs.existsSync(CONFIG_FILE) + ? JSON.parse(fs.readFileSync(CONFIG_FILE).toString()) + : {}; + this._contractsDir = opts.contractsDir || config.contractsDir || DEFAULT_CONTRACTS_DIR; + this._compilerSettings = opts.compilerSettings || config.compilerSettings || DEFAULT_COMPILER_SETTINGS; + this._artifactsDir = opts.artifactsDir || config.artifactsDir || DEFAULT_ARTIFACTS_DIR; + this._specifiedContracts = opts.contracts || config.contracts || '*'; this._nameResolver = new NameResolver(path.resolve(this._contractsDir)); const resolver = new FallthroughResolver(); resolver.appendResolver(new URLResolver()); const packagePath = path.resolve(''); resolver.appendResolver(new NPMResolver(packagePath)); + resolver.appendResolver(new RelativeFSResolver(this._contractsDir)); resolver.appendResolver(new FSResolver()); resolver.appendResolver(this._nameResolver); this._resolver = resolver; @@ -83,13 +99,13 @@ export class Compiler { await createDirIfDoesNotExistAsync(this._artifactsDir); await createDirIfDoesNotExistAsync(SOLC_BIN_DIR); let contractNamesToCompile: string[] = []; - if (this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER)) { + if (this._specifiedContracts === ALL_CONTRACTS_IDENTIFIER) { const allContracts = this._nameResolver.getAll(); contractNamesToCompile = _.map(allContracts, contractSource => path.basename(contractSource.path, constants.SOLIDITY_FILE_EXTENSION), ); } else { - contractNamesToCompile = Array.from(this._specifiedContracts.values()); + contractNamesToCompile = this._specifiedContracts; } for (const contractNameToCompile of contractNamesToCompile) { await this._compileContractAsync(contractNameToCompile); @@ -101,17 +117,18 @@ export class Compiler { */ private async _compileContractAsync(contractName: string): Promise { const contractSource = this._resolver.resolve(contractName); + const absoluteContractPath = path.join(this._contractsDir, contractSource.path); const currentArtifactIfExists = await getContractArtifactIfExistsAsync(this._artifactsDir, contractName); - const sourceTreeHashHex = `0x${this._getSourceTreeHash(contractSource.path).toString('hex')}`; - + const sourceTreeHashHex = `0x${this._getSourceTreeHash(absoluteContractPath).toString('hex')}`; let shouldCompile = false; if (_.isUndefined(currentArtifactIfExists)) { shouldCompile = true; } else { const currentArtifact = currentArtifactIfExists as ContractArtifact; shouldCompile = - currentArtifact.networks[this._networkId].optimizer_enabled !== this._optimizerEnabled || - currentArtifact.networks[this._networkId].source_tree_hash !== sourceTreeHashHex; + currentArtifact.schemaVersion !== '2.0.0' || + !_.isEqual(currentArtifact.compiler.settings, this._compilerSettings) || + currentArtifact.sourceTreeHashHex !== sourceTreeHashHex; } if (!shouldCompile) { return; @@ -139,30 +156,14 @@ export class Compiler { logUtils.log(`Compiling ${contractName} with Solidity v${solcVersion}...`); const source = contractSource.source; - const absoluteFilePath = contractSource.path; const standardInput: solc.StandardInput = { language: 'Solidity', sources: { - [absoluteFilePath]: { - urls: [`file://${absoluteFilePath}`], - }, - }, - settings: { - optimizer: { - enabled: this._optimizerEnabled, - }, - outputSelection: { - '*': { - '*': [ - 'abi', - 'evm.bytecode.object', - 'evm.bytecode.sourceMap', - 'evm.deployedBytecode.object', - 'evm.deployedBytecode.sourceMap', - ], - }, + [contractSource.path]: { + content: contractSource.source, }, }, + settings: this._compilerSettings, }; const compiled: solc.StandardOutput = JSON.parse( solcInstance.compileStandardWrapper(JSON.stringify(standardInput), importPath => { @@ -188,34 +189,28 @@ export class Compiler { }); } } - const compiledData = compiled.contracts[absoluteFilePath][contractName]; + const compiledData = compiled.contracts[contractSource.path][contractName]; if (_.isUndefined(compiledData)) { throw new Error( - `Contract ${contractName} not found in ${absoluteFilePath}. Please make sure your contract has the same name as it's file name`, + `Contract ${contractName} not found in ${ + contractSource.path + }. Please make sure your contract has the same name as it's file name`, ); } - const abi: ContractAbi = compiledData.abi; - const bytecode = `0x${compiledData.evm.bytecode.object}`; - const runtimeBytecode = `0x${compiledData.evm.deployedBytecode.object}`; - const sourceMap = compiledData.evm.bytecode.sourceMap; - const sourceMapRuntime = compiledData.evm.deployedBytecode.sourceMap; - const unresolvedSourcePaths = _.keys(compiled.sources); - const sources = _.map( - unresolvedSourcePaths, - unresolvedSourcePath => this._resolver.resolve(unresolvedSourcePath).path, + const sourceCodes = _.mapValues( + compiled.sources, + (_1, sourceFilePath) => this._resolver.resolve(sourceFilePath).source, ); - const updated_at = Date.now(); - const contractNetworkData: ContractNetworkData = { - solc_version: solcVersion, - source_tree_hash: sourceTreeHashHex, - optimizer_enabled: this._optimizerEnabled, - abi, - bytecode, - runtime_bytecode: runtimeBytecode, - updated_at, - source_map: sourceMap, - source_map_runtime: sourceMapRuntime, - sources, + const contractVersion: ContractVersionData = { + compilerOutput: compiledData, + sources: compiled.sources, + sourceCodes, + sourceTreeHashHex, + compiler: { + name: 'solc', + version: solcVersion, + settings: this._compilerSettings, + }, }; let newArtifact: ContractArtifact; @@ -223,17 +218,14 @@ export class Compiler { const currentArtifact = currentArtifactIfExists as ContractArtifact; newArtifact = { ...currentArtifact, - networks: { - ...currentArtifact.networks, - [this._networkId]: contractNetworkData, - }, + ...contractVersion, }; } else { newArtifact = { - contract_name: contractName, - networks: { - [this._networkId]: contractNetworkData, - }, + schemaVersion: '2.0.0', + contractName, + ...contractVersion, + networks: {}, }; } diff --git a/packages/deployer/src/deployer.ts b/packages/deployer/src/deployer.ts index ad05417b1..fe959e405 100644 --- a/packages/deployer/src/deployer.ts +++ b/packages/deployer/src/deployer.ts @@ -2,6 +2,7 @@ import { AbiType, ConstructorAbi, ContractAbi, Provider, TxData } from '@0xproje import { logUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; +import * as solc from 'solc'; import * as Web3 from 'web3'; import { Contract } from './utils/contract'; @@ -28,7 +29,20 @@ export class Deployer { private _artifactsDir: string; private _networkId: number; private _defaults: Partial; - + /** + * Gets data for current version stored in artifact. + * @param contractArtifact The contract artifact. + * @return Version specific contract data. + */ + private static _getContractCompilerOutputFromArtifactIfExists( + contractArtifact: ContractArtifact, + ): solc.StandardContractOutput { + const compilerOutputIfExists = contractArtifact.compilerOutput; + if (_.isUndefined(compilerOutputIfExists)) { + throw new Error(`Compiler output not found in artifact for contract: ${contractArtifact.contractName}`); + } + return compilerOutputIfExists; + } /** * Instantiate a new instance of the Deployer class. * @param opts Deployer options, including either an RPC url or Provider instance. @@ -58,10 +72,8 @@ export class Deployer { */ public async deployAsync(contractName: string, args: any[] = []): Promise { const contractArtifactIfExists: ContractArtifact = this._loadContractArtifactIfExists(contractName); - const contractNetworkDataIfExists: ContractNetworkData = this._getContractNetworkDataFromArtifactIfExists( - contractArtifactIfExists, - ); - const data = contractNetworkDataIfExists.bytecode; + const compilerOutput = Deployer._getContractCompilerOutputFromArtifactIfExists(contractArtifactIfExists); + const data = compilerOutput.evm.bytecode.object; const from = await this._getFromAddressAsync(); const gas = await this._getAllowableGasEstimateAsync(data); const txData = { @@ -70,7 +82,7 @@ export class Deployer { data, gas, }; - const abi = contractNetworkDataIfExists.abi; + const abi = compilerOutput.abi; const constructorAbi = _.find(abi, { type: AbiType.Constructor }) as ConstructorAbi; const constructorArgs = _.isUndefined(constructorAbi) ? [] : constructorAbi.inputs; if (constructorArgs.length !== args.length) { @@ -138,15 +150,13 @@ export class Deployer { args: any[], ): Promise { const contractArtifactIfExists: ContractArtifact = this._loadContractArtifactIfExists(contractName); - const contractNetworkDataIfExists: ContractNetworkData = this._getContractNetworkDataFromArtifactIfExists( - contractArtifactIfExists, - ); - const abi = contractNetworkDataIfExists.abi; + const compilerOutput = Deployer._getContractCompilerOutputFromArtifactIfExists(contractArtifactIfExists); + const abi = compilerOutput.abi; const encodedConstructorArgs = encoder.encodeConstructorArgsFromAbi(args, abi); - const newContractData = { - ...contractNetworkDataIfExists, + const newContractData: ContractNetworkData = { address: contractAddress, - constructor_args: encodedConstructorArgs, + links: {}, + constructorArgs: encodedConstructorArgs, }; const newArtifact = { ...contractArtifactIfExists, @@ -173,18 +183,6 @@ export class Deployer { throw new Error(`Artifact not found for contract: ${contractName} at ${artifactPath}`); } } - /** - * Gets data for current networkId stored in artifact. - * @param contractArtifact The contract artifact. - * @return Network specific contract data. - */ - private _getContractNetworkDataFromArtifactIfExists(contractArtifact: ContractArtifact): ContractNetworkData { - const contractNetworkDataIfExists = contractArtifact.networks[this._networkId]; - if (_.isUndefined(contractNetworkDataIfExists)) { - throw new Error(`Data not found in artifact for contract: ${contractArtifact.contract_name}`); - } - return contractNetworkDataIfExists; - } /** * Gets the address to use for sending a transaction. * @return The default from address. If not specified, returns the first address accessible by web3. diff --git a/packages/deployer/src/index.ts b/packages/deployer/src/index.ts index 186d644ef..31a75677b 100644 --- a/packages/deployer/src/index.ts +++ b/packages/deployer/src/index.ts @@ -1,2 +1,3 @@ export { Deployer } from './deployer'; export { Compiler } from './compiler'; +export { ContractArtifact, ContractNetworks } from './utils/types'; diff --git a/packages/deployer/src/utils/types.ts b/packages/deployer/src/utils/types.ts index a20d0f627..c4af5ac87 100644 --- a/packages/deployer/src/utils/types.ts +++ b/packages/deployer/src/utils/types.ts @@ -1,4 +1,5 @@ import { ContractAbi, Provider, TxData } from '@0xproject/types'; +import * as solc from 'solc'; import * as Web3 from 'web3'; import * as yargs from 'yargs'; @@ -9,28 +10,40 @@ export enum AbiType { Fallback = 'fallback', } -export interface ContractArtifact { - contract_name: string; +export interface ContractArtifact extends ContractVersionData { + schemaVersion: '2.0.0'; + contractName: string; networks: ContractNetworks; } +export interface ContractVersionData { + compiler: { + name: 'solc'; + version: string; + settings: solc.CompilerSettings; + }; + sources: { + [sourceName: string]: { + id: number; + }; + }; + sourceCodes: { + [sourceName: string]: string; + }; + sourceTreeHashHex: string; + compilerOutput: solc.StandardContractOutput; +} + export interface ContractNetworks { - [key: number]: ContractNetworkData; + [networkId: number]: ContractNetworkData; } export interface ContractNetworkData { - solc_version: string; - optimizer_enabled: boolean; - source_tree_hash: string; - abi: ContractAbi; - bytecode: string; - runtime_bytecode: string; - address?: string; - constructor_args?: string; - updated_at: number; - source_map: string; - source_map_runtime: string; - sources: string[]; + address: string; + links: { + [linkName: string]: string; + }; + constructorArgs: string; } export interface SolcErrors { @@ -42,7 +55,6 @@ export interface CliOptions extends yargs.Arguments { contractsDir: string; jsonrpcUrl: string; networkId: number; - shouldOptimize: boolean; gasPrice: string; account?: string; contract?: string; @@ -50,11 +62,10 @@ export interface CliOptions extends yargs.Arguments { } export interface CompilerOptions { - contractsDir: string; - networkId: number; - optimizerEnabled: boolean; - artifactsDir: string; - specifiedContracts: Set; + contractsDir?: string; + artifactsDir?: string; + compilerSettings?: solc.CompilerSettings; + contracts?: string[] | '*'; } export interface BaseDeployerOptions { diff --git a/packages/deployer/test/compiler_test.ts b/packages/deployer/test/compiler_test.ts index b03ae7935..9baf433d4 100644 --- a/packages/deployer/test/compiler_test.ts +++ b/packages/deployer/test/compiler_test.ts @@ -18,9 +18,7 @@ describe('#Compiler', function() { const compilerOpts: CompilerOptions = { artifactsDir, contractsDir, - networkId: constants.networkId, - optimizerEnabled: constants.optimizerEnabled, - specifiedContracts: new Set(constants.specifiedContracts), + contracts: constants.contracts, }; const compiler = new Compiler(compilerOpts); beforeEach((done: DoneCallback) => { @@ -38,9 +36,8 @@ describe('#Compiler', function() { }; const exchangeArtifactString = await fsWrapper.readFileAsync(exchangeArtifactPath, opts); const exchangeArtifact: ContractArtifact = JSON.parse(exchangeArtifactString); - const exchangeContractData: ContractNetworkData = exchangeArtifact.networks[constants.networkId]; // The last 43 bytes of the binaries are metadata which may not be equivalent - const unlinkedBinaryWithoutMetadata = exchangeContractData.bytecode.slice(0, -86); + const unlinkedBinaryWithoutMetadata = exchangeArtifact.compilerOutput.evm.bytecode.object.slice(0, -86); const exchangeBinaryWithoutMetadata = exchange_binary.slice(0, -86); expect(unlinkedBinaryWithoutMetadata).to.equal(exchangeBinaryWithoutMetadata); }); diff --git a/packages/deployer/test/deployer_test.ts b/packages/deployer/test/deployer_test.ts index 238624220..a8abc6454 100644 --- a/packages/deployer/test/deployer_test.ts +++ b/packages/deployer/test/deployer_test.ts @@ -19,9 +19,7 @@ describe('#Deployer', () => { const compilerOpts: CompilerOptions = { artifactsDir, contractsDir, - networkId: constants.networkId, - optimizerEnabled: constants.optimizerEnabled, - specifiedContracts: new Set(constants.specifiedContracts), + contracts: constants.contracts, }; const compiler = new Compiler(compilerOpts); const deployerOpts = { @@ -55,8 +53,7 @@ describe('#Deployer', () => { const exchangeContractData: ContractNetworkData = exchangeArtifact.networks[constants.networkId]; const exchangeAddress = exchangeContractInstance.address; expect(exchangeAddress).to.not.equal(undefined); - expect(exchangeContractData.address).to.equal(undefined); - expect(exchangeContractData.constructor_args).to.equal(undefined); + expect(exchangeContractData).to.equal(undefined); }); }); describe('#deployAndSaveAsync', () => { @@ -71,7 +68,7 @@ describe('#Deployer', () => { const exchangeContractData: ContractNetworkData = exchangeArtifact.networks[constants.networkId]; const exchangeAddress = exchangeContractInstance.address; expect(exchangeAddress).to.be.equal(exchangeContractData.address); - expect(constructor_args).to.be.equal(exchangeContractData.constructor_args); + expect(constructor_args).to.be.equal(exchangeContractData.constructorArgs); }); }); }); diff --git a/packages/deployer/test/fixtures/exchange_bin.ts b/packages/deployer/test/fixtures/exchange_bin.ts index 9fbf9bf95..914e76bf5 100644 --- a/packages/deployer/test/fixtures/exchange_bin.ts +++ b/packages/deployer/test/fixtures/exchange_bin.ts @@ -1,4 +1,4 @@ export const constructor_args = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000008da0d80f5007ef1e431dd2127178d224e32c2ef4'; export const exchange_binary = - '0x608060405234801561001057600080fd5b50604051604080612d998339810180604052810190808051906020019092919080519060200190929190505050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050612cca806100cf6000396000f3006080604052600436106100fc576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806314df96ee14610101578063288cdc911461015a5780632ac126221461019f578063363349be146101e4578063394c21e7146103f85780633b30ba59146104975780634f150787146104ee578063741bcc931461071b5780637e9abb50146107cf5780638163681e1461081457806398024a8b146108a6578063add1cbc5146108fb578063b7b2c7d614610952578063baa0181d14610b8b578063bc61394a14610cef578063cfc4d0ec14610dc3578063f06bbf7514610e60578063ffa1ad7414610e93575b600080fd5b34801561010d57600080fd5b50610140600480360381019080803590602001909291908035906020019092919080359060200190929190505050610f23565b604051808215151515815260200191505060405180910390f35b34801561016657600080fd5b506101896004803603810190808035600019169060200190929190505050610f7b565b6040518082815260200191505060405180910390f35b3480156101ab57600080fd5b506101ce6004803603810190808035600019169060200190929190505050610f93565b6040518082815260200191505060405180910390f35b3480156101f057600080fd5b506103e260048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561027257848483905060a00201600580602002604051908101604052809291908260056020028082843782019150505050508152602001906001019061022d565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102f157848483905060c0020160068060200260405190810160405280929190826006602002808284378201915050505050815260200190600101906102ac565b5050505050919291929080359060200190929190803515159060200190929190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290505050610fab565b6040518082815260200191505060405180910390f35b34801561040457600080fd5b506104816004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190505050611110565b6040518082815260200191505060405180910390f35b3480156104a357600080fd5b506104ac6115f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156104fa57600080fd5b5061071960048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561057c57848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610537565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156105fb57848483905060c0020160068060200260405190810160405280929190826006602002808284378201915050505050815260200190600101906105b6565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061161d565b005b34801561072757600080fd5b506107cd6004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291905050506116da565b005b3480156107db57600080fd5b506107fe60048036038101908080356000191690602001909291905050506116ff565b6040518082815260200191505060405180910390f35b34801561082057600080fd5b5061088c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190505050611748565b604051808215151515815260200191505060405180910390f35b3480156108b257600080fd5b506108e5600480360381019080803590602001909291908035906020019092919080359060200190929190505050611849565b6040518082815260200191505060405180910390f35b34801561090757600080fd5b50610910611867565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561095e57600080fd5b50610b8960048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156109e057848483905060a00201600580602002604051908101604052809291908260056020028082843782019150505050508152602001906001019061099b565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610a5f57848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610a1a565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080351515906020019092919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061188d565b005b348015610b9757600080fd5b50610ced60048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610c1957848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610bd4565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610c9857848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610c53565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061194d565b005b348015610cfb57600080fd5b50610dad6004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190803515159060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291905050506119c0565b6040518082815260200191505060405180910390f35b348015610dcf57600080fd5b50610e426004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c00190600680602002604051908101604052809291908260066020028082843782019150505050509192919290505050612160565b60405180826000191660001916815260200191505060405180910390f35b348015610e6c57600080fd5b50610e7561240b565b604051808261ffff1661ffff16815260200191505060405180910390f35b348015610e9f57600080fd5b50610ea8612411565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610ee8578082015181840152602081019050610ecd565b50505050905090810190601f168015610f155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600080600084801515610f3257fe5b86850991506000821415610f495760009250610f72565b610f68610f5983620f424061244a565b610f63888761244a565b61247d565b90506103e8811192505b50509392505050565b60026020528060005260406000206000915090505481565b60036020528060005260406000206000915090505481565b6000806000809150600090505b895181101561110057896000815181101515610fd057fe5b906020019060200201516003600581101515610fe857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff168a8281518110151561101157fe5b90602001906020020151600360058110151561102957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1614151561105057600080fd5b6110e4826110df8c8481518110151561106557fe5b906020019060200201518c8581518110151561107d57fe5b906020019060200201516110918d88612498565b8c8c888151811015156110a057fe5b906020019060200201518c898151811015156110b857fe5b906020019060200201518c8a8151811015156110d057fe5b906020019060200201516119c0565b6124b1565b9150878214156110f357611100565b8080600101915050610fb8565b8192505050979650505050505050565b600061111a612bd2565b6000806101606040519081016040528088600060058110151561113957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600160058110151561116857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600260058110151561119757fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860036005811015156111c657fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860046005811015156111f557fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200187600060068110151561122457fe5b6020020151815260200187600160068110151561123d57fe5b6020020151815260200187600260068110151561125657fe5b6020020151815260200187600360068110151561126f57fe5b6020020151815260200187600460068110151561128857fe5b6020020151815260200161129c8989612160565b6000191681525092503373ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff161415156112e357600080fd5b60008360a001511180156112fb575060008360c00151115b80156113075750600085115b151561131257600080fd5b8261012001514210151561136f57826101400151600019166000600381111561133757fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506115ee565b61138a8360c001516113858561014001516116ff565b612498565b915061139685836124cf565b905060008114156113f05782610140015160001916600160038111156113b857fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506115ee565b61141a600360008561014001516000191660001916815260200190815260200160002054826124b1565b60036000856101400151600019166000191681526020019081526020016000208190555082604001518360600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916836080015173ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff167f67d66f160bc93d925d05dae1794c90d2d6d6688b29b84ff069398a9b0458713186604001518760600151611552878a60c001518b60a00151611849565b878a6101400151604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182600019166000191681526020019550505050505060405180910390a48093505b5050509392505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b86518110156116d1576116c4878281518110151561163d57fe5b90602001906020020151878381518110151561165557fe5b90602001906020020151878481518110151561166d57fe5b90602001906020020151878581518110151561168557fe5b90602001906020020151878681518110151561169d57fe5b9060200190602002015187878151811015156116b557fe5b906020019060200201516116da565b8080600101915050611623565b50505050505050565b836116eb87878760008888886119c0565b1415156116f757600080fd5b505050505050565b600061174160026000846000191660001916815260200190815260200160002054600360008560001916600019168152602001908152602001600020546124b1565b9050919050565b600060018560405180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040518091039020858585604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af1158015611806573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614905095945050505050565b600061185e611858858461244a565b8461247d565b90509392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b87518110156119435761193588828151811015156118ad57fe5b9060200190602002015188838151811015156118c557fe5b9060200190602002015188848151811015156118dd57fe5b906020019060200201518888868151811015156118f657fe5b90602001906020020151888781518110151561190e57fe5b90602001906020020151888881518110151561192657fe5b906020019060200201516119c0565b508080600101915050611893565b5050505050505050565b60008090505b83518110156119ba576119ac848281518110151561196d57fe5b90602001906020020151848381518110151561198557fe5b90602001906020020151848481518110151561199d57fe5b90602001906020020151611110565b508080600101915050611953565b50505050565b60006119ca612bd2565b600080600080610160604051908101604052808e60006005811015156119ec57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6001600581101515611a1b57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6002600581101515611a4a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6003600581101515611a7957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6004600581101515611aa857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018d6000600681101515611ad757fe5b602002015181526020018d6001600681101515611af057fe5b602002015181526020018d6002600681101515611b0957fe5b602002015181526020018d6003600681101515611b2257fe5b602002015181526020018d6004600681101515611b3b57fe5b60200201518152602001611b4f8f8f612160565b600019168152509450600073ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161480611bc657503373ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff16145b1515611bd157600080fd5b60008560a00151118015611be9575060008560c00151115b8015611bf5575060008b115b1515611c0057600080fd5b611c1685600001518661014001518b8b8b611748565b1515611c2157600080fd5b84610120015142101515611c7e578461014001516000191660006003811115611c4657fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611c998560c00151611c948761014001516116ff565b612498565b9350611ca58b856124cf565b95506000861415611cff578461014001516000191660016003811115611cc757fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611d12868660c001518760a00151610f23565b15611d66578461014001516000191660026003811115611d2e57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b89158015611d7b5750611d7985876124e8565b155b15611dce5784610140015160001916600380811115611d9657fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611de1868660c001518760a00151611849565b9250611e0d600260008761014001516000191660001916815260200190815260200160002054876124b1565b600260008761014001516000191660001916815260200190815260200160002081905550611e45856040015186600001513386612838565b1515611e5057600080fd5b611e64856060015133876000015189612838565b1515611e6f57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16856080015173ffffffffffffffffffffffffffffffffffffffff16141515611f6e5760008560e001511115611f0c57611ec9868660c001518760e00151611849565b9150611f006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660000151876080015185612838565b1515611f0b57600080fd5b5b60008561010001511115611f6d57611f2e868660c00151876101000151611849565b9050611f616000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633876080015184612838565b1515611f6c57600080fd5b5b5b84604001518560600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916856080015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb33389604001518a60600151898d8a8a8f6101400151604051808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200184815260200183815260200182600019166000191681526020019850505050505050505060405180910390a48595505b5050505050979650505050505050565b60003083600060058110151561217257fe5b602002015184600160058110151561218657fe5b602002015185600260058110151561219a57fe5b60200201518660036005811015156121ae57fe5b60200201518760046005811015156121c257fe5b60200201518760006006811015156121d657fe5b60200201518860016006811015156121ea57fe5b60200201518960026006811015156121fe57fe5b60200201518a600360068110151561221257fe5b60200201518b600460068110151561222657fe5b60200201518c600560068110151561223a57fe5b6020020151604051808d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018481526020018381526020018281526020019c505050505050505050505050506040518091039020905092915050565b61138781565b6040805190810160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6000808284029050600084148061246b575082848281151561246857fe5b04145b151561247357fe5b8091505092915050565b600080828481151561248b57fe5b0490508091505092915050565b60008282111515156124a657fe5b818303905092915050565b60008082840190508381101515156124c557fe5b8091505092915050565b60008183106124de57816124e0565b825b905092915050565b600080600080600080600080600033975061250c8a8c60c001518d60a00151611849565b9650600073ffffffffffffffffffffffffffffffffffffffff168b6080015173ffffffffffffffffffffffffffffffffffffffff161415156127b9576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6040015173ffffffffffffffffffffffffffffffffffffffff161495506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6060015173ffffffffffffffffffffffffffffffffffffffff161494506126078a8c60c001518d60e00151611849565b935061261d8a8c60c001518d6101000151611849565b92508561262a5783612635565b61263487856124b1565b5b915084612642578261264d565b61264c8a846124b1565b5b90508161267f6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d600001516129ac565b10806126b85750816126b66000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d60000151612a94565b105b806126ec5750806126ea6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a6129ac565b105b8061272057508061271e6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a612a94565b105b1561272e576000985061282a565b8515801561276757508661274a8c604001518d600001516129ac565b10806127665750866127648c604001518d60000151612a94565b105b5b15612775576000985061282a565b841580156127a657508961278d8c606001518a6129ac565b10806127a55750896127a38c606001518a612a94565b105b5b156127b4576000985061282a565b612825565b866127cc8c604001518d600001516129ac565b10806127e85750866127e68c604001518d60000151612a94565b105b806127ff5750896127fd8c606001518a6129ac565b105b806128165750896128148c606001518a612a94565b105b15612824576000985061282a565b5b600198505b505050505050505092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166315dacbea868686866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050602060405180830381600087803b15801561296757600080fd5b505af115801561297b573d6000803e3d6000fd5b505050506040513d602081101561299157600080fd5b81019080805190602001909291905050509050949350505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a0823161138761ffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600088803b158015612a5057600080fd5b5087f1158015612a64573d6000803e3d6000fd5b50505050506040513d6020811015612a7b57600080fd5b8101908080519060200190929190505050905092915050565b60008273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e61138761ffff1684600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600088803b158015612b8e57600080fd5b5087f1158015612ba2573d6000803e3d6000fd5b50505050506040513d6020811015612bb957600080fd5b8101908080519060200190929190505050905092915050565b61016060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000801916815250905600a165627a7a72305820f91599ebd80f85632ef190bb5e1a738e7288d68a2cf9dcc6b579d76b892dcf6f0029'; + '608060405234801561001057600080fd5b50604051604080612d998339810180604052810190808051906020019092919080519060200190929190505050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050612cca806100cf6000396000f3006080604052600436106100fc576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806314df96ee14610101578063288cdc911461015a5780632ac126221461019f578063363349be146101e4578063394c21e7146103f85780633b30ba59146104975780634f150787146104ee578063741bcc931461071b5780637e9abb50146107cf5780638163681e1461081457806398024a8b146108a6578063add1cbc5146108fb578063b7b2c7d614610952578063baa0181d14610b8b578063bc61394a14610cef578063cfc4d0ec14610dc3578063f06bbf7514610e60578063ffa1ad7414610e93575b600080fd5b34801561010d57600080fd5b50610140600480360381019080803590602001909291908035906020019092919080359060200190929190505050610f23565b604051808215151515815260200191505060405180910390f35b34801561016657600080fd5b506101896004803603810190808035600019169060200190929190505050610f7b565b6040518082815260200191505060405180910390f35b3480156101ab57600080fd5b506101ce6004803603810190808035600019169060200190929190505050610f93565b6040518082815260200191505060405180910390f35b3480156101f057600080fd5b506103e260048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561027257848483905060a00201600580602002604051908101604052809291908260056020028082843782019150505050508152602001906001019061022d565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102f157848483905060c0020160068060200260405190810160405280929190826006602002808284378201915050505050815260200190600101906102ac565b5050505050919291929080359060200190929190803515159060200190929190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290505050610fab565b6040518082815260200191505060405180910390f35b34801561040457600080fd5b506104816004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190505050611110565b6040518082815260200191505060405180910390f35b3480156104a357600080fd5b506104ac6115f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156104fa57600080fd5b5061071960048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561057c57848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610537565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156105fb57848483905060c0020160068060200260405190810160405280929190826006602002808284378201915050505050815260200190600101906105b6565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061161d565b005b34801561072757600080fd5b506107cd6004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291905050506116da565b005b3480156107db57600080fd5b506107fe60048036038101908080356000191690602001909291905050506116ff565b6040518082815260200191505060405180910390f35b34801561082057600080fd5b5061088c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190505050611748565b604051808215151515815260200191505060405180910390f35b3480156108b257600080fd5b506108e5600480360381019080803590602001909291908035906020019092919080359060200190929190505050611849565b6040518082815260200191505060405180910390f35b34801561090757600080fd5b50610910611867565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561095e57600080fd5b50610b8960048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156109e057848483905060a00201600580602002604051908101604052809291908260056020028082843782019150505050508152602001906001019061099b565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610a5f57848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610a1a565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080351515906020019092919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061188d565b005b348015610b9757600080fd5b50610ced60048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610c1957848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610bd4565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610c9857848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610c53565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061194d565b005b348015610cfb57600080fd5b50610dad6004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190803515159060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291905050506119c0565b6040518082815260200191505060405180910390f35b348015610dcf57600080fd5b50610e426004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c00190600680602002604051908101604052809291908260066020028082843782019150505050509192919290505050612160565b60405180826000191660001916815260200191505060405180910390f35b348015610e6c57600080fd5b50610e7561240b565b604051808261ffff1661ffff16815260200191505060405180910390f35b348015610e9f57600080fd5b50610ea8612411565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610ee8578082015181840152602081019050610ecd565b50505050905090810190601f168015610f155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600080600084801515610f3257fe5b86850991506000821415610f495760009250610f72565b610f68610f5983620f424061244a565b610f63888761244a565b61247d565b90506103e8811192505b50509392505050565b60026020528060005260406000206000915090505481565b60036020528060005260406000206000915090505481565b6000806000809150600090505b895181101561110057896000815181101515610fd057fe5b906020019060200201516003600581101515610fe857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff168a8281518110151561101157fe5b90602001906020020151600360058110151561102957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1614151561105057600080fd5b6110e4826110df8c8481518110151561106557fe5b906020019060200201518c8581518110151561107d57fe5b906020019060200201516110918d88612498565b8c8c888151811015156110a057fe5b906020019060200201518c898151811015156110b857fe5b906020019060200201518c8a8151811015156110d057fe5b906020019060200201516119c0565b6124b1565b9150878214156110f357611100565b8080600101915050610fb8565b8192505050979650505050505050565b600061111a612bd2565b6000806101606040519081016040528088600060058110151561113957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600160058110151561116857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600260058110151561119757fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860036005811015156111c657fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860046005811015156111f557fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200187600060068110151561122457fe5b6020020151815260200187600160068110151561123d57fe5b6020020151815260200187600260068110151561125657fe5b6020020151815260200187600360068110151561126f57fe5b6020020151815260200187600460068110151561128857fe5b6020020151815260200161129c8989612160565b6000191681525092503373ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff161415156112e357600080fd5b60008360a001511180156112fb575060008360c00151115b80156113075750600085115b151561131257600080fd5b8261012001514210151561136f57826101400151600019166000600381111561133757fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506115ee565b61138a8360c001516113858561014001516116ff565b612498565b915061139685836124cf565b905060008114156113f05782610140015160001916600160038111156113b857fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506115ee565b61141a600360008561014001516000191660001916815260200190815260200160002054826124b1565b60036000856101400151600019166000191681526020019081526020016000208190555082604001518360600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916836080015173ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff167f67d66f160bc93d925d05dae1794c90d2d6d6688b29b84ff069398a9b0458713186604001518760600151611552878a60c001518b60a00151611849565b878a6101400151604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182600019166000191681526020019550505050505060405180910390a48093505b5050509392505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b86518110156116d1576116c4878281518110151561163d57fe5b90602001906020020151878381518110151561165557fe5b90602001906020020151878481518110151561166d57fe5b90602001906020020151878581518110151561168557fe5b90602001906020020151878681518110151561169d57fe5b9060200190602002015187878151811015156116b557fe5b906020019060200201516116da565b8080600101915050611623565b50505050505050565b836116eb87878760008888886119c0565b1415156116f757600080fd5b505050505050565b600061174160026000846000191660001916815260200190815260200160002054600360008560001916600019168152602001908152602001600020546124b1565b9050919050565b600060018560405180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040518091039020858585604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af1158015611806573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614905095945050505050565b600061185e611858858461244a565b8461247d565b90509392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b87518110156119435761193588828151811015156118ad57fe5b9060200190602002015188838151811015156118c557fe5b9060200190602002015188848151811015156118dd57fe5b906020019060200201518888868151811015156118f657fe5b90602001906020020151888781518110151561190e57fe5b90602001906020020151888881518110151561192657fe5b906020019060200201516119c0565b508080600101915050611893565b5050505050505050565b60008090505b83518110156119ba576119ac848281518110151561196d57fe5b90602001906020020151848381518110151561198557fe5b90602001906020020151848481518110151561199d57fe5b90602001906020020151611110565b508080600101915050611953565b50505050565b60006119ca612bd2565b600080600080610160604051908101604052808e60006005811015156119ec57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6001600581101515611a1b57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6002600581101515611a4a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6003600581101515611a7957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6004600581101515611aa857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018d6000600681101515611ad757fe5b602002015181526020018d6001600681101515611af057fe5b602002015181526020018d6002600681101515611b0957fe5b602002015181526020018d6003600681101515611b2257fe5b602002015181526020018d6004600681101515611b3b57fe5b60200201518152602001611b4f8f8f612160565b600019168152509450600073ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161480611bc657503373ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff16145b1515611bd157600080fd5b60008560a00151118015611be9575060008560c00151115b8015611bf5575060008b115b1515611c0057600080fd5b611c1685600001518661014001518b8b8b611748565b1515611c2157600080fd5b84610120015142101515611c7e578461014001516000191660006003811115611c4657fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611c998560c00151611c948761014001516116ff565b612498565b9350611ca58b856124cf565b95506000861415611cff578461014001516000191660016003811115611cc757fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611d12868660c001518760a00151610f23565b15611d66578461014001516000191660026003811115611d2e57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b89158015611d7b5750611d7985876124e8565b155b15611dce5784610140015160001916600380811115611d9657fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611de1868660c001518760a00151611849565b9250611e0d600260008761014001516000191660001916815260200190815260200160002054876124b1565b600260008761014001516000191660001916815260200190815260200160002081905550611e45856040015186600001513386612838565b1515611e5057600080fd5b611e64856060015133876000015189612838565b1515611e6f57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16856080015173ffffffffffffffffffffffffffffffffffffffff16141515611f6e5760008560e001511115611f0c57611ec9868660c001518760e00151611849565b9150611f006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660000151876080015185612838565b1515611f0b57600080fd5b5b60008561010001511115611f6d57611f2e868660c00151876101000151611849565b9050611f616000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633876080015184612838565b1515611f6c57600080fd5b5b5b84604001518560600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916856080015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb33389604001518a60600151898d8a8a8f6101400151604051808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200184815260200183815260200182600019166000191681526020019850505050505050505060405180910390a48595505b5050505050979650505050505050565b60003083600060058110151561217257fe5b602002015184600160058110151561218657fe5b602002015185600260058110151561219a57fe5b60200201518660036005811015156121ae57fe5b60200201518760046005811015156121c257fe5b60200201518760006006811015156121d657fe5b60200201518860016006811015156121ea57fe5b60200201518960026006811015156121fe57fe5b60200201518a600360068110151561221257fe5b60200201518b600460068110151561222657fe5b60200201518c600560068110151561223a57fe5b6020020151604051808d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018481526020018381526020018281526020019c505050505050505050505050506040518091039020905092915050565b61138781565b6040805190810160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6000808284029050600084148061246b575082848281151561246857fe5b04145b151561247357fe5b8091505092915050565b600080828481151561248b57fe5b0490508091505092915050565b60008282111515156124a657fe5b818303905092915050565b60008082840190508381101515156124c557fe5b8091505092915050565b60008183106124de57816124e0565b825b905092915050565b600080600080600080600080600033975061250c8a8c60c001518d60a00151611849565b9650600073ffffffffffffffffffffffffffffffffffffffff168b6080015173ffffffffffffffffffffffffffffffffffffffff161415156127b9576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6040015173ffffffffffffffffffffffffffffffffffffffff161495506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6060015173ffffffffffffffffffffffffffffffffffffffff161494506126078a8c60c001518d60e00151611849565b935061261d8a8c60c001518d6101000151611849565b92508561262a5783612635565b61263487856124b1565b5b915084612642578261264d565b61264c8a846124b1565b5b90508161267f6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d600001516129ac565b10806126b85750816126b66000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d60000151612a94565b105b806126ec5750806126ea6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a6129ac565b105b8061272057508061271e6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a612a94565b105b1561272e576000985061282a565b8515801561276757508661274a8c604001518d600001516129ac565b10806127665750866127648c604001518d60000151612a94565b105b5b15612775576000985061282a565b841580156127a657508961278d8c606001518a6129ac565b10806127a55750896127a38c606001518a612a94565b105b5b156127b4576000985061282a565b612825565b866127cc8c604001518d600001516129ac565b10806127e85750866127e68c604001518d60000151612a94565b105b806127ff5750896127fd8c606001518a6129ac565b105b806128165750896128148c606001518a612a94565b105b15612824576000985061282a565b5b600198505b505050505050505092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166315dacbea868686866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050602060405180830381600087803b15801561296757600080fd5b505af115801561297b573d6000803e3d6000fd5b505050506040513d602081101561299157600080fd5b81019080805190602001909291905050509050949350505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a0823161138761ffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600088803b158015612a5057600080fd5b5087f1158015612a64573d6000803e3d6000fd5b50505050506040513d6020811015612a7b57600080fd5b8101908080519060200190929190505050905092915050565b60008273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e61138761ffff1684600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600088803b158015612b8e57600080fd5b5087f1158015612ba2573d6000803e3d6000fd5b50505050506040513d6020811015612bb957600080fd5b8101908080519060200190929190505050905092915050565b61016060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000801916815250905600a165627a7a72305820f91599ebd80f85632ef190bb5e1a738e7288d68a2cf9dcc6b579d76b892dcf6f0029'; diff --git a/packages/deployer/test/util/constants.ts b/packages/deployer/test/util/constants.ts index b93081a80..88d6db550 100644 --- a/packages/deployer/test/util/constants.ts +++ b/packages/deployer/test/util/constants.ts @@ -7,5 +7,5 @@ export const constants = { timeoutMs: 30000, zrxTokenAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498', tokenTransferProxyAddress: '0x8da0d80f5007ef1e431dd2127178d224e32c2ef4', - specifiedContracts: '*', + contracts: '*' as '*', }; diff --git a/packages/metacoin/compiler.json b/packages/metacoin/compiler.json new file mode 100644 index 000000000..f5817e0c8 --- /dev/null +++ b/packages/metacoin/compiler.json @@ -0,0 +1,15 @@ +{ + "compilerSettings": { + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + } + } +} diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json index 1ab749017..17aad0aaf 100644 --- a/packages/metacoin/package.json +++ b/packages/metacoin/package.json @@ -12,13 +12,13 @@ "build": "tsc", "test": "run-s build run_mocha", "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", - "run_mocha": "mocha lib/test/**/*.js --bail --exit", + "run_mocha": "mocha lib/test/**/*_test.js lib/test/global_hooks.js --bail --exit", "generate_contract_wrappers": "node ../abi-gen/lib/index.js --abis 'artifacts/Metacoin.json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers --backend ethers && prettier --write 'src/contract_wrappers/**.ts'", "coverage:report:text": "istanbul report text", "coverage:report:html": "istanbul report html && open coverage/index.html", "coverage:report:lcov": "istanbul report lcov", "test:circleci": "yarn test:coverage", - "compile": "node ../deployer/lib/src/cli.js compile --contracts Metacoin --contracts-dir contracts --artifacts-dir artifacts" + "compile": "node ../deployer/lib/src/cli.js compile" }, "author": "", "license": "Apache-2.0", diff --git a/packages/sol-cov/src/collect_contract_data.ts b/packages/sol-cov/src/collect_contract_data.ts index 1d8bc7178..3d8a45cec 100644 --- a/packages/sol-cov/src/collect_contract_data.ts +++ b/packages/sol-cov/src/collect_contract_data.ts @@ -8,25 +8,22 @@ import { ContractData } from './types'; export const collectContractsData = (artifactsPath: string, sourcesPath: string, networkId: number) => { const artifactsGlob = `${artifactsPath}/**/*.json`; const artifactFileNames = glob.sync(artifactsGlob, { absolute: true }); - const contractsDataIfExists: Array = _.map(artifactFileNames, artifactFileName => { + const contractsData: ContractData[] = []; + _.forEach(artifactFileNames, artifactFileName => { const artifact = JSON.parse(fs.readFileSync(artifactFileName).toString()); - const sources = artifact.networks[networkId].sources; - const contractName = artifact.contract_name; + const sources = _.keys(artifact.sources); + const contractName = artifact.contractName; // We don't compute coverage for dependencies const sourceCodes = _.map(sources, (source: string) => fs.readFileSync(source).toString()); - if (_.isUndefined(artifact.networks[networkId])) { - throw new Error(`No ${contractName} artifacts found for networkId ${networkId}`); - } const contractData = { sourceCodes, sources, - sourceMap: artifact.networks[networkId].source_map, - sourceMapRuntime: artifact.networks[networkId].source_map_runtime, - runtimeBytecode: artifact.networks[networkId].runtime_bytecode, - bytecode: artifact.networks[networkId].bytecode, + bytecode: artifact.compilerOutput.evm.bytecode.object, + sourceMap: artifact.compilerOutput.evm.bytecode.sourceMap, + runtimeBytecode: artifact.compilerOutput.evm.deployedBytecode.object, + sourceMapRuntime: artifact.compilerOutput.evm.deployedBytecode.sourceMap, }; - return contractData; + contractsData.push(contractData); }); - const contractsData = _.filter(contractsDataIfExists, contractData => !_.isEmpty(contractData)) as ContractData[]; return contractsData; }; diff --git a/packages/sol-cov/src/coverage_manager.ts b/packages/sol-cov/src/coverage_manager.ts index 230ccc3c9..509c1cb99 100644 --- a/packages/sol-cov/src/coverage_manager.ts +++ b/packages/sol-cov/src/coverage_manager.ts @@ -130,7 +130,10 @@ export class CoverageManager { for (const traceInfo of this._traceInfos) { if (traceInfo.address !== constants.NEW_CONTRACT) { // Runtime transaction - const runtimeBytecode = (traceInfo as TraceInfoExistingContract).runtimeBytecode; + let runtimeBytecode = (traceInfo as TraceInfoExistingContract).runtimeBytecode; + if (runtimeBytecode.startsWith('0x')) { + runtimeBytecode = runtimeBytecode.slice(2); + } const contractData = _.find(this._contractsData, { runtimeBytecode }) as ContractData; if (_.isUndefined(contractData)) { throw new Error(`Transaction to an unknown address: ${traceInfo.address}`); @@ -154,7 +157,10 @@ export class CoverageManager { } } else { // Contract creation transaction - const bytecode = (traceInfo as TraceInfoNewContract).bytecode; + let bytecode = (traceInfo as TraceInfoNewContract).bytecode; + if (bytecode.startsWith('0x')) { + bytecode = bytecode.slice(2); + } const contractData = _.find(this._contractsData, contractDataCandidate => bytecode.startsWith(contractDataCandidate.bytecode), ) as ContractData; diff --git a/packages/sol-resolver/src/index.ts b/packages/sol-resolver/src/index.ts index cd6ec42ec..a86053259 100644 --- a/packages/sol-resolver/src/index.ts +++ b/packages/sol-resolver/src/index.ts @@ -3,6 +3,7 @@ export { FallthroughResolver } from './resolvers/fallthrough_resolver'; export { URLResolver } from './resolvers/url_resolver'; export { NPMResolver } from './resolvers/npm_resolver'; export { FSResolver } from './resolvers/fs_resolver'; +export { RelativeFSResolver } from './resolvers/relative_fs_resolver'; export { NameResolver } from './resolvers/name_resolver'; export { EnumerableResolver } from './resolvers/enumerable_resolver'; export { Resolver } from './resolvers/resolver'; diff --git a/packages/sol-resolver/src/resolvers/name_resolver.ts b/packages/sol-resolver/src/resolvers/name_resolver.ts index 6849b7610..a0bedab98 100644 --- a/packages/sol-resolver/src/resolvers/name_resolver.ts +++ b/packages/sol-resolver/src/resolvers/name_resolver.ts @@ -18,7 +18,7 @@ export class NameResolver extends EnumerableResolver { const onFile = (filePath: string) => { const contractName = path.basename(filePath, SOLIDITY_FILE_EXTENSION); if (contractName === lookupContractName) { - const source = fs.readFileSync(filePath).toString(); + const source = fs.readFileSync(path.join(this._contractsDir, filePath)).toString(); contractSource = { source, path: filePath, @@ -35,7 +35,7 @@ export class NameResolver extends EnumerableResolver { const contractSources: ContractSource[] = []; const onFile = (filePath: string) => { const contractName = path.basename(filePath, SOLIDITY_FILE_EXTENSION); - const source = fs.readFileSync(filePath).toString(); + const source = fs.readFileSync(path.join(this._contractsDir, filePath)).toString(); const contractSource = { source, path: filePath, @@ -54,9 +54,10 @@ export class NameResolver extends EnumerableResolver { throw new Error(`No directory found at ${dirPath}`); } for (const fileName of dirContents) { - const entryPath = path.join(dirPath, fileName); - const isDirectory = fs.lstatSync(entryPath).isDirectory(); - const isComplete = isDirectory ? this._traverseContractsDir(entryPath, onFile) : onFile(entryPath); + const absoluteEntryPath = path.join(dirPath, fileName); + const isDirectory = fs.lstatSync(absoluteEntryPath).isDirectory(); + const entryPath = path.relative(this._contractsDir, absoluteEntryPath); + const isComplete = isDirectory ? this._traverseContractsDir(absoluteEntryPath, onFile) : onFile(entryPath); if (isComplete) { return isComplete; } diff --git a/packages/sol-resolver/src/resolvers/relative_fs_resolver.ts b/packages/sol-resolver/src/resolvers/relative_fs_resolver.ts new file mode 100644 index 000000000..2317ede83 --- /dev/null +++ b/packages/sol-resolver/src/resolvers/relative_fs_resolver.ts @@ -0,0 +1,26 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +import { ContractSource } from '../types'; + +import { Resolver } from './resolver'; + +export class RelativeFSResolver extends Resolver { + private _contractsDir: string; + constructor(contractsDir: string) { + super(); + this._contractsDir = contractsDir; + } + // tslint:disable-next-line:prefer-function-over-method + public resolveIfExists(importPath: string): ContractSource | undefined { + const filePath = path.join(this._contractsDir, importPath); + if (fs.existsSync(filePath)) { + const fileContent = fs.readFileSync(filePath).toString(); + return { + source: fileContent, + path: importPath, + }; + } + return undefined; + } +} diff --git a/packages/typescript-typings/types/solc/index.d.ts b/packages/typescript-typings/types/solc/index.d.ts index b20f9b2ff..5a87ac267 100644 --- a/packages/typescript-typings/types/solc/index.d.ts +++ b/packages/typescript-typings/types/solc/index.d.ts @@ -59,32 +59,33 @@ declare module 'solc' { | 'evm.gasEstimates' | 'ewasm.wast' | 'ewasm.wasm'; + export interface CompilerSettings { + remappings?: string[]; + optimizer?: { + enabled: boolean; + runs?: number; + }; + evmVersion?: 'homestead' | 'tangerineWhistle' | 'spuriousDragon' | 'byzantium' | 'constantinople'; + metadata?: { + useLiteralContent: true; + }; + libraries?: { + [fileName: string]: { + [libName: string]: string; + }; + }; + outputSelection: { + [fileName: string]: { + [contractName: string]: OutputField[]; + }; + }; + } export interface StandardInput { language: 'Solidity' | 'serpent' | 'lll' | 'assembly'; sources: { [fileName: string]: Source; }; - settings: { - remappings?: string[]; - optimizer?: { - enabled: boolean; - runs?: number; - }; - evmVersion?: 'homestead' | 'tangerineWhistle' | 'spuriousDragon' | 'byzantium' | 'constantinople'; - metadata?: { - useLiteralContent: true; - }; - libraries?: { - [fileName: string]: { - [libName: string]: string; - }; - }; - outputSelection: { - [fileName: string]: { - [contractName: string]: OutputField[]; - }; - }; - }; + settings: CompilerSettings; } export type ErrorType = | 'JSONError' @@ -114,6 +115,19 @@ declare module 'solc' { formattedMessage?: string; } import { ContractAbi } from '@0xproject/types'; + export interface StandardContractOutput { + abi: ContractAbi; + evm: { + bytecode: { + object: string; + sourceMap: string; + }; + deployedBytecode: { + object: string; + sourceMap: string; + }; + }; + } export interface StandardOutput { errors: Error[]; sources: { @@ -125,19 +139,7 @@ declare module 'solc' { }; contracts: { [fileName: string]: { - [contractName: string]: { - abi: ContractAbi; - evm: { - bytecode: { - object: string; - sourceMap: string; - }; - deployedBytecode: { - object: string; - sourceMap: string; - }; - }; - }; + [contractName: string]: StandardContractOutput; }; }; } -- cgit v1.2.3 From c9b8f2a397606f3667e5829b5a0364f9896daec5 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 10:52:28 +0200 Subject: Fix sol-cov to work with the new artifacts format --- packages/sol-cov/src/collect_contract_data.ts | 4 ++- packages/sol-cov/src/coverage_manager.ts | 51 ++++++++++++++------------- 2 files changed, 30 insertions(+), 25 deletions(-) (limited to 'packages') diff --git a/packages/sol-cov/src/collect_contract_data.ts b/packages/sol-cov/src/collect_contract_data.ts index 3d8a45cec..bb20e98be 100644 --- a/packages/sol-cov/src/collect_contract_data.ts +++ b/packages/sol-cov/src/collect_contract_data.ts @@ -14,7 +14,9 @@ export const collectContractsData = (artifactsPath: string, sourcesPath: string, const sources = _.keys(artifact.sources); const contractName = artifact.contractName; // We don't compute coverage for dependencies - const sourceCodes = _.map(sources, (source: string) => fs.readFileSync(source).toString()); + const sourceCodes = _.map(sources, (source: string) => + fs.readFileSync(path.join(sourcesPath, source)).toString(), + ); const contractData = { sourceCodes, sources, diff --git a/packages/sol-cov/src/coverage_manager.ts b/packages/sol-cov/src/coverage_manager.ts index 509c1cb99..e932ac081 100644 --- a/packages/sol-cov/src/coverage_manager.ts +++ b/packages/sol-cov/src/coverage_manager.ts @@ -29,10 +29,31 @@ import { import { utils } from './utils'; export class CoverageManager { + private _sourcesPath: string; private _traceInfos: TraceInfo[] = []; private _contractsData: ContractData[] = []; private _getContractCodeAsync: (address: string) => Promise; - private static _getSingleFileCoverageForTrace( + constructor( + artifactsPath: string, + sourcesPath: string, + networkId: number, + getContractCodeAsync: (address: string) => Promise, + ) { + this._getContractCodeAsync = getContractCodeAsync; + this._sourcesPath = sourcesPath; + this._contractsData = collectContractsData(artifactsPath, this._sourcesPath, networkId); + } + public appendTraceInfo(traceInfo: TraceInfo): void { + this._traceInfos.push(traceInfo); + } + public async writeCoverageAsync(): Promise { + const finalCoverage = await this._computeCoverageAsync(); + const jsonReplacer: null = null; + const numberOfJsonSpaces = 4; + const stringifiedCoverage = JSON.stringify(finalCoverage, jsonReplacer, numberOfJsonSpaces); + fs.writeFileSync('coverage/coverage.json', stringifiedCoverage); + } + private _getSingleFileCoverageForTrace( contractData: ContractData, coveredPcs: number[], pcToSourceRange: { [programCounter: number]: SourceRange }, @@ -94,11 +115,12 @@ export class CoverageManager { ); statementCoverage[modifierStatementId] = isModifierCovered; } + const absoluteFileName = path.join(this._sourcesPath, fileName); const partialCoverage = { - [contractData.sources[fileIndex]]: { + [absoluteFileName]: { ...coverageEntriesDescription, l: {}, // It's able to derive it from statement coverage - path: fileName, + path: absoluteFileName, f: functionCoverage, s: statementCoverage, b: branchCoverage, @@ -106,25 +128,6 @@ export class CoverageManager { }; return partialCoverage; } - constructor( - artifactsPath: string, - sourcesPath: string, - networkId: number, - getContractCodeAsync: (address: string) => Promise, - ) { - this._getContractCodeAsync = getContractCodeAsync; - this._contractsData = collectContractsData(artifactsPath, sourcesPath, networkId); - } - public appendTraceInfo(traceInfo: TraceInfo): void { - this._traceInfos.push(traceInfo); - } - public async writeCoverageAsync(): Promise { - const finalCoverage = await this._computeCoverageAsync(); - const jsonReplacer: null = null; - const numberOfJsonSpaces = 4; - const stringifiedCoverage = JSON.stringify(finalCoverage, jsonReplacer, numberOfJsonSpaces); - fs.writeFileSync('coverage/coverage.json', stringifiedCoverage); - } private async _computeCoverageAsync(): Promise { const collector = new Collector(); for (const traceInfo of this._traceInfos) { @@ -147,7 +150,7 @@ export class CoverageManager { contractData.sources, ); for (let fileIndex = 0; fileIndex < contractData.sources.length; fileIndex++) { - const singleFileCoverageForTrace = CoverageManager._getSingleFileCoverageForTrace( + const singleFileCoverageForTrace = this._getSingleFileCoverageForTrace( contractData, traceInfo.coveredPcs, pcToSourceRange, @@ -176,7 +179,7 @@ export class CoverageManager { contractData.sources, ); for (let fileIndex = 0; fileIndex < contractData.sources.length; fileIndex++) { - const singleFileCoverageForTrace = CoverageManager._getSingleFileCoverageForTrace( + const singleFileCoverageForTrace = this._getSingleFileCoverageForTrace( contractData, traceInfo.coveredPcs, pcToSourceRange, -- cgit v1.2.3 From 27262c4e5690e79ac19976012c0b82e86644dbdc Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 13:31:08 +0200 Subject: Move artifacts from src/artifacts to artifacts/v1 --- packages/0x.js/package.json | 2 +- packages/contracts/compiler.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index d3cf9ad5f..a23e01938 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -21,7 +21,7 @@ "test": "run-s clean test:commonjs", "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov", "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", - "update_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/src/artifacts/$i.json test/artifacts; done;", + "update_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/artifacts/1.0.0/$i.json test/artifacts; done;", "clean": "shx rm -rf _bundles lib test_temp scripts", "build:umd:prod": "NODE_ENV=production webpack", "build:commonjs": "tsc && yarn update_artifacts && copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts", diff --git a/packages/contracts/compiler.json b/packages/contracts/compiler.json index 06a9829d5..493d6373d 100644 --- a/packages/contracts/compiler.json +++ b/packages/contracts/compiler.json @@ -1,5 +1,5 @@ { - "artifactsDir": "../migrations/src/artifacts", + "artifactsDir": "../migrations/artifacts/1.0.0", "contractsDir": "src/contracts", "compilerSettings": { "outputSelection": { -- cgit v1.2.3 From 0f1589a43f610a79f46fa4c3412670b546b032af Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 13:37:21 +0200 Subject: Define a separator const --- packages/deployer/src/cli.ts | 7 ++++--- packages/deployer/src/compiler.ts | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'packages') diff --git a/packages/deployer/src/cli.ts b/packages/deployer/src/cli.ts index b06168e31..5df9f9963 100644 --- a/packages/deployer/src/cli.ts +++ b/packages/deployer/src/cli.ts @@ -19,6 +19,7 @@ const DEFAULT_NETWORK_ID = 50; const DEFAULT_JSONRPC_URL = 'http://localhost:8545'; const DEFAULT_GAS_PRICE = (10 ** 9 * 2).toString(); const DEFAULT_CONTRACTS_LIST = '*'; +const SEPARATOR = ','; /** * Compiles all contracts with options passed in through CLI. @@ -28,7 +29,7 @@ async function onCompileCommandAsync(argv: CliOptions): Promise { const opts: CompilerOptions = { contractsDir: argv.contractsDir, artifactsDir: argv.artifactsDir, - contracts: argv.contracts === '*' ? argv.contracts : argv.contracts.split(','), + contracts: argv.contracts === DEFAULT_CONTRACTS_LIST ? DEFAULT_CONTRACTS_LIST : argv.contracts.split(SEPARATOR), }; await commands.compileAsync(opts); } @@ -44,7 +45,7 @@ async function onDeployCommandAsync(argv: CliOptions): Promise { const compilerOpts: CompilerOptions = { contractsDir: argv.contractsDir, artifactsDir: argv.artifactsDir, - contracts: argv.contracts === '*' ? argv.contracts : argv.contracts.split(','), + contracts: argv.contracts === DEFAULT_CONTRACTS_LIST ? DEFAULT_CONTRACTS_LIST : argv.contracts.split(SEPARATOR), }; await commands.compileAsync(compilerOpts); @@ -59,7 +60,7 @@ async function onDeployCommandAsync(argv: CliOptions): Promise { defaults, }; const deployerArgsString = argv.args as string; - const deployerArgs = deployerArgsString.split(','); + const deployerArgs = deployerArgsString.split(SEPARATOR); await commands.deployAsync(argv.contract as string, deployerArgs, deployerOpts); } /** diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index 673bc3186..85449ac8d 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -53,7 +53,7 @@ const DEFAULT_COMPILER_SETTINGS: solc.CompilerSettings = { }, outputSelection: { '*': { - '*': ['abi', 'evm.bytecode.object'], + [ALL_CONTRACTS_IDENTIFIER]: ['abi', 'evm.bytecode.object'], }, }, }; -- cgit v1.2.3 From 95df4433dc31cfb59d2a75c18f05af92d7677db9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 13:40:05 +0200 Subject: Fix a typo --- packages/deployer/src/cli.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/deployer/src/cli.ts b/packages/deployer/src/cli.ts index 5df9f9963..87a8a6c65 100644 --- a/packages/deployer/src/cli.ts +++ b/packages/deployer/src/cli.ts @@ -76,7 +76,7 @@ function deployCommandBuilder(yargsInstance: any) { }) .option('contract', { type: 'string', - description: 'name of contract to deploy, exluding .sol extension', + description: 'name of contract to deploy, excluding .sol extension', }) .option('args', { type: 'string', -- cgit v1.2.3 From 3d51bc1ada697e4b4fdac83bc61b2a4459d59469 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 13:40:53 +0200 Subject: Rename args to constructor-args --- packages/deployer/src/cli.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/deployer/src/cli.ts b/packages/deployer/src/cli.ts index 87a8a6c65..9c029a225 100644 --- a/packages/deployer/src/cli.ts +++ b/packages/deployer/src/cli.ts @@ -59,7 +59,7 @@ async function onDeployCommandAsync(argv: CliOptions): Promise { networkId, defaults, }; - const deployerArgsString = argv.args as string; + const deployerArgsString = argv.constructorArgs as string; const deployerArgs = deployerArgsString.split(SEPARATOR); await commands.deployAsync(argv.contract as string, deployerArgs, deployerOpts); } @@ -78,7 +78,7 @@ function deployCommandBuilder(yargsInstance: any) { type: 'string', description: 'name of contract to deploy, excluding .sol extension', }) - .option('args', { + .option('constructor-args', { type: 'string', description: 'comma separated list of constructor args to deploy contract with', }) -- cgit v1.2.3 From 02147f546e60ab16e0573cd73e524840f924d4de Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 13:41:50 +0200 Subject: Fix comments --- packages/deployer/src/cli.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/deployer/src/cli.ts b/packages/deployer/src/cli.ts index 9c029a225..8c89cf382 100644 --- a/packages/deployer/src/cli.ts +++ b/packages/deployer/src/cli.ts @@ -64,7 +64,7 @@ async function onDeployCommandAsync(argv: CliOptions): Promise { await commands.deployAsync(argv.contract as string, deployerArgs, deployerOpts); } /** - * Provides extra required options for deploy command. + * Adds additional required options for when the user is calling the deploy command. * @param yargsInstance yargs instance provided in builder function callback. */ function deployCommandBuilder(yargsInstance: any) { @@ -101,7 +101,7 @@ function deployCommandBuilder(yargsInstance: any) { } /** - * Provides extra required options for compile command. + * Adds additional required options for when the user is calling the compile command. * @param yargsInstance yargs instance provided in builder function callback. */ function compileCommandBuilder(yargsInstance: any) { -- cgit v1.2.3 From 7c1e05d33c2fd5d026ce69ac96d0b2096b1a9cdb Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 13:42:47 +0200 Subject: Add a comment --- packages/deployer/src/compiler.ts | 3 +++ 1 file changed, 3 insertions(+) (limited to 'packages') diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index 85449ac8d..4d2058880 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -47,6 +47,9 @@ const ALL_CONTRACTS_IDENTIFIER = '*'; const SOLC_BIN_DIR = path.join(__dirname, '..', '..', 'solc_bin'); const DEFAULT_CONTRACTS_DIR = path.resolve('contracts'); const DEFAULT_ARTIFACTS_DIR = path.resolve('artifacts'); +// Solc compiler settings cannot be configured from the commandline. +// If you need this configured, please create a `compiler.json` config file +// with your desired configurations. const DEFAULT_COMPILER_SETTINGS: solc.CompilerSettings = { optimizer: { enabled: false, -- cgit v1.2.3 From fad7dc9f04f39e754ac0ec437736c7bee33fa28e Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 13:46:44 +0200 Subject: Use named constants --- packages/deployer/src/compiler.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index 4d2058880..db06ccf43 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -43,7 +43,9 @@ import { } from './utils/types'; import { utils } from './utils/utils'; +type TYPE_ALL_FILES_IDENTIFIER = '*'; const ALL_CONTRACTS_IDENTIFIER = '*'; +const ALL_FILES_IDENTIFIER = '*'; const SOLC_BIN_DIR = path.join(__dirname, '..', '..', 'solc_bin'); const DEFAULT_CONTRACTS_DIR = path.resolve('contracts'); const DEFAULT_ARTIFACTS_DIR = path.resolve('artifacts'); @@ -55,7 +57,7 @@ const DEFAULT_COMPILER_SETTINGS: solc.CompilerSettings = { enabled: false, }, outputSelection: { - '*': { + [ALL_FILES_IDENTIFIER]: { [ALL_CONTRACTS_IDENTIFIER]: ['abi', 'evm.bytecode.object'], }, }, @@ -72,19 +74,20 @@ export class Compiler { private _contractsDir: string; private _compilerSettings: solc.CompilerSettings; private _artifactsDir: string; - private _specifiedContracts: string[] | '*'; + private _specifiedContracts: string[] | TYPE_ALL_FILES_IDENTIFIER; /** * Instantiates a new instance of the Compiler class. * @return An instance of the Compiler class. */ constructor(opts: CompilerOptions) { + // TODO: Look for config file in parent directories if not found in current directory const config: CompilerOptions = fs.existsSync(CONFIG_FILE) ? JSON.parse(fs.readFileSync(CONFIG_FILE).toString()) : {}; this._contractsDir = opts.contractsDir || config.contractsDir || DEFAULT_CONTRACTS_DIR; this._compilerSettings = opts.compilerSettings || config.compilerSettings || DEFAULT_COMPILER_SETTINGS; this._artifactsDir = opts.artifactsDir || config.artifactsDir || DEFAULT_ARTIFACTS_DIR; - this._specifiedContracts = opts.contracts || config.contracts || '*'; + this._specifiedContracts = opts.contracts || config.contracts || ALL_CONTRACTS_IDENTIFIER; this._nameResolver = new NameResolver(path.resolve(this._contractsDir)); const resolver = new FallthroughResolver(); resolver.appendResolver(new URLResolver()); -- cgit v1.2.3 From fcb0a05880f6217f5b5942ec419fcf4df490551d Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 13:49:21 +0200 Subject: Improve the readability of the check for should compile --- packages/deployer/src/compiler.ts | 10 +++++----- packages/deployer/src/utils/constants.ts | 1 + packages/deployer/src/utils/types.ts | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'packages') diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts index db06ccf43..e81df3c0a 100644 --- a/packages/deployer/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -131,10 +131,10 @@ export class Compiler { shouldCompile = true; } else { const currentArtifact = currentArtifactIfExists as ContractArtifact; - shouldCompile = - currentArtifact.schemaVersion !== '2.0.0' || - !_.isEqual(currentArtifact.compiler.settings, this._compilerSettings) || - currentArtifact.sourceTreeHashHex !== sourceTreeHashHex; + const isUserOnLatestVersion = currentArtifact.schemaVersion === constants.LATEST_ARTIFACT_VERSION; + const didCompilerSettingsChange = !_.isEqual(currentArtifact.compiler.settings, this._compilerSettings); + const didSourceChange = currentArtifact.sourceTreeHashHex !== sourceTreeHashHex; + shouldCompile = isUserOnLatestVersion || didCompilerSettingsChange || didSourceChange; } if (!shouldCompile) { return; @@ -228,7 +228,7 @@ export class Compiler { }; } else { newArtifact = { - schemaVersion: '2.0.0', + schemaVersion: constants.LATEST_ARTIFACT_VERSION, contractName, ...contractVersion, networks: {}, diff --git a/packages/deployer/src/utils/constants.ts b/packages/deployer/src/utils/constants.ts index 6f9dfb994..df2ddb3b2 100644 --- a/packages/deployer/src/utils/constants.ts +++ b/packages/deployer/src/utils/constants.ts @@ -1,4 +1,5 @@ export const constants = { SOLIDITY_FILE_EXTENSION: '.sol', BASE_COMPILER_URL: 'https://ethereum.github.io/solc-bin/bin/', + LATEST_ARTIFACT_VERSION: '2.0.0', }; diff --git a/packages/deployer/src/utils/types.ts b/packages/deployer/src/utils/types.ts index c4af5ac87..19c27df67 100644 --- a/packages/deployer/src/utils/types.ts +++ b/packages/deployer/src/utils/types.ts @@ -11,7 +11,7 @@ export enum AbiType { } export interface ContractArtifact extends ContractVersionData { - schemaVersion: '2.0.0'; + schemaVersion: string; contractName: string; networks: ContractNetworks; } -- cgit v1.2.3 From 2d30183d658c9d178544e1c14fb779306e5d2778 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 13:57:03 +0200 Subject: CHeck if ABI exists --- packages/deployer/src/deployer.ts | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'packages') diff --git a/packages/deployer/src/deployer.ts b/packages/deployer/src/deployer.ts index fe959e405..c8c3a9a06 100644 --- a/packages/deployer/src/deployer.ts +++ b/packages/deployer/src/deployer.ts @@ -82,6 +82,9 @@ export class Deployer { data, gas, }; + if (_.isUndefined(compilerOutput.abi)) { + throw new Error(`ABI not found in ${contractName} artifacts`); + } const abi = compilerOutput.abi; const constructorAbi = _.find(abi, { type: AbiType.Constructor }) as ConstructorAbi; const constructorArgs = _.isUndefined(constructorAbi) ? [] : constructorAbi.inputs; @@ -151,6 +154,9 @@ export class Deployer { ): Promise { const contractArtifactIfExists: ContractArtifact = this._loadContractArtifactIfExists(contractName); const compilerOutput = Deployer._getContractCompilerOutputFromArtifactIfExists(contractArtifactIfExists); + if (_.isUndefined(compilerOutput.abi)) { + throw new Error(`ABI not found in ${contractName} artifacts`); + } const abi = compilerOutput.abi; const encodedConstructorArgs = encoder.encodeConstructorArgsFromAbi(args, abi); const newContractData: ContractNetworkData = { -- cgit v1.2.3 From 9e67e12732a0fc87f0000917e6bbf21c3c2db260 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 14:04:58 +0200 Subject: Add removeHexPrefix util method --- packages/sol-cov/src/coverage_manager.ts | 8 ++------ packages/sol-cov/src/utils.ts | 4 ++++ 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'packages') diff --git a/packages/sol-cov/src/coverage_manager.ts b/packages/sol-cov/src/coverage_manager.ts index e932ac081..6a57d07c9 100644 --- a/packages/sol-cov/src/coverage_manager.ts +++ b/packages/sol-cov/src/coverage_manager.ts @@ -134,9 +134,7 @@ export class CoverageManager { if (traceInfo.address !== constants.NEW_CONTRACT) { // Runtime transaction let runtimeBytecode = (traceInfo as TraceInfoExistingContract).runtimeBytecode; - if (runtimeBytecode.startsWith('0x')) { - runtimeBytecode = runtimeBytecode.slice(2); - } + runtimeBytecode = utils.removeHexPrefix(runtimeBytecode); const contractData = _.find(this._contractsData, { runtimeBytecode }) as ContractData; if (_.isUndefined(contractData)) { throw new Error(`Transaction to an unknown address: ${traceInfo.address}`); @@ -161,9 +159,7 @@ export class CoverageManager { } else { // Contract creation transaction let bytecode = (traceInfo as TraceInfoNewContract).bytecode; - if (bytecode.startsWith('0x')) { - bytecode = bytecode.slice(2); - } + bytecode = utils.removeHexPrefix(bytecode); const contractData = _.find(this._contractsData, contractDataCandidate => bytecode.startsWith(contractDataCandidate.bytecode), ) as ContractData; diff --git a/packages/sol-cov/src/utils.ts b/packages/sol-cov/src/utils.ts index f155043a1..d970c42ee 100644 --- a/packages/sol-cov/src/utils.ts +++ b/packages/sol-cov/src/utils.ts @@ -4,6 +4,10 @@ export const utils = { compareLineColumn(lhs: LineColumn, rhs: LineColumn): number { return lhs.line !== rhs.line ? lhs.line - rhs.line : lhs.column - rhs.column; }, + removeHexPrefix(hex: string): string { + const hexPrefix = '0x'; + return hex.startsWith(hexPrefix) ? hex.slice(hexPrefix.length) : hex; + }, isRangeInside(childRange: SingleFileSourceRange, parentRange: SingleFileSourceRange): boolean { return ( utils.compareLineColumn(parentRange.start, childRange.start) <= 0 && -- cgit v1.2.3 From 8eabc49e9d17925d5cce92cf9e1b3d65ba875f2d Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 14:06:00 +0200 Subject: Introduce a var --- packages/sol-resolver/src/resolvers/name_resolver.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/sol-resolver/src/resolvers/name_resolver.ts b/packages/sol-resolver/src/resolvers/name_resolver.ts index a0bedab98..76bed802e 100644 --- a/packages/sol-resolver/src/resolvers/name_resolver.ts +++ b/packages/sol-resolver/src/resolvers/name_resolver.ts @@ -18,7 +18,8 @@ export class NameResolver extends EnumerableResolver { const onFile = (filePath: string) => { const contractName = path.basename(filePath, SOLIDITY_FILE_EXTENSION); if (contractName === lookupContractName) { - const source = fs.readFileSync(path.join(this._contractsDir, filePath)).toString(); + const absoluteContractPath = path.join(this._contractsDir, filePath); + const source = fs.readFileSync(absoluteContractPath).toString(); contractSource = { source, path: filePath, @@ -35,7 +36,8 @@ export class NameResolver extends EnumerableResolver { const contractSources: ContractSource[] = []; const onFile = (filePath: string) => { const contractName = path.basename(filePath, SOLIDITY_FILE_EXTENSION); - const source = fs.readFileSync(path.join(this._contractsDir, filePath)).toString(); + const absoluteContractPath = path.join(this._contractsDir, filePath); + const source = fs.readFileSync(absoluteContractPath).toString(); const contractSource = { source, path: filePath, -- cgit v1.2.3 From b699a61f563b6dbffa8c7f05802be9314d7a967b Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 14:23:24 +0200 Subject: Create an artifacts folder --- packages/migrations/artifacts/1.0.0/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/migrations/artifacts/1.0.0/.gitkeep (limited to 'packages') diff --git a/packages/migrations/artifacts/1.0.0/.gitkeep b/packages/migrations/artifacts/1.0.0/.gitkeep new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From 906af858a5b013927e06ebafdad12d13ba674932 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 7 May 2018 14:32:17 +0200 Subject: Fix artifacts paths --- packages/contracts/package.json | 4 ++-- packages/dev-utils/src/coverage.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 4ca4e2db1..c47518f17 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -10,7 +10,7 @@ "scripts": { "build:watch": "tsc -w", "prebuild": "run-s clean compile copy_artifacts generate_contract_wrappers", - "copy_artifacts": "copyfiles -u 4 '../migrations/src/artifacts/**/*' ./lib/src/artifacts;", + "copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/1.0.0/**/*' ./lib/src/artifacts;", "build": "tsc", "test": "run-s build run_mocha", "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", @@ -26,7 +26,7 @@ "test:circleci": "yarn test:coverage" }, "config": { - "abis": "../migrations/src/artifacts/@(DummyToken|TokenTransferProxy|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|Arbitrage|EtherDelta|AccountLevels).json" + "abis": "../migrations/artifacts/1.0.0/@(DummyToken|TokenTransferProxy|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|Arbitrage|EtherDelta|AccountLevels).json" }, "repository": { "type": "git", diff --git a/packages/dev-utils/src/coverage.ts b/packages/dev-utils/src/coverage.ts index 67c87ec30..743573874 100644 --- a/packages/dev-utils/src/coverage.ts +++ b/packages/dev-utils/src/coverage.ts @@ -13,7 +13,7 @@ export const coverage = { return coverageSubprovider; }, _getCoverageSubprovider(): CoverageSubprovider { - const artifactsPath = '../migrations/src/artifacts'; + const artifactsPath = '../migrations/artifacts/1.0.0'; const contractsPath = 'src/contracts'; const networkId = 50; const defaultFromAddress = constants.TESTRPC_FIRST_ADDRESS; -- cgit v1.2.3 From 73c6f11c9c19f5332ba7f02811a5386b844f9357 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 8 May 2018 10:47:35 +0200 Subject: Update The Ocean logo --- .../public/images/landing/project_logos/the_ocean.png | Bin 4766 -> 6322 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'packages') diff --git a/packages/website/public/images/landing/project_logos/the_ocean.png b/packages/website/public/images/landing/project_logos/the_ocean.png index 74678b5d4..0677abc29 100644 Binary files a/packages/website/public/images/landing/project_logos/the_ocean.png and b/packages/website/public/images/landing/project_logos/the_ocean.png differ -- cgit v1.2.3 From a44874d2eb1dd9bf721c3d86f65c2e2078210049 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 25 Apr 2018 11:16:07 -0700 Subject: Add token flow --- .../ts/components/legacy_portal/legacy_portal.tsx | 47 ---------------------- .../legacy_portal/legacy_portal_menu.tsx | 20 --------- packages/website/ts/components/portal/portal.tsx | 35 +++++++++++++++- packages/website/ts/components/wallet/wallet.tsx | 10 ++++- 4 files changed, 43 insertions(+), 69 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/legacy_portal/legacy_portal.tsx b/packages/website/ts/components/legacy_portal/legacy_portal.tsx index 8942e4356..c45b20365 100644 --- a/packages/website/ts/components/legacy_portal/legacy_portal.tsx +++ b/packages/website/ts/components/legacy_portal/legacy_portal.tsx @@ -154,7 +154,6 @@ export class LegacyPortal extends React.Component {this.props.blockchainIsLoaded ? ( - {isDevelopment && ( - - )} - {isDevelopment && ( - - )} t.isTracked); - return ( -
-
- -
-
- ); - } - private _renderRelayers() { - return ( -
-
- -
-
- ); - } private _renderEthWrapper() { return ( {this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')} - {configs.ENVIRONMENT === Environments.DEVELOPMENT && ( -
- - {this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')} - - - {this._renderMenuItemWithIcon('Relayers', 'zmdi-input-antenna')} - -
- )}
); } diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 507860ee6..bee2cf95d 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -8,13 +8,14 @@ import { Blockchain } from 'ts/blockchain'; import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; +import { AssetPicker } from 'ts/components/generate_order/asset_picker'; import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; import { TopBar } from 'ts/components/top_bar/top_bar'; import { FlashMessage } from 'ts/components/ui/flash_message'; import { Wallet } from 'ts/components/wallet/wallet'; import { localStorage } from 'ts/local_storage/local_storage'; import { Dispatcher } from 'ts/redux/dispatcher'; -import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress } from 'ts/types'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, TokenVisibility } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; @@ -48,6 +49,7 @@ interface PortalState { prevPathname: string; isDisclaimerDialogOpen: boolean; isLedgerDialogOpen: boolean; + isAssetPickerDialogOpen: boolean; } const THROTTLE_TIMEOUT = 100; @@ -89,6 +91,7 @@ export class Portal extends React.Component { prevUserAddress: this.props.userAddress, prevPathname: this.props.location.pathname, isDisclaimerDialogOpen: !hasAcceptedDisclaimer, + isAssetPickerDialogOpen: false, isLedgerDialogOpen: false, }; } @@ -176,6 +179,7 @@ export class Portal extends React.Component { injectedProviderName={this.props.injectedProviderName} providerType={this.props.providerType} onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} + onAddToken={this._onAddToken.bind(this)} />
@@ -208,15 +212,44 @@ export class Portal extends React.Component { isOpen={this.state.isLedgerDialogOpen} /> )} +
); } + private _onTokenChosen(tokenAddress: string) { + if (_.isEmpty(tokenAddress)) { + this.setState({ + isAssetPickerDialogOpen: false, + }); + return; + } + const token = this.props.tokenByAddress[tokenAddress]; + this.props.dispatcher.updateTokenByAddress([token]); + this.setState({ + isAssetPickerDialogOpen: false, + }); + } private _onToggleLedgerDialog() { this.setState({ isLedgerDialogOpen: !this.state.isLedgerDialogOpen, }); } + private _onAddToken() { + this.setState({ + isAssetPickerDialogOpen: !this.state.isAssetPickerDialogOpen, + }); + } private _onPortalDisclaimerAccepted() { localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set'); this.setState({ diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 057c712e5..068764027 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -55,6 +55,7 @@ export interface WalletProps { injectedProviderName: string; providerType: ProviderType; onToggleLedgerDialog: () => void; + onAddToken: () => void; } interface WalletState { @@ -232,7 +233,14 @@ export class Wallet extends React.Component { } private _renderFooterRows() { const primaryText = '+ other tokens'; - return ; + return ( + + ); } private _renderEthRows() { const primaryText = this._renderAmount( -- cgit v1.2.3 From 419b670aa35eb35a767137121b5e594a04793eb7 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 3 May 2018 15:15:13 -0700 Subject: Make wallet scrollable --- packages/website/ts/components/wallet/wallet.tsx | 57 ++++++++++++++++++++---- 1 file changed, 48 insertions(+), 9 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 068764027..a28012aaf 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -61,6 +61,7 @@ export interface WalletProps { interface WalletState { trackedTokenStateByAddress: TokenStateByAddress; wrappedEtherDirection?: Side; + isHoveringSidebar: boolean; } interface AllowanceToggleConfig { @@ -95,6 +96,9 @@ const styles: Styles = { }, footerItemInnerDiv: { paddingLeft: 24, + borderTopColor: colors.walletBorder, + borderTopStyle: 'solid', + borderWidth: 1, }, borderedItem: { borderBottomColor: colors.walletBorder, @@ -115,7 +119,17 @@ const styles: Styles = { paddingTop: 8, paddingBottom: 8, }, - accessoryItemsContainer: { width: 150, right: 8 }, + accessoryItemsContainer: { + width: 150, + right: 8, + }, + bodyInnerDiv: { + padding: 0, + // TODO: make this completely responsive + maxHeight: 475, + overflow: 'auto', + WebkitOverflowScrolling: 'touch', + }, }; const ETHER_ICON_PATH = '/images/ether.png'; @@ -140,6 +154,7 @@ export class Wallet extends React.Component { this.state = { trackedTokenStateByAddress: initialTrackedTokenStateByAddress, wrappedEtherDirection: undefined, + isHoveringSidebar: false, }; } public componentWillMount() { @@ -185,12 +200,7 @@ export class Wallet extends React.Component { return ( {isAddressAvailable - ? _.concat( - this._renderConnectedHeaderRows(), - this._renderEthRows(), - this._renderTokenRows(), - this._renderFooterRows(), - ) + ? _.concat(this._renderConnectedHeaderRows(), this._renderBody(), this._renderFooterRows()) : _.concat(this._renderDisconnectedHeaderRows(), this._renderDisconnectedRows())} ); @@ -231,6 +241,33 @@ export class Wallet extends React.Component { /> ); } + private _renderBody() { + const bodyStyle: React.CSSProperties = { + ...styles.bodyInnerDiv, + overflow: this.state.isHoveringSidebar ? 'auto' : 'hidden', + }; + return ( + + {this._renderEthRows()} + {this._renderTokenRows()} + + ); + } + private _onSidebarHover(event: React.FormEvent) { + this.setState({ + isHoveringSidebar: true, + }); + } + private _onSidebarHoverOff() { + this.setState({ + isHoveringSidebar: false, + }); + } private _renderFooterRows() { const primaryText = '+ other tokens'; return ( @@ -301,7 +338,7 @@ export class Wallet extends React.Component { ); return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this)); } - private _renderTokenRow(token: Token) { + private _renderTokenRow(token: Token, index: number) { const tokenState = this.state.trackedTokenStateByAddress[token.address]; const tokenLink = sharedUtils.getEtherScanLinkIfExists( token.address, @@ -318,12 +355,14 @@ export class Wallet extends React.Component { tokenState, }, }; + // if this is the last item in the list, do not render the border, it is rendered by the footer + const borderedStyle = index !== this.props.trackedTokens.length - 1 ? styles.borderedItem : {}; const shouldShowWrapEtherItem = !_.isUndefined(this.state.wrappedEtherDirection) && this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection; const style = shouldShowWrapEtherItem ? { ...walletItemStyles.focusedItem, ...styles.paddedItem } - : { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem }; + : { ...styles.tokenItem, ...borderedStyle, ...styles.paddedItem }; const etherToken = this._getEthToken(); return (
-- cgit v1.2.3 From 9cbd1516586fd5514cce8d216881bad3871c58fa Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 3 May 2018 15:26:30 -0700 Subject: Only show untracked tokens --- packages/website/ts/components/portal/portal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index bee2cf95d..f6077edf8 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -221,7 +221,7 @@ export class Portal extends React.Component { currentTokenAddress={''} onTokenChosen={this._onTokenChosen.bind(this)} tokenByAddress={this.props.tokenByAddress} - tokenVisibility={TokenVisibility.ALL} + tokenVisibility={TokenVisibility.UNTRACKED} />
-- cgit v1.2.3 From 6c38481550d3bc57413ffb013d1b94a53672202b Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 8 May 2018 10:17:01 -0700 Subject: Fix typo --- packages/website/ts/components/portal/portal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index f6077edf8..e198a9f03 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -108,7 +108,7 @@ export class Portal extends React.Component { // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered // the initialization process always occurs from the same base state. This helps avoid // initialization inconsistencies (i.e While the portal was unrendered, the user might have - // become disconnected from their backing Ethereum node, changes user accounts, etc...) + // become disconnected from their backing Ethereum node, changed user accounts, etc...) this.props.dispatcher.resetState(); } public componentWillReceiveProps(nextProps: PortalProps) { -- cgit v1.2.3 From 17f3d5f6bac178ffda6060eea227ef8deaaf73aa Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 8 May 2018 11:12:46 -0700 Subject: Suggestions and fix bad merge --- packages/website/ts/components/portal/portal.tsx | 9 --------- .../website/ts/components/top_bar/provider_display.tsx | 18 ++++++------------ 2 files changed, 6 insertions(+), 21 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 88003a94e..d359219cd 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -9,11 +9,7 @@ import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; -<<<<<<< HEAD import { TopBar, TopBarDisplayType } from 'ts/components/top_bar/top_bar'; -======= -import { TopBar } from 'ts/components/top_bar/top_bar'; ->>>>>>> development import { FlashMessage } from 'ts/components/ui/flash_message'; import { Wallet } from 'ts/components/wallet/wallet'; import { localStorage } from 'ts/local_storage/local_storage'; @@ -55,11 +51,7 @@ interface PortalState { } const THROTTLE_TIMEOUT = 100; -<<<<<<< HEAD const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded); -======= -const TOP_BAR_HEIGHT = 60; ->>>>>>> development const styles: Styles = { root: { @@ -71,7 +63,6 @@ const styles: Styles = { height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, }, scrollContainer: { - overflowZ: 'hidden', height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, WebkitOverflowScrolling: 'touch', overflow: 'auto', diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx index fa5609014..4cd50dba9 100644 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ b/packages/website/ts/components/top_bar/provider_display.tsx @@ -11,7 +11,7 @@ import { ProviderType } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { utils } from 'ts/utils/utils'; -const IDENTICON_DIAMETER = 24; +const ROOT_HEIGHT = 24; export interface ProviderDisplayProps { dispatcher: Dispatcher; @@ -27,12 +27,9 @@ interface ProviderDisplayState {} const styles: Styles = { root: { - height: 24, + height: ROOT_HEIGHT, backgroundColor: colors.white, - borderBottomRightRadius: 24, - borderBottomLeftRadius: 24, - borderTopRightRadius: 24, - borderTopLeftRadius: 24, + borderRadius: ROOT_HEIGHT, boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`, }, }; @@ -52,21 +49,18 @@ export class ProviderDisplay extends React.Component
- +
{displayAddress}
{isProviderMetamask && (
- +
)}
-- cgit v1.2.3 From 5ed9b8b1dc042319fd9ddbdb886c93a660a96769 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 8 May 2018 11:16:12 -0700 Subject: Remove overflowZ property from portal --- packages/website/ts/components/portal/portal.tsx | 1 - 1 file changed, 1 deletion(-) (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index e198a9f03..1038d0dc2 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -65,7 +65,6 @@ const styles: Styles = { height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, }, scrollContainer: { - overflowZ: 'hidden', height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, WebkitOverflowScrolling: 'touch', overflow: 'auto', -- cgit v1.2.3 From f94d4b492dc0a2bfdd8bfa8d9a1376ed33b03060 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 8 May 2018 11:32:44 -0700 Subject: Display top tokens from backend --- .../components/relayer_index/relayer_grid_tile.tsx | 33 +--------------------- .../relayer_index/relayer_top_tokens.tsx | 16 +++++------ packages/website/ts/types.ts | 9 +++++- 3 files changed, 17 insertions(+), 41 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index 0b9b8165e..677c66695 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -12,37 +12,6 @@ export interface RelayerGridTileProps { networkId: number; } -// TODO: Get top tokens from remote -const topTokens = [ - { - address: '0x1dad4783cf3fe3085c1426157ab175a6119a04ba', - decimals: 18, - iconUrl: '/images/token_icons/makerdao.png', - isRegistered: true, - isTracked: true, - name: 'Maker DAO', - symbol: 'MKR', - }, - { - address: '0x323b5d4c32345ced77393b3530b1eed0f346429d', - decimals: 18, - iconUrl: '/images/token_icons/melon.png', - isRegistered: true, - isTracked: true, - name: 'Melon Token', - symbol: 'MLN', - }, - { - address: '0xb18845c260f680d5b9d84649638813e342e4f8c9', - decimals: 18, - iconUrl: '/images/token_icons/augur.png', - isRegistered: true, - isTracked: true, - name: 'Augur Reputation Token', - symbol: 'REP', - }, -]; - const styles: Styles = { root: { backgroundColor: colors.white, @@ -108,7 +77,7 @@ export const RelayerGridTile: React.StatelessComponent = (
Daily Trade Volume
- +
Top tokens
diff --git a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx index 233590b78..db4d3a211 100644 --- a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx +++ b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx @@ -3,10 +3,10 @@ import * as _ from 'lodash'; import * as React from 'react'; import { TokenIcon } from 'ts/components/ui/token_icon'; -import { Token } from 'ts/types'; +import { WebsiteBackendTokenInfo } from 'ts/types'; export interface TopTokensProps { - tokens: Token[]; + tokens: WebsiteBackendTokenInfo[]; networkId: number; } @@ -23,17 +23,17 @@ const styles: Styles = { export const TopTokens: React.StatelessComponent = (props: TopTokensProps) => { return (
- {_.map(props.tokens, (token: Token, index: number) => { + {_.map(props.tokens, (tokenInfo: WebsiteBackendTokenInfo, index: number) => { const firstItemStyle = { ...styles.tokenLabel, ...styles.followingTokenLabel }; const style = index !== 0 ? firstItemStyle : styles.tokenLabel; return ( - {token.symbol} + {tokenInfo.symbol} ); })} @@ -41,6 +41,6 @@ export const TopTokens: React.StatelessComponent = (props: TopTo ); }; -function tokenLinkFromToken(token: Token, networkId: number) { - return sharedUtils.getEtherScanLinkIfExists(token.address, networkId, EtherscanLinkSuffixes.Address); +function tokenLinkFromToken(tokenInfo: WebsiteBackendTokenInfo, networkId: number) { + return sharedUtils.getEtherScanLinkIfExists(tokenInfo.address, networkId, EtherscanLinkSuffixes.Address); } diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 2754075a7..f6752aef1 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -503,19 +503,26 @@ export interface TokenState { price?: BigNumber; } -// TODO: Add topTokens property once available from backend export interface WebsiteBackendRelayerInfo { name: string; dailyTxnVolume: string; url: string; appUrl?: string; headerImgUrl: string; + topTokens: WebsiteBackendTokenInfo[]; } export interface WebsiteBackendPriceInfo { [symbol: string]: string; } +export interface WebsiteBackendTokenInfo { + address: string; + decimals: number; + name: string; + symbol: string; +} + export interface WebsiteBackendGasInfo { average: number; } -- cgit v1.2.3 From 9f2258ebd962f60dfaa277814a3ead93d1b19ac7 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 09:28:57 -0700 Subject: Change relayer grid tile to link on header --- .../components/relayer_index/relayer_grid_tile.tsx | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index 677c66695..cf2a1f66d 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -65,25 +65,25 @@ const styles: Styles = { export const RelayerGridTile: React.StatelessComponent = (props: RelayerGridTileProps) => { const link = props.relayerInfo.appUrl || props.relayerInfo.url; return ( - - -
+ +
+ -
-
- {props.relayerInfo.name} -
-
{props.relayerInfo.dailyTxnVolume}
-
- Daily Trade Volume -
- -
- Top tokens -
+
+
+
+ {props.relayerInfo.name} +
+
{props.relayerInfo.dailyTxnVolume}
+
+ Daily Trade Volume +
+ +
+ Top tokens
- - +
+ ); }; -- cgit v1.2.3 From 09b26645eebb53e8a730f60998fd689c6bb15528 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 10:04:28 -0700 Subject: Fallback image for relayer grid tile --- packages/website/ts/components/relayer_index/relayer_grid_tile.tsx | 3 ++- packages/website/ts/types.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index cf2a1f66d..23c5da50b 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -64,11 +64,12 @@ const styles: Styles = { export const RelayerGridTile: React.StatelessComponent = (props: RelayerGridTileProps) => { const link = props.relayerInfo.appUrl || props.relayerInfo.url; + const headerImgUrl = props.relayerInfo.headerImgUrl || '/images/landing/hero_chip_image.png'; return (
- +
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index f6752aef1..67e4a5d7d 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -508,7 +508,7 @@ export interface WebsiteBackendRelayerInfo { dailyTxnVolume: string; url: string; appUrl?: string; - headerImgUrl: string; + headerImgUrl?: string; topTokens: WebsiteBackendTokenInfo[]; } -- cgit v1.2.3 From 20f6d8d3d0d7452bd4dc35c7c55b2cfc169216ca Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 10:57:02 -0700 Subject: Implement loading and error state for relayer grid --- .../ts/components/relayer_index/relayer_index.tsx | 60 ++++++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index bc84cf9e8..df208753b 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -1,5 +1,7 @@ import { colors, Styles } from '@0xproject/react-shared'; import * as _ from 'lodash'; +import CircularProgress from 'material-ui/CircularProgress'; +import FlatButton from 'material-ui/FlatButton'; import { GridList } from 'material-ui/GridList'; import * as React from 'react'; @@ -55,7 +57,24 @@ export class RelayerIndex extends React.Component +
+
+ {_.isUndefined(this.state.error) ? ( + + ) : ( + + )} +
+
+
+ ); + } else { return (
- {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo) => ( - + {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo, index) => ( + ))}
); - } else { - // TODO: loading and error states with a scrolling container - return null; } } private async _fetchRelayerInfosAsync(): Promise { @@ -96,3 +108,31 @@ export class RelayerIndex extends React.Component void; +} +const Retry = (props: RetryProps) => ( +
+
+
+ Something went wrong. +
+
+ +
+
+
+); -- cgit v1.2.3 From c7a147f49d6e16e677eab5a9a70191720ec61963 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 9 May 2018 23:14:44 +0200 Subject: Configure the compiler to generate artifacts with deployedBytecode --- packages/sol-cov/compiler.json | 18 ++++++++++++++++++ packages/sol-cov/package.json | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 packages/sol-cov/compiler.json (limited to 'packages') diff --git a/packages/sol-cov/compiler.json b/packages/sol-cov/compiler.json new file mode 100644 index 000000000..a6a0c6d3a --- /dev/null +++ b/packages/sol-cov/compiler.json @@ -0,0 +1,18 @@ +{ + "contracts": ["SimpleStorage"], + "contractsDir": "test/fixtures/contracts", + "artifactsDir": "test/fixtures/artifacts", + "compilerSettings": { + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + } + } +} diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json index 4eb1147d7..425b561a6 100644 --- a/packages/sol-cov/package.json +++ b/packages/sol-cov/package.json @@ -14,7 +14,7 @@ "run_mocha": "mocha lib/test/**/*_test.js --exit", "clean": "shx rm -rf lib scripts", "build": "copyfiles 'test/fixtures/**/*' ./lib && tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts", - "compile_test": "node ../deployer/lib/src/cli.js compile --contracts SimpleStorage --contracts-dir test/fixtures/contracts --artifacts-dir test/fixtures/artifacts", + "compile_test": "node ../deployer/lib/src/cli.js compile", "manual:postpublish": "yarn build; node ./scripts/postpublish.js", "docs:stage": "yarn build && node ./scripts/stage_docs.js", "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES", -- cgit v1.2.3 From e83b056bd494e0e6a16fd0b9bfdb84bac2ab271d Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 15:59:10 -0700 Subject: Clear relayer grid state when fetching --- packages/website/ts/components/relayer_index/relayer_index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'packages') diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index df208753b..dffd0f83f 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -93,6 +93,12 @@ export class RelayerIndex extends React.Component { try { + if (!this._isUnmounted) { + this.setState({ + relayerInfos: undefined, + error: undefined, + }); + } const relayerInfos = await backendClient.getRelayerInfosAsync(); if (!this._isUnmounted) { this.setState({ -- cgit v1.2.3 From c64ad1af28ef116e210aafb3ea6ad2138361cd7c Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 17:29:02 -0700 Subject: Add fallback image support to relayer grid tile --- .../components/relayer_index/relayer_grid_tile.tsx | 38 ++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index 23c5da50b..d88a59d15 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -62,14 +62,19 @@ const styles: Styles = { }, }; +const FALLBACK_IMG_SRC = '/images/landing/hero_chip_image.png'; + export const RelayerGridTile: React.StatelessComponent = (props: RelayerGridTileProps) => { const link = props.relayerInfo.appUrl || props.relayerInfo.url; - const headerImgUrl = props.relayerInfo.headerImgUrl || '/images/landing/hero_chip_image.png'; return (
- +
@@ -88,3 +93,32 @@ export const RelayerGridTile: React.StatelessComponent = ( ); }; + +interface ImgWithFallbackProps { + src?: string; + fallbackSrc: string; + style: React.CSSProperties; +} +interface ImgWithFallbackState { + imageLoadFailed: boolean; +} +class ImgWithFallback extends React.Component { + constructor(props: ImgWithFallbackProps) { + super(props); + this.state = { + imageLoadFailed: false, + }; + } + public render() { + if (this.state.imageLoadFailed || _.isUndefined(this.props.src)) { + return ; + } else { + return ; + } + } + private _onError() { + this.setState({ + imageLoadFailed: true, + }); + } +} -- cgit v1.2.3