From 3031598843080ff4fabb7bfb0ba823be6d545285 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 30 Jun 2018 13:23:13 -0700 Subject: Implement icon button --- packages/website/ts/components/ui/text.tsx | 5 +++-- packages/website/ts/components/wallet/wallet.tsx | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/ui/text.tsx b/packages/website/ts/components/ui/text.tsx index c1cb2ade4..315f72854 100644 --- a/packages/website/ts/components/ui/text.tsx +++ b/packages/website/ts/components/ui/text.tsx @@ -3,7 +3,7 @@ import { darken } from 'polished'; import * as React from 'react'; import { styled } from 'ts/style/theme'; -export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4'; +export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' | 'i'; export interface TextProps { className?: string; @@ -17,6 +17,7 @@ export interface TextProps { fontWeight?: number | string; textDecorationLine?: string; onClick?: (event: React.MouseEvent) => void; + hoverColor?: string; } const PlainText: React.StatelessComponent = ({ children, className, onClick, Tag }) => ( @@ -37,7 +38,7 @@ export const Text = styled(PlainText)` ${props => (props.onClick ? 'cursor: pointer' : '')}; transition: color 0.5s ease; &:hover { - ${props => (props.onClick ? `color: ${darken(0.3, props.fontColor)}` : '')}; + ${props => (props.onClick ? `color: ${props.hoverColor || darken(0.3, props.fontColor)}` : '')}; } `; diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 1f1e3598a..899f8e3a3 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -199,11 +199,26 @@ export class Wallet extends React.Component { ); + const onClick = _.noop; + const accessory = ( + + + + ); return ( } main={main} + accessory={accessory} minHeight="60px" backgroundColor={colors.white} /> -- cgit v1.2.3 From be64184cfa11dcabd543161b5d7a6726d4e7924d Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 30 Jun 2018 13:51:40 -0700 Subject: Clean up a bit of the provider display logic --- .../ts/components/top_bar/install_prompt.tsx | 59 ++++++++++++++ .../ts/components/top_bar/provider_display.tsx | 92 +++++----------------- packages/website/ts/components/ui/drop_down.tsx | 2 +- 3 files changed, 80 insertions(+), 73 deletions(-) create mode 100644 packages/website/ts/components/top_bar/install_prompt.tsx (limited to 'packages') diff --git a/packages/website/ts/components/top_bar/install_prompt.tsx b/packages/website/ts/components/top_bar/install_prompt.tsx new file mode 100644 index 000000000..8d1a9c48a --- /dev/null +++ b/packages/website/ts/components/top_bar/install_prompt.tsx @@ -0,0 +1,59 @@ +import RaisedButton from 'material-ui/RaisedButton'; +import * as React from 'react'; + +import { colors } from 'ts/style/colors'; +import { constants } from 'ts/utils/constants'; + +export interface InstallPromptProps { + onToggleLedgerDialog: () => void; +} + +export const InstallPrompt: React.StatelessComponent = ({ onToggleLedgerDialog }) => { + return ( +
+
+ Choose a wallet: +
+
+
+
Install a browser wallet
+
+ +
+ +
+
+
+
or
+
+
+
+
Connect to a ledger hardware wallet
+
+ +
+
+ +
+
+
+
+ ); +}; diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx index 8743e4320..18afee4ea 100644 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ b/packages/website/ts/components/top_bar/provider_display.tsx @@ -7,6 +7,7 @@ import Lock from 'material-ui/svg-icons/action/lock'; import * as React from 'react'; import { Blockchain } from 'ts/blockchain'; +import { InstallPrompt } from 'ts/components/top_bar/install_prompt'; import { ProviderPicker } from 'ts/components/top_bar/provider_picker'; import { AccountConnection } from 'ts/components/ui/account_connection'; import { Container } from 'ts/components/ui/container'; @@ -72,78 +73,25 @@ export class ProviderDisplay extends React.Component - ); - } else { - // Nothing to connect to, show install/info popover - return ( -
-
- Choose a wallet: -
-
-
-
Install a browser wallet
-
- -
-
- Use{' '} - - Metamask - {' '} - or{' '} - - Parity Signer - -
-
-
-
-
or
-
-
-
-
Connect to a ledger hardware wallet
-
- -
-
- -
-
-
-
- ); + const accountState = this._getAccountState(); + switch (accountState) { + case AccountState.Ready: + case AccountState.Locked: + return ( + + ); + case AccountState.Disconnected: + return ; + case AccountState.Loading: + default: + return null; } } private _renderIcon(): React.ReactNode { diff --git a/packages/website/ts/components/ui/drop_down.tsx b/packages/website/ts/components/ui/drop_down.tsx index 22cb942f8..7d900d685 100644 --- a/packages/website/ts/components/ui/drop_down.tsx +++ b/packages/website/ts/components/ui/drop_down.tsx @@ -66,7 +66,7 @@ export class DropDown extends React.Component { targetOrigin={this.props.targetOrigin} onRequestClose={this._closePopover.bind(this)} useLayerForClickAway={false} - animation={PopoverAnimationVertical} + animated={false} zDepth={this.props.zDepth} >
-- cgit v1.2.3 From da8cf9981eda4a068c22d0107e07b704afda2584 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 30 Jun 2018 14:25:33 -0700 Subject: Implement simple menu --- .../ts/components/top_bar/provider_display.tsx | 25 ++++--- .../ts/components/top_bar/provider_picker.tsx | 79 ---------------------- packages/website/ts/components/ui/container.tsx | 1 + packages/website/ts/components/ui/drop_down.tsx | 2 +- packages/website/ts/components/ui/simple_menu.tsx | 34 ++++++++++ 5 files changed, 50 insertions(+), 91 deletions(-) delete mode 100644 packages/website/ts/components/top_bar/provider_picker.tsx create mode 100644 packages/website/ts/components/ui/simple_menu.tsx (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 18afee4ea..3f29d5ff3 100644 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ b/packages/website/ts/components/top_bar/provider_display.tsx @@ -5,19 +5,21 @@ import RaisedButton from 'material-ui/RaisedButton'; import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet'; import Lock from 'material-ui/svg-icons/action/lock'; import * as React from 'react'; +import * as CopyToClipboard from 'react-copy-to-clipboard'; +import { Link } from 'react-router-dom'; import { Blockchain } from 'ts/blockchain'; import { InstallPrompt } from 'ts/components/top_bar/install_prompt'; -import { ProviderPicker } from 'ts/components/top_bar/provider_picker'; import { AccountConnection } from 'ts/components/ui/account_connection'; import { Container } from 'ts/components/ui/container'; import { DropDown } from 'ts/components/ui/drop_down'; import { Identicon } from 'ts/components/ui/identicon'; import { Island } from 'ts/components/ui/island'; +import { SimpleMenu, SimpleMenuItem } from 'ts/components/ui/simple_menu'; import { Text } from 'ts/components/ui/text'; import { Dispatcher } from 'ts/redux/dispatcher'; import { colors } from 'ts/style/colors'; -import { AccountState, ProviderType } from 'ts/types'; +import { AccountState, ProviderType, WebsitePaths } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { utils } from 'ts/utils/utils'; @@ -76,19 +78,20 @@ export class ProviderDisplay extends React.Component + + + + + + + + + ); case AccountState.Disconnected: return ; + case AccountState.Locked: case AccountState.Loading: default: return null; diff --git a/packages/website/ts/components/top_bar/provider_picker.tsx b/packages/website/ts/components/top_bar/provider_picker.tsx deleted file mode 100644 index 7937f2e9d..000000000 --- a/packages/website/ts/components/top_bar/provider_picker.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { colors, constants as sharedConstants } from '@0xproject/react-shared'; -import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton'; -import * as React from 'react'; -import { Blockchain } from 'ts/blockchain'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { ProviderType } from 'ts/types'; - -interface ProviderPickerProps { - networkId: number; - injectedProviderName: string; - providerType: ProviderType; - onToggleLedgerDialog: () => void; - dispatcher: Dispatcher; - blockchain: Blockchain; -} - -interface ProviderPickerState {} - -export class ProviderPicker extends React.Component { - public render(): React.ReactNode { - const isLedgerSelected = this.props.providerType === ProviderType.Ledger; - const menuStyle = { - padding: 10, - paddingTop: 15, - paddingBottom: 15, - }; - // Show dropdown with two options - return ( -
- - - - -
- ); - } - private _renderLabel(title: string, shouldShowNetwork: boolean): React.ReactNode { - const label = ( -
-
{title}
- {shouldShowNetwork && this._renderNetwork()} -
- ); - return label; - } - private _renderNetwork(): React.ReactNode { - const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId]; - return ( -
-
- -
-
{networkName}
-
- ); - } - private _onProviderRadioChanged(value: string): void { - if (value === ProviderType.Ledger) { - this.props.onToggleLedgerDialog(); - } else { - // tslint:disable-next-line:no-floating-promises - this.props.blockchain.updateProviderToInjectedAsync(); - } - } -} diff --git a/packages/website/ts/components/ui/container.tsx b/packages/website/ts/components/ui/container.tsx index fb718d731..edbf8814b 100644 --- a/packages/website/ts/components/ui/container.tsx +++ b/packages/website/ts/components/ui/container.tsx @@ -17,6 +17,7 @@ export interface ContainerProps { maxHeight?: StringOrNum; width?: StringOrNum; height?: StringOrNum; + minWidth?: StringOrNum; minHeight?: StringOrNum; isHidden?: boolean; className?: string; diff --git a/packages/website/ts/components/ui/drop_down.tsx b/packages/website/ts/components/ui/drop_down.tsx index 7d900d685..3738e50eb 100644 --- a/packages/website/ts/components/ui/drop_down.tsx +++ b/packages/website/ts/components/ui/drop_down.tsx @@ -49,7 +49,7 @@ export class DropDown extends React.Component { // call hoverOff whenever the dropdown receives updated props. This is a hack // because it will effectively close the dropdown on any prop update, barring // dropdowns from having dynamic content. - this._onHoverOff(); + // this._onHoverOff(); } public render(): React.ReactNode { return ( diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx new file mode 100644 index 000000000..29445c965 --- /dev/null +++ b/packages/website/ts/components/ui/simple_menu.tsx @@ -0,0 +1,34 @@ +import * as _ from 'lodash'; +import * as React from 'react'; + +import { Container } from 'ts/components/ui/container'; +import { Text } from 'ts/components/ui/text'; +import { colors } from 'ts/style/colors'; + +export interface SimpleMenuProps {} + +export const SimpleMenu: React.StatelessComponent = ({ children }) => { + return ( + + {children} + + ); +}; + +export interface SimpleMenuItemProps { + text: string; + onClick?: () => void; +} +export const SimpleMenuItem: React.StatelessComponent = ({ text, onClick }) => ( + + + {text} + + +); -- cgit v1.2.3 From 6daf754f5bb4aa85d0f65bfdaf8910db4401d1cc Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sat, 30 Jun 2018 23:32:06 -0700 Subject: Add menu to wallet --- packages/website/ts/components/wallet/wallet.tsx | 40 +++++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 899f8e3a3..b43164664 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -5,15 +5,18 @@ import * as _ from 'lodash'; import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet'; import * as React from 'react'; +import * as CopyToClipboard from 'react-copy-to-clipboard'; import { Link } from 'react-router-dom'; import firstBy = require('thenby'); import { Blockchain } from 'ts/blockchain'; import { AccountConnection } from 'ts/components/ui/account_connection'; import { Container } from 'ts/components/ui/container'; +import { DropDown } from 'ts/components/ui/drop_down'; import { IconButton } from 'ts/components/ui/icon_button'; import { Identicon } from 'ts/components/ui/identicon'; import { Island } from 'ts/components/ui/island'; +import { SimpleMenu, SimpleMenuItem } from 'ts/components/ui/simple_menu'; import { Text } from 'ts/components/ui/text'; import { TokenIcon } from 'ts/components/ui/token_icon'; import { BodyOverlay } from 'ts/components/wallet/body_overlay'; @@ -202,14 +205,35 @@ export class Wallet extends React.Component { const onClick = _.noop; const accessory = ( - + } + popoverContent={ + + + + + + + + + + } + anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} + targetOrigin={{ horizontal: 'right', vertical: 'top' }} + zDepth={1} /> ); -- cgit v1.2.3 From a6f40d418704a8dca8c787663f00b6bcbdf18ba4 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sun, 1 Jul 2018 13:31:43 -0700 Subject: Implement correct behavior for menu in the wallet --- packages/website/ts/blockchain_watcher.ts | 7 +++--- .../ts/components/top_bar/provider_display.tsx | 9 ++++---- packages/website/ts/components/top_bar/top_bar.tsx | 4 ++-- packages/website/ts/components/ui/drop_down.tsx | 27 ++++++++++++++++++---- packages/website/ts/components/ui/simple_menu.tsx | 14 +++++++---- packages/website/ts/components/wallet/wallet.tsx | 22 +++++++++--------- 6 files changed, 52 insertions(+), 31 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/blockchain_watcher.ts b/packages/website/ts/blockchain_watcher.ts index df5f73fd1..4b23aa98a 100644 --- a/packages/website/ts/blockchain_watcher.ts +++ b/packages/website/ts/blockchain_watcher.ts @@ -10,6 +10,7 @@ export class BlockchainWatcher { private _watchBalanceIntervalId: NodeJS.Timer; private _prevUserEtherBalanceInWei?: BigNumber; private _prevUserAddressIfExists: string; + private _prevNodeVersionIfExists: string; constructor(dispatcher: Dispatcher, web3Wrapper: Web3Wrapper, shouldPollUserAddress: boolean) { this._dispatcher = dispatcher; this._shouldPollUserAddress = shouldPollUserAddress; @@ -43,11 +44,9 @@ export class BlockchainWatcher { ); } private async _updateBalanceAsync(): Promise { - let prevNodeVersion: string; - // Check for node version changes const currentNodeVersion = await this._web3Wrapper.getNodeVersionAsync(); - if (currentNodeVersion !== prevNodeVersion) { - prevNodeVersion = currentNodeVersion; + if (this._prevNodeVersionIfExists !== currentNodeVersion) { + this._prevNodeVersionIfExists = currentNodeVersion; this._dispatcher.updateNodeVersion(currentNodeVersion); } diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx index 3f29d5ff3..6d02ebd59 100644 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ b/packages/website/ts/components/top_bar/provider_display.tsx @@ -51,7 +51,7 @@ export class ProviderDisplay extends React.Component {this._renderIcon()} @@ -61,14 +61,13 @@ export class ProviderDisplay extends React.Component ); const hasLedgerProvider = this.props.providerType === ProviderType.Ledger; - const horizontalPosition = isExternallyInjectedProvider || hasLedgerProvider ? 'left' : 'middle'; return (
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index fac6c131f..778536663 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -199,7 +199,7 @@ export class TopBar extends React.Component { cursor: 'pointer', paddingTop: 16, }; - const hoverActiveNode = ( + const activeNode = (
{this.props.translate.get(Key.Developers, Deco.Cap)}
@@ -224,7 +224,7 @@ export class TopBar extends React.Component {
{ public static defaultProps: Partial = { style: DEFAULT_STYLE, zDepth: 1, + shouldWaitForClickToActivate: false, }; private _isHovering: boolean; private _popoverCloseCheckIntervalId: number; @@ -49,7 +51,7 @@ export class DropDown extends React.Component { // call hoverOff whenever the dropdown receives updated props. This is a hack // because it will effectively close the dropdown on any prop update, barring // dropdowns from having dynamic content. - // this._onHoverOff(); + this._onHoverOff(); } public render(): React.ReactNode { return ( @@ -58,7 +60,7 @@ export class DropDown extends React.Component { onMouseEnter={this._onHover.bind(this)} onMouseLeave={this._onHoverOff.bind(this)} > - {this.props.hoverActiveNode} +
{this.props.activeNode}
{ animated={false} zDepth={this.props.zDepth} > -
+
{this.props.popoverContent}
); } + private _onActiveNodeClick(event: React.FormEvent): void { + event.stopPropagation(); + if (this.props.shouldWaitForClickToActivate) { + this.setState({ + isDropDownOpen: true, + anchorEl: event.currentTarget, + }); + } + } private _onHover(event: React.FormEvent): void { this._isHovering = true; - this._checkIfShouldOpenPopover(event); + if (!this.props.shouldWaitForClickToActivate) { + this._checkIfShouldOpenPopover(event); + } } private _checkIfShouldOpenPopover(event: React.FormEvent): void { if (this.state.isDropDownOpen) { diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx index 29445c965..22414d101 100644 --- a/packages/website/ts/components/ui/simple_menu.tsx +++ b/packages/website/ts/components/ui/simple_menu.tsx @@ -5,15 +5,17 @@ import { Container } from 'ts/components/ui/container'; import { Text } from 'ts/components/ui/text'; import { colors } from 'ts/style/colors'; -export interface SimpleMenuProps {} +export interface SimpleMenuProps { + minWidth?: number | string; +} -export const SimpleMenu: React.StatelessComponent = ({ children }) => { +export const SimpleMenu: React.StatelessComponent = ({ children, minWidth }) => { return ( {children} @@ -26,9 +28,13 @@ export interface SimpleMenuItemProps { onClick?: () => void; } export const SimpleMenuItem: React.StatelessComponent = ({ text, onClick }) => ( - + {text} ); + +SimpleMenu.defaultProps = { + minWidth: '220px', +}; diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index b43164664..fca6c5745 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -206,7 +206,7 @@ export class Wallet extends React.Component { const accessory = ( { /> } popoverContent={ - + @@ -234,19 +234,19 @@ export class Wallet extends React.Component { anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} targetOrigin={{ horizontal: 'right', vertical: 'top' }} zDepth={1} + shouldWaitForClickToActivate={true} /> ); return ( - - } - main={main} - accessory={accessory} - minHeight="60px" - backgroundColor={colors.white} - /> - + } + main={main} + accessory={accessory} + minHeight="60px" + backgroundColor={colors.white} + /> ); } private _renderBody(): React.ReactElement<{}> { -- cgit v1.2.3 From 955fdf5d13945fc7267e8ce0cc1f6016c57f3b72 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sun, 1 Jul 2018 14:03:07 -0700 Subject: Give connected header accessory more padding --- packages/website/ts/components/wallet/wallet.tsx | 22 +++++++++++++--------- 1 file changed, 13 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 fca6c5745..ab234ae1b 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -207,15 +207,19 @@ export class Wallet extends React.Component { + // this container gives the menu button more of a hover target for the drop down + // it prevents accidentally closing the menu by moving off of the button + + + } popoverContent={ -- cgit v1.2.3 From 5a7908984e118f2babf7c0680bf17afa148f5122 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sun, 1 Jul 2018 14:34:50 -0700 Subject: Consolidate logic for common menu items --- .../ts/components/top_bar/provider_display.tsx | 19 +++---- packages/website/ts/components/ui/simple_menu.tsx | 66 ++++++++++++++++++---- packages/website/ts/components/wallet/wallet.tsx | 22 +++----- 3 files changed, 74 insertions(+), 33 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 6d02ebd59..c2915f9a9 100644 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ b/packages/website/ts/components/top_bar/provider_display.tsx @@ -5,8 +5,6 @@ import RaisedButton from 'material-ui/RaisedButton'; import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet'; import Lock from 'material-ui/svg-icons/action/lock'; import * as React from 'react'; -import * as CopyToClipboard from 'react-copy-to-clipboard'; -import { Link } from 'react-router-dom'; import { Blockchain } from 'ts/blockchain'; import { InstallPrompt } from 'ts/components/top_bar/install_prompt'; @@ -15,7 +13,12 @@ import { Container } from 'ts/components/ui/container'; import { DropDown } from 'ts/components/ui/drop_down'; import { Identicon } from 'ts/components/ui/identicon'; import { Island } from 'ts/components/ui/island'; -import { SimpleMenu, SimpleMenuItem } from 'ts/components/ui/simple_menu'; +import { + CopyAddressSimpleMenuItem, + DifferentWalletSimpleMenuItem, + GoToAccountManagementSimpleMenuItem, + SimpleMenu, +} from 'ts/components/ui/simple_menu'; import { Text } from 'ts/components/ui/text'; import { Dispatcher } from 'ts/redux/dispatcher'; import { colors } from 'ts/style/colors'; @@ -79,13 +82,9 @@ export class ProviderDisplay extends React.Component - - - - - - - + + + ); case AccountState.Disconnected: diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx index 22414d101..52d97b1ea 100644 --- a/packages/website/ts/components/ui/simple_menu.tsx +++ b/packages/website/ts/components/ui/simple_menu.tsx @@ -1,9 +1,12 @@ import * as _ from 'lodash'; import * as React from 'react'; +import * as CopyToClipboard from 'react-copy-to-clipboard'; +import { Link } from 'react-router-dom'; import { Container } from 'ts/components/ui/container'; import { Text } from 'ts/components/ui/text'; import { colors } from 'ts/style/colors'; +import { WebsitePaths } from 'ts/types'; export interface SimpleMenuProps { minWidth?: number | string; @@ -23,18 +26,61 @@ export const SimpleMenu: React.StatelessComponent = ({ children ); }; +SimpleMenu.defaultProps = { + minWidth: '220px', +}; + export interface SimpleMenuItemProps { - text: string; + displayText: string; onClick?: () => void; } -export const SimpleMenuItem: React.StatelessComponent = ({ text, onClick }) => ( - - - {text} - - -); +export const SimpleMenuItem: React.StatelessComponent = ({ displayText, onClick }) => { + // Falling back to _.noop for onclick retains the hovering effect + return ( + + + {displayText} + + + ); +}; -SimpleMenu.defaultProps = { - minWidth: '220px', +export interface CopyAddressSimpleMenuItemProps { + userAddress: string; + onClick?: () => void; +} +export const CopyAddressSimpleMenuItem: React.StatelessComponent = ({ + userAddress, + onClick, +}) => { + return ( + + + + ); +}; + +export interface LinkSimpleMenuItemProps { + onClick?: () => void; +} +export const GoToAccountManagementSimpleMenuItem: React.StatelessComponent = ({ onClick }) => { + return ( + + + + ); +}; + +export interface DifferentWalletSimpleMenuItemProps { + onClick?: () => void; +} +export const DifferentWalletSimpleMenuItem: React.StatelessComponent = ({ + onClick, +}) => { + return ; }; diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index ab234ae1b..b6ae79b74 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -16,7 +16,12 @@ import { DropDown } from 'ts/components/ui/drop_down'; import { IconButton } from 'ts/components/ui/icon_button'; import { Identicon } from 'ts/components/ui/identicon'; import { Island } from 'ts/components/ui/island'; -import { SimpleMenu, SimpleMenuItem } from 'ts/components/ui/simple_menu'; +import { + CopyAddressSimpleMenuItem, + DifferentWalletSimpleMenuItem, + GoToAccountManagementSimpleMenuItem, + SimpleMenu, +} from 'ts/components/ui/simple_menu'; import { Text } from 'ts/components/ui/text'; import { TokenIcon } from 'ts/components/ui/token_icon'; import { BodyOverlay } from 'ts/components/wallet/body_overlay'; @@ -37,7 +42,6 @@ import { TokenByAddress, TokenState, TokenStateByAddress, - WebsitePaths, } from 'ts/types'; import { analytics } from 'ts/utils/analytics'; import { constants } from 'ts/utils/constants'; @@ -88,7 +92,6 @@ const HEADER_ITEM_KEY = 'HEADER'; const ETHER_ITEM_KEY = 'ETHER'; const USD_DECIMAL_PLACES = 2; const NO_ALLOWANCE_TOGGLE_SPACE_WIDTH = 56; -const ACCOUNT_PATH = `${WebsitePaths.Portal}/account`; const PLACEHOLDER_COLOR = colors.grey300; const LOADING_ROWS_COUNT = 6; @@ -223,16 +226,9 @@ export class Wallet extends React.Component { } popoverContent={ - - - - - - - + + + } anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} -- cgit v1.2.3 From 2dea179333dd14ad74aea65bb6558aac3bb716f4 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sun, 1 Jul 2018 14:44:14 -0700 Subject: More cleanup --- packages/website/ts/components/ui/drop_down.tsx | 1 - packages/website/ts/components/wallet/wallet.tsx | 61 ++++++++++++------------ 2 files changed, 31 insertions(+), 31 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/ui/drop_down.tsx b/packages/website/ts/components/ui/drop_down.tsx index 3f1fec3f4..947e51be0 100644 --- a/packages/website/ts/components/ui/drop_down.tsx +++ b/packages/website/ts/components/ui/drop_down.tsx @@ -83,7 +83,6 @@ export class DropDown extends React.Component { ); } private _onActiveNodeClick(event: React.FormEvent): void { - event.stopPropagation(); if (this.props.shouldWaitForClickToActivate) { this.setState({ isDropDownOpen: true, diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index b6ae79b74..56776d255 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -21,6 +21,7 @@ import { DifferentWalletSimpleMenuItem, GoToAccountManagementSimpleMenuItem, SimpleMenu, + SimpleMenuItem, } from 'ts/components/ui/simple_menu'; import { Text } from 'ts/components/ui/text'; import { TokenIcon } from 'ts/components/ui/token_icon'; @@ -207,36 +208,36 @@ export class Wallet extends React.Component { ); const onClick = _.noop; const accessory = ( - - - - - } - popoverContent={ - - - - - - } - anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} - targetOrigin={{ horizontal: 'right', vertical: 'top' }} - zDepth={1} - shouldWaitForClickToActivate={true} - /> - + + + + } + popoverContent={ + + + + + + + + } + anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} + targetOrigin={{ horizontal: 'right', vertical: 'top' }} + zDepth={1} + shouldWaitForClickToActivate={true} + /> ); return ( Date: Sun, 1 Jul 2018 14:48:01 -0700 Subject: Lint fixes --- packages/website/ts/components/top_bar/provider_display.tsx | 13 +++---------- packages/website/ts/components/ui/drop_down.tsx | 2 +- packages/website/ts/components/ui/simple_menu.tsx | 5 +---- packages/website/ts/components/wallet/wallet.tsx | 2 -- 4 files changed, 5 insertions(+), 17 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 c2915f9a9..74f9beedb 100644 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ b/packages/website/ts/components/top_bar/provider_display.tsx @@ -1,7 +1,6 @@ import { Styles } from '@0xproject/react-shared'; import * as _ from 'lodash'; import CircularProgress from 'material-ui/CircularProgress'; -import RaisedButton from 'material-ui/RaisedButton'; import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet'; import Lock from 'material-ui/svg-icons/action/lock'; import * as React from 'react'; @@ -22,8 +21,7 @@ import { import { Text } from 'ts/components/ui/text'; import { Dispatcher } from 'ts/redux/dispatcher'; import { colors } from 'ts/style/colors'; -import { AccountState, ProviderType, WebsitePaths } from 'ts/types'; -import { constants } from 'ts/utils/constants'; +import { AccountState, ProviderType } from 'ts/types'; import { utils } from 'ts/utils/utils'; const ROOT_HEIGHT = 24; @@ -50,10 +48,6 @@ const styles: Styles = { export class ProviderDisplay extends React.Component { public render(): React.ReactNode { - const isExternallyInjectedProvider = utils.isExternallyInjected( - this.props.providerType, - this.props.injectedProviderName, - ); const activeNode = ( {this._renderIcon()} @@ -63,12 +57,11 @@ export class ProviderDisplay extends React.Component ); - const hasLedgerProvider = this.props.providerType === ProviderType.Ledger; return (
); } - public renderPopoverContent(hasInjectedProvider: boolean, hasLedgerProvider: boolean): React.ReactNode { + private _renderPopoverContent(): React.ReactNode { const accountState = this._getAccountState(); switch (accountState) { case AccountState.Ready: diff --git a/packages/website/ts/components/ui/drop_down.tsx b/packages/website/ts/components/ui/drop_down.tsx index 947e51be0..c21c69993 100644 --- a/packages/website/ts/components/ui/drop_down.tsx +++ b/packages/website/ts/components/ui/drop_down.tsx @@ -1,4 +1,4 @@ -import Popover, { PopoverAnimationVertical } from 'material-ui/Popover'; +import Popover from 'material-ui/Popover'; import * as React from 'react'; import { MaterialUIPosition } from 'ts/types'; diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx index 52d97b1ea..c1cab07bd 100644 --- a/packages/website/ts/components/ui/simple_menu.tsx +++ b/packages/website/ts/components/ui/simple_menu.tsx @@ -65,10 +65,7 @@ export const CopyAddressSimpleMenuItem: React.StatelessComponent void; -} -export const GoToAccountManagementSimpleMenuItem: React.StatelessComponent = ({ onClick }) => { +export const GoToAccountManagementSimpleMenuItem: React.StatelessComponent<{}> = () => { return ( diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 56776d255..875e6e78d 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -5,8 +5,6 @@ import * as _ from 'lodash'; import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet'; import * as React from 'react'; -import * as CopyToClipboard from 'react-copy-to-clipboard'; -import { Link } from 'react-router-dom'; import firstBy = require('thenby'); import { Blockchain } from 'ts/blockchain'; -- cgit v1.2.3 From 8c5dc7cecdb8766e68a1d70d007904eb62ac1c55 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 2 Jul 2018 15:52:59 -0700 Subject: Only auto-start onboarding if blockchain is loaded --- .../website/ts/components/onboarding/portal_onboarding_flow.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx index 6bfa5c75f..6d8007659 100644 --- a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx +++ b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx @@ -46,7 +46,7 @@ class PlainPortalOnboardingFlow extends React.Component this.props.updateIsRunning(false)); } @@ -61,6 +61,9 @@ class PlainPortalOnboardingFlow extends React.Component Date: Mon, 2 Jul 2018 15:58:53 -0700 Subject: Remove max-width from onboarding card to support iPad --- packages/website/ts/components/onboarding/onboarding_card.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/website/ts/components/onboarding/onboarding_card.tsx b/packages/website/ts/components/onboarding/onboarding_card.tsx index 48e8ab022..ba5b3d6ea 100644 --- a/packages/website/ts/components/onboarding/onboarding_card.tsx +++ b/packages/website/ts/components/onboarding/onboarding_card.tsx @@ -39,7 +39,7 @@ export const OnboardingCard: React.StatelessComponent = ({ borderRadius, }) => ( - +
{title} -- cgit v1.2.3 From a5231df6d9d8c9b89431df2e4674f46d307f6d80 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 2 Jul 2018 17:26:48 -0700 Subject: Add media query abstraction around ScreenWidths and stop relayer grid hover effect on mobile --- packages/website/public/index.html | 12 +++++++++++- .../components/onboarding/unlock_wallet_onboarding_step.tsx | 2 +- .../ts/components/relayer_index/relayer_grid_tile.tsx | 4 ++++ packages/website/ts/types.ts | 7 ++++--- packages/website/ts/utils/utils.ts | 7 ++----- 5 files changed, 22 insertions(+), 10 deletions(-) (limited to 'packages') diff --git a/packages/website/public/index.html b/packages/website/public/index.html index 4c0985c71..c7a40875f 100644 --- a/packages/website/public/index.html +++ b/packages/website/public/index.html @@ -70,7 +70,17 @@ })(document, 'script', 'twitter-wjs'); - + + diff --git a/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx b/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx index 0039aa545..4ed7137d4 100644 --- a/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx +++ b/packages/website/ts/components/onboarding/unlock_wallet_onboarding_step.tsx @@ -10,7 +10,7 @@ export const UnlockWalletOnboardingStep: React.StatelessComponent - Unlock your metamask extension to get started. + Unlock your MetaMask extension to get started.
); 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 b26bf512b..20594e5ca 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -9,6 +9,7 @@ import { Container } from 'ts/components/ui/container'; import { Image } from 'ts/components/ui/image'; import { Island } from 'ts/components/ui/island'; import { colors } from 'ts/style/colors'; +import { media } from 'ts/style/media'; import { styled } from 'ts/style/theme'; import { WebsiteBackendRelayerInfo } from 'ts/types'; import { utils } from 'ts/utils/utils'; @@ -111,6 +112,9 @@ const GridTile = styled(PlainGridTile)` &:hover { transform: translate(0px, -3px); } + ${media.small` + transform: none; + `}; `; interface SectionProps { diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 498a0a5b8..e8fdbc255 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -215,10 +215,11 @@ export interface ContractEvent { } export type ValidatedBigNumberCallback = (isValid: boolean, amount?: BigNumber) => void; +// Associated values are in `em` units export enum ScreenWidths { - Sm = 'SM', - Md = 'MD', - Lg = 'LG', + Sm = 40, + Md = 52, + Lg = 64, } export enum AlertTypes { diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts index 726e1815f..73dacc1d6 100644 --- a/packages/website/ts/utils/utils.ts +++ b/packages/website/ts/utils/utils.ts @@ -27,9 +27,6 @@ import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; import * as u2f from 'ts/vendor/u2f_api'; -const LG_MIN_EM = 64; -const MD_MIN_EM = 52; - const isDogfood = (): boolean => _.includes(window.location.href, configs.DOMAIN_DOGFOOD); export const utils = { @@ -134,9 +131,9 @@ export const utils = { // This logic mirrors the CSS media queries in BassCSS for the `lg-`, `md-` and `sm-` CSS // class prefixes. Do not edit these. - if (widthInEm > LG_MIN_EM) { + if (widthInEm > ScreenWidths.Lg) { return ScreenWidths.Lg; - } else if (widthInEm > MD_MIN_EM) { + } else if (widthInEm > ScreenWidths.Md) { return ScreenWidths.Md; } else { return ScreenWidths.Sm; -- cgit v1.2.3 From a31f7a5112e9a74a64dd4079a08c0c749e3ffaeb Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 2 Jul 2018 18:12:08 -0700 Subject: Implement fixed position onboarding option --- .../ts/components/onboarding/onboarding_flow.tsx | 55 ++++++++++++++++------ .../onboarding/portal_onboarding_flow.tsx | 45 ++++++++++-------- 2 files changed, 67 insertions(+), 33 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/onboarding/onboarding_flow.tsx b/packages/website/ts/components/onboarding/onboarding_flow.tsx index 1f4c6df82..9abbc1c82 100644 --- a/packages/website/ts/components/onboarding/onboarding_flow.tsx +++ b/packages/website/ts/components/onboarding/onboarding_flow.tsx @@ -1,18 +1,35 @@ +import * as _ from 'lodash'; import * as React from 'react'; import { Placement, Popper, PopperChildrenProps } from 'react-popper'; import { OnboardingCard } from 'ts/components/onboarding/onboarding_card'; +import { PointerDirection } from 'ts/components/ui/pointer'; import { ContinueButtonDisplay, OnboardingTooltip } from 'ts/components/onboarding/onboarding_tooltip'; import { Animation } from 'ts/components/ui/animation'; import { Container } from 'ts/components/ui/container'; import { Overlay } from 'ts/components/ui/overlay'; import { zIndex } from 'ts/style/z_index'; -export interface Step { +export interface FixedPositionSettings { + type: 'fixed'; + top?: string; + bottom?: string; + left?: string; + right?: string; + pointerDirection?: PointerDirection; +} + +export interface TargetPositionSettings { + type: 'target'; target: string; + placement: Placement; +} + +export interface Step { + // Provide either a CSS selector, or fixed position settings. Only applies to desktop. + position: TargetPositionSettings | FixedPositionSettings; title?: string; content: React.ReactNode; - placement?: Placement; shouldHideBackButton?: boolean; shouldHideNextButton?: boolean; continueButtonDisplay?: ContinueButtonDisplay; @@ -40,18 +57,30 @@ export class OnboardingFlow extends React.Component { return null; } let onboardingElement = null; + const currentStep = this._getCurrentStep(); if (this.props.isMobile) { - onboardingElement = {this._renderOnboardignCard()}; - } else { + onboardingElement = {this._renderOnboardingCard()}; + } else if (currentStep.position.type === 'target') { + const { placement, target } = currentStep.position; onboardingElement = ( - + {this._renderPopperChildren.bind(this)} ); + } else if (currentStep.position.type === 'fixed') { + const { top, right, bottom, left, pointerDirection } = currentStep.position; + onboardingElement = ( + + {this._renderToolTip(pointerDirection)} + + ); } if (this.props.disableOverlay) { return onboardingElement; @@ -63,9 +92,6 @@ export class OnboardingFlow extends React.Component {
); } - private _getElementForStep(): Element { - return document.querySelector(this._getCurrentStep().target); - } private _renderPopperChildren(props: PopperChildrenProps): React.ReactNode { const customStyles = { zIndex: zIndex.aboveOverlay }; // On re-render, we want to re-center the popper. @@ -76,7 +102,7 @@ export class OnboardingFlow extends React.Component {
); } - private _renderToolTip(): React.ReactNode { + private _renderToolTip(pointerDirection?: PointerDirection): React.ReactNode { const { steps, stepIndex } = this.props; const step = steps[stepIndex]; const isLastStep = steps.length - 1 === stepIndex; @@ -94,12 +120,13 @@ export class OnboardingFlow extends React.Component { continueButtonDisplay={step.continueButtonDisplay} continueButtonText={step.continueButtonText} onContinueButtonClick={step.onContinueButtonClick} + pointerDirection={pointerDirection} /> ); } - private _renderOnboardignCard(): React.ReactNode { + private _renderOnboardingCard(): React.ReactNode { const { steps, stepIndex } = this.props; const step = steps[stepIndex]; const isLastStep = steps.length - 1 === stepIndex; diff --git a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx index 6d8007659..f83736aae 100644 --- a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx +++ b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx @@ -9,7 +9,12 @@ import { AddEthOnboardingStep } from 'ts/components/onboarding/add_eth_onboardin import { CongratsOnboardingStep } from 'ts/components/onboarding/congrats_onboarding_step'; import { InstallWalletOnboardingStep } from 'ts/components/onboarding/install_wallet_onboarding_step'; import { IntroOnboardingStep } from 'ts/components/onboarding/intro_onboarding_step'; -import { OnboardingFlow, Step } from 'ts/components/onboarding/onboarding_flow'; +import { + OnboardingFlow, + Step, + TargetPositionSettings, + FixedPositionSettings, +} from 'ts/components/onboarding/onboarding_flow'; import { SetAllowancesOnboardingStep } from 'ts/components/onboarding/set_allowances_onboarding_step'; import { UnlockWalletOnboardingStep } from 'ts/components/onboarding/unlock_wallet_onboarding_step'; import { @@ -79,56 +84,61 @@ class PlainPortalOnboardingFlow extends React.Component, - placement: 'right', shouldHideBackButton: true, shouldHideNextButton: true, }, { - target: '.wallet', + position: underMetamaskExtension, title: '0x Ecosystem Setup', content: , - placement: 'right', shouldHideBackButton: true, shouldHideNextButton: true, }, { - target: '.wallet', + position: nextToWalletPosition, title: '0x Ecosystem Account Setup', content: , - placement: 'right', shouldHideBackButton: true, continueButtonDisplay: 'enabled', }, { - target: '.wallet', + position: nextToWalletPosition, title: 'Step 1: Add ETH', content: ( ), - placement: 'right', continueButtonDisplay: this._userHasVisibleEth() ? 'enabled' : 'disabled', }, { - target: '.wallet', + position: nextToWalletPosition, title: 'Step 2: Wrap ETH', content: , - placement: 'right', continueButtonDisplay: 'enabled', }, { - target: '.wallet', + position: nextToWalletPosition, title: 'Step 2: Wrap ETH', content: , - placement: 'right', continueButtonDisplay: this._userHasVisibleWeth() ? 'enabled' : 'disabled', }, { - target: '.wallet', + position: nextToWalletPosition, title: 'Step 2: Wrap ETH', content: ( ), - placement: 'right', continueButtonDisplay: this._userHasVisibleWeth() ? 'enabled' : 'disabled', }, { - target: '.wallet', + position: nextToWalletPosition, title: 'Step 3: Unlock Tokens', content: ( ), - placement: 'right', continueButtonDisplay: this._doesUserHaveAllowancesForWethAndZrx() ? 'enabled' : 'disabled', }, { - target: '.wallet', + position: nextToWalletPosition, title: '🎉 The Ecosystem Awaits', content: , - placement: 'right', continueButtonDisplay: 'enabled', shouldHideNextButton: true, continueButtonText: 'Enter the 0x Ecosystem', -- cgit v1.2.3 From f62044c1e3f35e0985724ebc1bac3a9b23dc2c2e Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 2 Jul 2018 18:14:21 -0700 Subject: Add media file and remove stray comment --- .../ts/components/onboarding/portal_onboarding_flow.tsx | 2 -- packages/website/ts/style/media.ts | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 packages/website/ts/style/media.ts (limited to 'packages') diff --git a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx index 6d8007659..c8786da13 100644 --- a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx +++ b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx @@ -45,8 +45,6 @@ class PlainPortalOnboardingFlow extends React.Component void; public componentDidMount(): void { this._adjustStepIfShould(); - // Wait until the step is adjusted to decide whether we should show onboarding. - // setTimeout(this._autoStartOnboardingIfShould.bind(this), 1000); // If there is a route change, just close onboarding. this._unlisten = this.props.history.listen(() => this.props.updateIsRunning(false)); } diff --git a/packages/website/ts/style/media.ts b/packages/website/ts/style/media.ts new file mode 100644 index 000000000..2f8551f34 --- /dev/null +++ b/packages/website/ts/style/media.ts @@ -0,0 +1,15 @@ +import * as _ from 'lodash'; +import { css } from 'ts/style/theme'; +import { ScreenWidths } from 'ts/types'; + +const generateMediaWrapper = (screenWidth: ScreenWidths) => (...args: any[]) => css` + @media (max-width: ${screenWidth}) { + ${css.apply(css, args)}; + } +`; + +export const media = { + small: generateMediaWrapper(ScreenWidths.Sm), + medium: generateMediaWrapper(ScreenWidths.Md), + large: generateMediaWrapper(ScreenWidths.Lg), +}; -- cgit v1.2.3 From 8929543b550cad73987a795d97bbe7dee6bb0d45 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 2 Jul 2018 18:15:41 -0700 Subject: Add end comment to hotjar tracking code --- packages/website/public/index.html | 1 + 1 file changed, 1 insertion(+) (limited to 'packages') diff --git a/packages/website/public/index.html b/packages/website/public/index.html index c7a40875f..060f2c3c2 100644 --- a/packages/website/public/index.html +++ b/packages/website/public/index.html @@ -81,6 +81,7 @@ a.appendChild(r); })(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv='); + -- cgit v1.2.3 From 6fc5c0cd460cf1cb8ac8fbe86e6d2fdbaa23ffe1 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 2 Jul 2018 18:36:41 -0700 Subject: Remove unused import --- packages/website/ts/style/media.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'packages') diff --git a/packages/website/ts/style/media.ts b/packages/website/ts/style/media.ts index 2f8551f34..3c992eb9f 100644 --- a/packages/website/ts/style/media.ts +++ b/packages/website/ts/style/media.ts @@ -1,4 +1,3 @@ -import * as _ from 'lodash'; import { css } from 'ts/style/theme'; import { ScreenWidths } from 'ts/types'; -- cgit v1.2.3 From 5b64b3ea937326978b5742ec1b3692ebe5c41991 Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Mon, 2 Jul 2018 18:44:37 -0700 Subject: Improve robustness of revert reason assertions --- .../contracts/test/asset_proxy/authorizable.ts | 18 +-- packages/contracts/test/asset_proxy/proxies.ts | 16 +- packages/contracts/test/exchange/core.ts | 36 ++--- packages/contracts/test/exchange/dispatcher.ts | 8 +- packages/contracts/test/exchange/match_orders.ts | 12 +- .../contracts/test/exchange/signature_validator.ts | 10 +- packages/contracts/test/exchange/transactions.ts | 16 +- packages/contracts/test/exchange/wrapper.ts | 12 +- packages/contracts/test/libraries/lib_bytes.ts | 46 +++--- .../contracts/test/multisig/asset_proxy_owner.ts | 21 +-- .../test/multisig/multi_sig_with_time_lock.ts | 8 +- packages/contracts/test/token_registry.ts | 32 ++-- packages/contracts/test/tokens/ether_token.ts | 4 +- .../test/tokens/unlimited_allowance_token.ts | 8 +- packages/contracts/test/utils/assertions.ts | 161 +++++++++++++-------- packages/contracts/test/utils/constants.ts | 1 - .../test/utils/core_combinatorial_utils.ts | 4 +- packages/dev-utils/src/blockchain_lifecycle.ts | 22 +-- packages/migrations/artifacts/2.0.0/ZRXToken.json | 32 ++-- packages/web3-wrapper/src/index.ts | 2 +- packages/web3-wrapper/src/web3_wrapper.ts | 21 +++ 21 files changed, 269 insertions(+), 221 deletions(-) (limited to 'packages') diff --git a/packages/contracts/test/asset_proxy/authorizable.ts b/packages/contracts/test/asset_proxy/authorizable.ts index 5a0586c28..e99c6cee3 100644 --- a/packages/contracts/test/asset_proxy/authorizable.ts +++ b/packages/contracts/test/asset_proxy/authorizable.ts @@ -5,7 +5,7 @@ import * as chai from 'chai'; import { MixinAuthorizableContract } from '../../generated_contract_wrappers/mixin_authorizable'; import { artifacts } from '../utils/artifacts'; -import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { expectTransactionFailedAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; @@ -44,7 +44,7 @@ describe('Authorizable', () => { }); describe('addAuthorizedAddress', () => { it('should throw if not called by owner', async () => { - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }), RevertReason.OnlyContractOwner, ); @@ -62,7 +62,7 @@ describe('Authorizable', () => { await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }), constants.AWAIT_TRANSACTION_MINED_MS, ); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }), RevertReason.TargetAlreadyAuthorized, ); @@ -75,7 +75,7 @@ describe('Authorizable', () => { await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }), constants.AWAIT_TRANSACTION_MINED_MS, ); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { from: notOwner, }), @@ -99,7 +99,7 @@ describe('Authorizable', () => { }); it('should throw if owner attempts to remove an address that is not authorized', async () => { - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { from: owner, }), @@ -115,7 +115,7 @@ describe('Authorizable', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); const index = new BigNumber(0); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, { from: notOwner, }), @@ -128,7 +128,7 @@ describe('Authorizable', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); const index = new BigNumber(1); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, { from: owner, }), @@ -137,7 +137,7 @@ describe('Authorizable', () => { }); it('should throw if owner attempts to remove an address that is not authorized', async () => { const index = new BigNumber(0); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, { from: owner, }), @@ -156,7 +156,7 @@ describe('Authorizable', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); const address1Index = new BigNumber(0); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, { from: owner, }), diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts index fc1e53352..bf9f9bc3e 100644 --- a/packages/contracts/test/asset_proxy/proxies.ts +++ b/packages/contracts/test/asset_proxy/proxies.ts @@ -17,7 +17,7 @@ import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_pr import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy'; import { IAssetProxyContract } from '../../generated_contract_wrappers/i_asset_proxy'; import { artifacts } from '../utils/artifacts'; -import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { expectTransactionFailedAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; @@ -184,7 +184,7 @@ describe('Asset Transfer Proxies', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); // Perform a transfer; expect this to fail. - return expectRevertReasonOrAlwaysFailingTransactionAsync( + await expectTransactionFailedAsync( web3Wrapper.sendTransactionAsync({ to: erc20Proxy.address, data, @@ -205,7 +205,7 @@ describe('Asset Transfer Proxies', () => { takerAddress, amount, ); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + await expectTransactionFailedAsync( web3Wrapper.sendTransactionAsync({ to: erc20Proxy.address, data, @@ -344,7 +344,7 @@ describe('Asset Transfer Proxies', () => { erc20Proxy.address, // the ERC20 proxy does not have an ERC721 receiver amount, ); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( web3Wrapper.sendTransactionAsync({ to: erc721Proxy.address, data, @@ -369,7 +369,7 @@ describe('Asset Transfer Proxies', () => { takerAddress, amount, ); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( web3Wrapper.sendTransactionAsync({ to: erc721Proxy.address, data, @@ -393,7 +393,7 @@ describe('Asset Transfer Proxies', () => { takerAddress, amount, ); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( web3Wrapper.sendTransactionAsync({ to: erc721Proxy.address, data, @@ -421,7 +421,7 @@ describe('Asset Transfer Proxies', () => { takerAddress, amount, ); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( web3Wrapper.sendTransactionAsync({ to: erc721Proxy.address, data, @@ -442,7 +442,7 @@ describe('Asset Transfer Proxies', () => { takerAddress, amount, ); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( web3Wrapper.sendTransactionAsync({ to: erc721Proxy.address, data, diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts index db56623f9..4e70893fc 100644 --- a/packages/contracts/test/exchange/core.ts +++ b/packages/contracts/test/exchange/core.ts @@ -14,7 +14,7 @@ import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_pr import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy'; import { CancelContractEventArgs, ExchangeContract } from '../../generated_contract_wrappers/exchange'; import { artifacts } from '../utils/artifacts'; -import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { expectTransactionFailedAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; @@ -144,7 +144,7 @@ describe('Exchange core', () => { const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]); const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`; signedOrder.signature = invalidSigHex; - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), RevertReason.InvalidOrderSignature, ); @@ -153,7 +153,7 @@ describe('Exchange core', () => { it('should throw if no value is filled', async () => { signedOrder = orderFactory.newSignedOrder(); await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), RevertReason.OrderUnfillable, ); @@ -167,7 +167,7 @@ describe('Exchange core', () => { }); it('should throw if not sent by maker', async () => { - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress), RevertReason.InvalidMaker, ); @@ -178,7 +178,7 @@ describe('Exchange core', () => { makerAssetAmount: new BigNumber(0), }); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), RevertReason.OrderUnfillable, ); @@ -189,7 +189,7 @@ describe('Exchange core', () => { takerAssetAmount: new BigNumber(0), }); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), RevertReason.OrderUnfillable, ); @@ -197,7 +197,7 @@ describe('Exchange core', () => { it('should be able to cancel a full order', async () => { await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount: signedOrder.takerAssetAmount.div(2), }), @@ -222,7 +222,7 @@ describe('Exchange core', () => { it('should throw if already cancelled', async () => { await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), RevertReason.OrderUnfillable, ); @@ -232,7 +232,7 @@ describe('Exchange core', () => { signedOrder = orderFactory.newSignedOrder({ expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)), }); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress), RevertReason.OrderUnfillable, ); @@ -250,7 +250,7 @@ describe('Exchange core', () => { }); const fillTakerAssetAmount2 = new BigNumber(1); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount: fillTakerAssetAmount2, }), @@ -264,7 +264,7 @@ describe('Exchange core', () => { const orderEpoch = new BigNumber(1); await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress); const lesserOrderEpoch = new BigNumber(0); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.cancelOrdersUpToAsync(lesserOrderEpoch, makerAddress), RevertReason.InvalidNewOrderEpoch, ); @@ -273,7 +273,7 @@ describe('Exchange core', () => { it('should fail to set orderEpoch equal to existing orderEpoch', async () => { const orderEpoch = new BigNumber(1); await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress), RevertReason.InvalidNewOrderEpoch, ); @@ -363,7 +363,7 @@ describe('Exchange core', () => { expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress); // Call Exchange const takerAssetFillAmount = signedOrder.takerAssetAmount; - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), RevertReason.TransferFailed, ); @@ -386,7 +386,7 @@ describe('Exchange core', () => { expect(initialOwnerTakerAsset).to.be.bignumber.not.equal(takerAddress); // Call Exchange const takerAssetFillAmount = signedOrder.takerAssetAmount; - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), RevertReason.TransferFailed, ); @@ -409,7 +409,7 @@ describe('Exchange core', () => { expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress); // Call Exchange const takerAssetFillAmount = signedOrder.takerAssetAmount; - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), RevertReason.InvalidAmount, ); @@ -432,7 +432,7 @@ describe('Exchange core', () => { expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress); // Call Exchange const takerAssetFillAmount = signedOrder.takerAssetAmount; - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), RevertReason.InvalidAmount, ); @@ -449,7 +449,7 @@ describe('Exchange core', () => { }); // Call Exchange const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), RevertReason.RoundingError, ); @@ -475,7 +475,7 @@ describe('Exchange core', () => { expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress); // Call Exchange const takerAssetFillAmount = signedOrder.takerAssetAmount; - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }), RevertReason.LengthGreaterThan131Required, ); diff --git a/packages/contracts/test/exchange/dispatcher.ts b/packages/contracts/test/exchange/dispatcher.ts index afbf958d9..94ada1ef2 100644 --- a/packages/contracts/test/exchange/dispatcher.ts +++ b/packages/contracts/test/exchange/dispatcher.ts @@ -14,7 +14,7 @@ import { TestAssetProxyDispatcherContract, } from '../../generated_contract_wrappers/test_asset_proxy_dispatcher'; import { artifacts } from '../utils/artifacts'; -import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { expectTransactionFailedAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; @@ -129,7 +129,7 @@ describe('AssetProxyDispatcher', () => { txDefaults, ); // Register new ERC20 Transfer Proxy contract - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(newErc20TransferProxy.address, { from: owner, }), @@ -138,7 +138,7 @@ describe('AssetProxyDispatcher', () => { }); it('should throw if requesting address is not owner', async () => { - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: notOwner }), RevertReason.OnlyContractOwner, ); @@ -210,7 +210,7 @@ describe('AssetProxyDispatcher', () => { const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address); // Perform a transfer from makerAddress to takerAddress const amount = new BigNumber(10); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync( encodedAssetData, makerAddress, diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index 0d07d156f..90406415f 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -12,7 +12,7 @@ import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_pr import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy'; import { ExchangeContract } from '../../generated_contract_wrappers/exchange'; import { artifacts } from '../utils/artifacts'; -import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { expectTransactionFailedAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; @@ -602,7 +602,7 @@ describe('matchOrders', () => { // Cancel left order await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress); // Match orders - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), RevertReason.OrderUnfillable, ); @@ -627,7 +627,7 @@ describe('matchOrders', () => { // Cancel right order await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress); // Match orders - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), RevertReason.OrderUnfillable, ); @@ -650,7 +650,7 @@ describe('matchOrders', () => { feeRecipientAddress: feeRecipientAddressRight, }); // Match orders - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), RevertReason.NegativeSpreadRequired, ); @@ -673,7 +673,7 @@ describe('matchOrders', () => { feeRecipientAddress: feeRecipientAddressRight, }); // Match orders - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), // We are assuming assetData fields of the right order are the // reverse of the left order, rather than checking equality. This @@ -702,7 +702,7 @@ describe('matchOrders', () => { feeRecipientAddress: feeRecipientAddressRight, }); // Match orders - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), RevertReason.InvalidOrderSignature, ); diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index 1db7dfc6d..c44d22479 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -13,7 +13,7 @@ import { TestValidatorContract } from '../../generated_contract_wrappers/test_va import { TestWalletContract } from '../../generated_contract_wrappers/test_wallet'; import { addressUtils } from '../utils/address_utils'; import { artifacts } from '../utils/artifacts'; -import { expectRevertOrOtherErrorAsync } from '../utils/assertions'; +import { expectContractCallFailed } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { LogDecoder } from '../utils/log_decoder'; @@ -101,7 +101,7 @@ describe('MixinSignatureValidator', () => { it('should revert when signature is empty', async () => { const emptySignature = '0x'; const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( signatureValidator.publicIsValidSignature.callAsync( orderHashHex, signedOrder.makerAddress, @@ -115,7 +115,7 @@ describe('MixinSignatureValidator', () => { const unsupportedSignatureType = SignatureType.NSignatureTypes; const unsupportedSignatureHex = `0x${unsupportedSignatureType}`; const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( signatureValidator.publicIsValidSignature.callAsync( orderHashHex, signedOrder.makerAddress, @@ -128,7 +128,7 @@ describe('MixinSignatureValidator', () => { it('should revert when SignatureType=Illegal', async () => { const unsupportedSignatureHex = `0x${SignatureType.Illegal}`; const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( signatureValidator.publicIsValidSignature.callAsync( orderHashHex, signedOrder.makerAddress, @@ -155,7 +155,7 @@ describe('MixinSignatureValidator', () => { const signatureBuffer = Buffer.concat([fillerData, signatureType]); const signatureHex = ethUtil.bufferToHex(signatureBuffer); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( signatureValidator.publicIsValidSignature.callAsync( orderHashHex, signedOrder.makerAddress, diff --git a/packages/contracts/test/exchange/transactions.ts b/packages/contracts/test/exchange/transactions.ts index 4f8b49e0e..959d79517 100644 --- a/packages/contracts/test/exchange/transactions.ts +++ b/packages/contracts/test/exchange/transactions.ts @@ -11,7 +11,7 @@ import { ExchangeContract } from '../../generated_contract_wrappers/exchange'; import { ExchangeWrapperContract } from '../../generated_contract_wrappers/exchange_wrapper'; import { WhitelistContract } from '../../generated_contract_wrappers/whitelist'; import { artifacts } from '../utils/artifacts'; -import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { expectTransactionFailedAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; @@ -134,7 +134,7 @@ describe('Exchange transactions', () => { }); it('should throw if not called by specified sender', async () => { - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.executeTransactionAsync(signedTx, takerAddress), RevertReason.FailedExecution, ); @@ -177,7 +177,7 @@ describe('Exchange transactions', () => { it('should throw if the a 0x transaction with the same transactionHash has already been executed', async () => { await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.executeTransactionAsync(signedTx, senderAddress), RevertReason.InvalidTxHash, ); @@ -197,7 +197,7 @@ describe('Exchange transactions', () => { }); it('should throw if not called by specified sender', async () => { - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.executeTransactionAsync(signedTx, makerAddress), RevertReason.FailedExecution, ); @@ -205,7 +205,7 @@ describe('Exchange transactions', () => { it('should cancel the order when signed by maker and called by sender', async () => { await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, senderAddress), RevertReason.OrderUnfillable, ); @@ -250,7 +250,7 @@ describe('Exchange transactions', () => { signedOrder.signature, ); const signedFillTx = takerTransactionFactory.newSignedTransaction(fillData); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapperContract.fillOrder.sendTransactionAsync( orderWithoutExchangeAddress, takerAssetFillAmount, @@ -370,7 +370,7 @@ describe('Exchange transactions', () => { orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); const takerAssetFillAmount = signedOrder.takerAssetAmount; const salt = generatePseudoRandomSalt(); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( whitelist.fillOrderIfWhitelisted.sendTransactionAsync( orderWithoutExchangeAddress, takerAssetFillAmount, @@ -392,7 +392,7 @@ describe('Exchange transactions', () => { orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder); const takerAssetFillAmount = signedOrder.takerAssetAmount; const salt = generatePseudoRandomSalt(); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( whitelist.fillOrderIfWhitelisted.sendTransactionAsync( orderWithoutExchangeAddress, takerAssetFillAmount, diff --git a/packages/contracts/test/exchange/wrapper.ts b/packages/contracts/test/exchange/wrapper.ts index 7942f7695..69f374e46 100644 --- a/packages/contracts/test/exchange/wrapper.ts +++ b/packages/contracts/test/exchange/wrapper.ts @@ -12,7 +12,7 @@ import { ERC20ProxyContract } from '../../generated_contract_wrappers/e_r_c20_pr import { ERC721ProxyContract } from '../../generated_contract_wrappers/e_r_c721_proxy'; import { ExchangeContract } from '../../generated_contract_wrappers/exchange'; import { artifacts } from '../utils/artifacts'; -import { expectRevertReasonOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { expectTransactionFailedAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; @@ -174,7 +174,7 @@ describe('Exchange wrappers', () => { expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)), }); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress), RevertReason.OrderUnfillable, ); @@ -187,7 +187,7 @@ describe('Exchange wrappers', () => { takerAssetFillAmount: signedOrder.takerAssetAmount.div(2), }); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress), RevertReason.CompleteFillFailed, ); @@ -500,7 +500,7 @@ describe('Exchange wrappers', () => { await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress); - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts, }), @@ -703,7 +703,7 @@ describe('Exchange wrappers', () => { orderFactory.newSignedOrder(), ]; - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18), }), @@ -921,7 +921,7 @@ describe('Exchange wrappers', () => { orderFactory.newSignedOrder(), ]; - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, { makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18), }), diff --git a/packages/contracts/test/libraries/lib_bytes.ts b/packages/contracts/test/libraries/lib_bytes.ts index 963b51b8f..c80b61e19 100644 --- a/packages/contracts/test/libraries/lib_bytes.ts +++ b/packages/contracts/test/libraries/lib_bytes.ts @@ -9,7 +9,7 @@ import * as _ from 'lodash'; import { TestLibBytesContract } from '../../generated_contract_wrappers/test_lib_bytes'; import { artifacts } from '../utils/artifacts'; -import { expectRevertOrOtherErrorAsync } from '../utils/assertions'; +import { expectContractCallFailed } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; @@ -100,7 +100,7 @@ describe('LibBytes', () => { describe('popLastByte', () => { it('should revert if length is 0', async () => { - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicPopLastByte.callAsync(constants.NULL_BYTES), RevertReason.LibBytesGreaterThanZeroLengthRequired, ); @@ -116,7 +116,7 @@ describe('LibBytes', () => { describe('popLast20Bytes', () => { it('should revert if length is less than 20', async () => { - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicPopLast20Bytes.callAsync(byteArrayShorterThan20Bytes), RevertReason.LibBytesGreaterOrEqualTo20LengthRequired, ); @@ -184,7 +184,7 @@ describe('LibBytes', () => { describe('deepCopyBytes', () => { it('should revert if dest is shorter than source', async () => { - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicDeepCopyBytes.callAsync(byteArrayShorterThan32Bytes, byteArrayLongerThan32Bytes), RevertReason.LibBytesGreaterOrEqualToSourceBytesLengthRequired, ); @@ -237,7 +237,7 @@ describe('LibBytes', () => { it('should fail if the byte array is too short to hold an address', async () => { const shortByteArray = '0xabcdef'; const offset = new BigNumber(0); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadAddress.callAsync(shortByteArray, offset), RevertReason.LibBytesGreaterOrEqualTo20LengthRequired, ); @@ -245,7 +245,7 @@ describe('LibBytes', () => { it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => { const byteArray = testAddress; const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadAddress.callAsync(byteArray, badOffset), RevertReason.LibBytesGreaterOrEqualTo20LengthRequired, ); @@ -281,7 +281,7 @@ describe('LibBytes', () => { }); it('should fail if the byte array is too short to hold an address', async () => { const offset = new BigNumber(0); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicWriteAddress.callAsync(byteArrayShorterThan20Bytes, offset, testAddress), RevertReason.LibBytesGreaterOrEqualTo20LengthRequired, ); @@ -289,7 +289,7 @@ describe('LibBytes', () => { it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => { const byteArray = byteArrayLongerThan32Bytes; const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicWriteAddress.callAsync(byteArray, badOffset, testAddress), RevertReason.LibBytesGreaterOrEqualTo20LengthRequired, ); @@ -313,14 +313,14 @@ describe('LibBytes', () => { }); it('should fail if the byte array is too short to hold a bytes32', async () => { const offset = new BigNumber(0); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); }); it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => { const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadBytes32.callAsync(testBytes32, badOffset), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); @@ -356,7 +356,7 @@ describe('LibBytes', () => { }); it('should fail if the byte array is too short to hold a bytes32', async () => { const offset = new BigNumber(0); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicWriteBytes32.callAsync(byteArrayShorterThan32Bytes, offset, testBytes32), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); @@ -364,7 +364,7 @@ describe('LibBytes', () => { it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => { const byteArray = byteArrayLongerThan32Bytes; const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicWriteBytes32.callAsync(byteArray, badOffset, testBytes32), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); @@ -392,7 +392,7 @@ describe('LibBytes', () => { }); it('should fail if the byte array is too short to hold a uint256', async () => { const offset = new BigNumber(0); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); @@ -402,7 +402,7 @@ describe('LibBytes', () => { const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256); const byteArray = ethUtil.bufferToHex(testUint256AsBuffer); const badOffset = new BigNumber(testUint256AsBuffer.byteLength); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadUint256.callAsync(byteArray, badOffset), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); @@ -442,7 +442,7 @@ describe('LibBytes', () => { }); it('should fail if the byte array is too short to hold a uint256', async () => { const offset = new BigNumber(0); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicWriteUint256.callAsync(byteArrayShorterThan32Bytes, offset, testUint256), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); @@ -450,7 +450,7 @@ describe('LibBytes', () => { it('should fail if the length between the offset and end of the byte array is too short to hold a uint256', async () => { const byteArray = byteArrayLongerThan32Bytes; const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicWriteUint256.callAsync(byteArray, badOffset, testUint256), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); @@ -461,7 +461,7 @@ describe('LibBytes', () => { // AssertionError: expected promise to be rejected with an error including 'revert' but it was fulfilled with '0x08c379a0' it('should revert if byte array has a length < 4', async () => { const byteArrayLessThan4Bytes = '0x010101'; - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadBytes4.callAsync(byteArrayLessThan4Bytes, new BigNumber(0)), RevertReason.LibBytesGreaterOrEqualTo4LengthRequired, ); @@ -516,28 +516,28 @@ describe('LibBytes', () => { it('should fail if the byte array is too short to hold the length of a nested byte array', async () => { // The length of the nested array is 32 bytes. By storing less than 32 bytes, a length cannot be read. const offset = new BigNumber(0); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadBytesWithLength.callAsync(byteArrayShorterThan32Bytes, offset), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); }); it('should fail if we store a nested byte array length, without a nested byte array', async () => { const offset = new BigNumber(0); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadBytesWithLength.callAsync(testBytes32, offset), RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired, ); }); it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array', async () => { const badOffset = new BigNumber(ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadBytesWithLength.callAsync(byteArrayShorterThan32Bytes, badOffset), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); }); it('should fail if the length between the offset and end of the byte array is too short to hold the nested byte array', async () => { const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicReadBytesWithLength.callAsync(testBytes32, badOffset), RevertReason.LibBytesGreaterOrEqualTo32LengthRequired, ); @@ -649,7 +649,7 @@ describe('LibBytes', () => { it('should fail if the byte array is too short to hold the length of a nested byte array', async () => { const offset = new BigNumber(0); const emptyByteArray = ethUtil.bufferToHex(new Buffer(1)); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicWriteBytesWithLength.callAsync(emptyByteArray, offset, longData), RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired, ); @@ -657,7 +657,7 @@ describe('LibBytes', () => { it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array)', async () => { const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength)); const badOffset = new BigNumber(ethUtil.toBuffer(shortTestBytesAsBuffer).byteLength); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( libBytes.publicWriteBytesWithLength.callAsync(emptyByteArray, badOffset, shortData), RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired, ); diff --git a/packages/contracts/test/multisig/asset_proxy_owner.ts b/packages/contracts/test/multisig/asset_proxy_owner.ts index cde86dd46..16231dfcb 100644 --- a/packages/contracts/test/multisig/asset_proxy_owner.ts +++ b/packages/contracts/test/multisig/asset_proxy_owner.ts @@ -14,8 +14,9 @@ import { MixinAuthorizableContract } from '../../generated_contract_wrappers/mix import { TestAssetProxyOwnerContract } from '../../generated_contract_wrappers/test_asset_proxy_owner'; import { artifacts } from '../utils/artifacts'; import { - expectRevertOrAlwaysFailingTransactionAsync, - expectRevertOrContractCallFailedAsync, + expectContractCallFailedWithoutReasonAsync, + expectContractCreationFailedWithoutReason, + expectTransactionFailedWithoutReasonAsync, } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; @@ -108,7 +109,7 @@ describe('AssetProxyOwner', () => { }); it('should throw if a null address is included in assetProxyContracts', async () => { const assetProxyContractAddresses = [erc20Proxy.address, constants.NULL_ADDRESS]; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectContractCreationFailedWithoutReason( AssetProxyOwnerContract.deployFrom0xArtifactAsync( artifacts.AssetProxyOwner, provider, @@ -150,7 +151,7 @@ describe('AssetProxyOwner', () => { describe('registerAssetProxy', () => { it('should throw if not called by multisig', async () => { const isRegistered = true; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( testAssetProxyOwner.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, isRegistered, { from: owners[0], }), @@ -277,7 +278,7 @@ describe('AssetProxyOwner', () => { ); const log = submitTxRes.logs[0] as LogWithDecodedArgs; const txId = log.args.transactionId; - return expectRevertOrContractCallFailedAsync( + return expectContractCallFailedWithoutReasonAsync( testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(txId), ); }); @@ -312,7 +313,7 @@ describe('AssetProxyOwner', () => { ); const log = submitTxRes.logs[0] as LogWithDecodedArgs; const txId = log.args.transactionId; - return expectRevertOrContractCallFailedAsync( + return expectContractCallFailedWithoutReasonAsync( testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(txId), ); }); @@ -332,7 +333,7 @@ describe('AssetProxyOwner', () => { const log = res.logs[0] as LogWithDecodedArgs; const txId = log.args.transactionId; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, { from: owners[1], }), @@ -354,7 +355,7 @@ describe('AssetProxyOwner', () => { await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, { from: owners[1], }), @@ -376,7 +377,7 @@ describe('AssetProxyOwner', () => { await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, { from: owners[1], }), @@ -433,7 +434,7 @@ describe('AssetProxyOwner', () => { const isExecuted = tx[3]; expect(isExecuted).to.equal(true); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, { from: owners[1], }), diff --git a/packages/contracts/test/multisig/multi_sig_with_time_lock.ts b/packages/contracts/test/multisig/multi_sig_with_time_lock.ts index a746403d2..a7b99d867 100644 --- a/packages/contracts/test/multisig/multi_sig_with_time_lock.ts +++ b/packages/contracts/test/multisig/multi_sig_with_time_lock.ts @@ -8,7 +8,7 @@ import { SubmissionContractEventArgs, } from '../../generated_contract_wrappers/multi_sig_wallet_with_time_lock'; import { artifacts } from '../utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { expectTransactionFailedWithoutReasonAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { increaseTimeAndMineBlockAsync } from '../utils/increase_time'; @@ -67,7 +67,7 @@ describe('MultiSigWalletWithTimeLock', () => { }); it('should throw when not called by wallet', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }), ); }); @@ -78,7 +78,7 @@ describe('MultiSigWalletWithTimeLock', () => { const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]); const log = res.logs[0] as LogWithDecodedArgs; const txId = log.args.transactionId; - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }), ); }); @@ -147,7 +147,7 @@ describe('MultiSigWalletWithTimeLock', () => { }); it('should throw if it has enough confirmations but is not past the time lock', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }), ); }); diff --git a/packages/contracts/test/token_registry.ts b/packages/contracts/test/token_registry.ts index 32f8cdee3..7cc43be9b 100644 --- a/packages/contracts/test/token_registry.ts +++ b/packages/contracts/test/token_registry.ts @@ -7,7 +7,7 @@ import * as _ from 'lodash'; import { TokenRegistryContract } from '../generated_contract_wrappers/token_registry'; import { artifacts } from './utils/artifacts'; -import { expectRevertOrAlwaysFailingTransactionAsync } from './utils/assertions'; +import { expectTransactionFailedWithoutReasonAsync } from './utils/assertions'; import { chaiSetup } from './utils/chai_setup'; import { constants } from './utils/constants'; import { TokenRegWrapper } from './utils/token_registry_wrapper'; @@ -75,7 +75,7 @@ describe('TokenRegistry', () => { describe('addToken', () => { it('should throw when not called by owner', async () => { - return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(token1, notOwner)); + return expectTransactionFailedWithoutReasonAsync(tokenRegWrapper.addTokenAsync(token1, notOwner)); }); it('should add token metadata when called by owner', async () => { @@ -87,20 +87,18 @@ describe('TokenRegistry', () => { it('should throw if token already exists', async () => { await tokenRegWrapper.addTokenAsync(token1, owner); - return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(token1, owner)); + return expectTransactionFailedWithoutReasonAsync(tokenRegWrapper.addTokenAsync(token1, owner)); }); it('should throw if token address is null', async () => { - return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(nullToken, owner)); + return expectTransactionFailedWithoutReasonAsync(tokenRegWrapper.addTokenAsync(nullToken, owner)); }); it('should throw if name already exists', async () => { await tokenRegWrapper.addTokenAsync(token1, owner); const duplicateNameToken = _.assign({}, token2, { name: token1.name }); - return expectRevertOrAlwaysFailingTransactionAsync( - tokenRegWrapper.addTokenAsync(duplicateNameToken, owner), - ); + return expectTransactionFailedWithoutReasonAsync(tokenRegWrapper.addTokenAsync(duplicateNameToken, owner)); }); it('should throw if symbol already exists', async () => { @@ -109,7 +107,7 @@ describe('TokenRegistry', () => { symbol: token1.symbol, }); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner), ); }); @@ -136,7 +134,7 @@ describe('TokenRegistry', () => { describe('setTokenName', () => { it('should throw when not called by owner', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( tokenReg.setTokenName.sendTransactionAsync(token1.address, token2.name, { from: notOwner }), ); }); @@ -162,13 +160,13 @@ describe('TokenRegistry', () => { it('should throw if the name already exists', async () => { await tokenRegWrapper.addTokenAsync(token2, owner); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( tokenReg.setTokenName.sendTransactionAsync(token1.address, token2.name, { from: owner }), ); }); it('should throw if token does not exist', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( tokenReg.setTokenName.sendTransactionAsync(nullToken.address, token2.name, { from: owner }), ); }); @@ -176,7 +174,7 @@ describe('TokenRegistry', () => { describe('setTokenSymbol', () => { it('should throw when not called by owner', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( tokenReg.setTokenSymbol.sendTransactionAsync(token1.address, token2.symbol, { from: notOwner, }), @@ -202,7 +200,7 @@ describe('TokenRegistry', () => { it('should throw if the symbol already exists', async () => { await tokenRegWrapper.addTokenAsync(token2, owner); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( tokenReg.setTokenSymbol.sendTransactionAsync(token1.address, token2.symbol, { from: owner, }), @@ -210,7 +208,7 @@ describe('TokenRegistry', () => { }); it('should throw if token does not exist', async () => { - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( tokenReg.setTokenSymbol.sendTransactionAsync(nullToken.address, token2.symbol, { from: owner, }), @@ -221,7 +219,7 @@ describe('TokenRegistry', () => { describe('removeToken', () => { it('should throw if not called by owner', async () => { const index = new BigNumber(0); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( tokenReg.removeToken.sendTransactionAsync(token1.address, index, { from: notOwner }), ); }); @@ -240,7 +238,7 @@ describe('TokenRegistry', () => { it('should throw if token does not exist', async () => { const index = new BigNumber(0); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( tokenReg.removeToken.sendTransactionAsync(nullToken.address, index, { from: owner }), ); }); @@ -248,7 +246,7 @@ describe('TokenRegistry', () => { it('should throw if token at given index does not match address', async () => { await tokenRegWrapper.addTokenAsync(token2, owner); const incorrectIndex = new BigNumber(0); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( tokenReg.removeToken.sendTransactionAsync(token2.address, incorrectIndex, { from: owner }), ); }); diff --git a/packages/contracts/test/tokens/ether_token.ts b/packages/contracts/test/tokens/ether_token.ts index 25ef15595..a104fc915 100644 --- a/packages/contracts/test/tokens/ether_token.ts +++ b/packages/contracts/test/tokens/ether_token.ts @@ -5,7 +5,7 @@ import * as chai from 'chai'; import { WETH9Contract } from '../../generated_contract_wrappers/weth9'; import { artifacts } from '../utils/artifacts'; -import { expectInsufficientFundsAsync, expectRevertOrAlwaysFailingTransactionAsync } from '../utils/assertions'; +import { expectInsufficientFundsAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; @@ -74,7 +74,7 @@ describe('EtherToken', () => { const initEthTokenBalance = await etherToken.balanceOf.callAsync(account); const ethTokensToWithdraw = initEthTokenBalance.plus(1); - return expectRevertOrAlwaysFailingTransactionAsync( + return expectTransactionFailedWithoutReasonAsync( etherToken.withdraw.sendTransactionAsync(ethTokensToWithdraw), ); }); diff --git a/packages/contracts/test/tokens/unlimited_allowance_token.ts b/packages/contracts/test/tokens/unlimited_allowance_token.ts index 09a24950c..8a3b20d0f 100644 --- a/packages/contracts/test/tokens/unlimited_allowance_token.ts +++ b/packages/contracts/test/tokens/unlimited_allowance_token.ts @@ -5,7 +5,7 @@ import * as chai from 'chai'; import { DummyERC20TokenContract } from '../../generated_contract_wrappers/dummy_e_r_c20_token'; import { artifacts } from '../utils/artifacts'; -import { expectRevertOrOtherErrorAsync } from '../utils/assertions'; +import { expectContractCallFailed } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; @@ -54,7 +54,7 @@ describe('UnlimitedAllowanceToken', () => { it('should throw if owner has insufficient balance', async () => { const ownerBalance = await token.balanceOf.callAsync(owner); const amountToTransfer = ownerBalance.plus(1); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( token.transfer.callAsync(spender, amountToTransfer, { from: owner }), RevertReason.Erc20InsufficientBalance, ); @@ -93,7 +93,7 @@ describe('UnlimitedAllowanceToken', () => { await token.approve.sendTransactionAsync(spender, amountToTransfer, { from: owner }), constants.AWAIT_TRANSACTION_MINED_MS, ); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( token.transferFrom.callAsync(owner, spender, amountToTransfer, { from: spender, }), @@ -109,7 +109,7 @@ describe('UnlimitedAllowanceToken', () => { const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0; expect(isSpenderAllowanceInsufficient).to.be.true(); - return expectRevertOrOtherErrorAsync( + return expectContractCallFailed( token.transferFrom.callAsync(owner, spender, amountToTransfer, { from: spender, }), diff --git a/packages/contracts/test/utils/assertions.ts b/packages/contracts/test/utils/assertions.ts index baba892d3..89e90ad2f 100644 --- a/packages/contracts/test/utils/assertions.ts +++ b/packages/contracts/test/utils/assertions.ts @@ -1,108 +1,153 @@ import { RevertReason } from '@0xproject/types'; +import { logUtils } from '@0xproject/utils'; +import { NodeType } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import { TransactionReceipt, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import * as _ from 'lodash'; -import { constants } from './constants'; import { web3Wrapper } from './web3_wrapper'; const expect = chai.expect; -function _expectEitherErrorAsync(p: Promise, error1: string, error2: string): PromiseLike { - return expect(p) - .to.be.rejected() - .then(e => { - expect(e).to.satisfy( - (err: Error) => _.includes(err.message, error1) || _.includes(err.message, error2), - `expected promise to reject with error message that includes "${error1}" or "${error2}", but got: ` + - `"${e.message}"\n`, - ); - }); +// Represents the return value of a `sendTransaction` call. The Promise should +// resolve with either a transaction receipt or a transaction hash. +export type sendTransactionResult = Promise; + +async function _getGanacheOrGethError(ganacheError: string, gethError: string): Promise { + const nodeType = await web3Wrapper.getNodeTypeAsync(); + switch (nodeType) { + case NodeType.Ganache: + return ganacheError; + case NodeType.Geth: + return gethError; + default: + throw new Error(`Unknown node type: ${nodeType}`); + } +} + +async function _getInsufficientFundsErrorMessageAsync(): Promise { + return _getGanacheOrGethError("sender doesn't have enough funds", 'insufficient funds'); +} + +async function _getTransactionFailedErrorMessageAsync(): Promise { + return _getGanacheOrGethError('revert', 'always failing transaction'); +} + +async function _getContractCallFailedErrorMessageAsync(): Promise { + return _getGanacheOrGethError('revert', 'Contract call failed'); } /** * Rejects if the given Promise does not reject with an error indicating * insufficient funds. - * @param p the Promise which is expected to reject + * @param p a promise resulting from a contract call or sendTransaction call. * @returns a new Promise which will reject if the conditions are not met and * otherwise resolve with no value. */ -export function expectInsufficientFundsAsync(p: Promise): PromiseLike { - return _expectEitherErrorAsync(p, 'insufficient funds', "sender doesn't have enough funds"); +export async function expectInsufficientFundsAsync(p: Promise): Promise { + const errMessage = await _getInsufficientFundsErrorMessageAsync(); + return expect(p).to.be.rejectedWith(errMessage); } /** - * Rejects if the given Promise does not reject with a "revert" error or the - * given otherError. - * @param p the Promise which is expected to reject - * @param otherError the other error which is accepted as a valid reject error. + * Resolves if the the sendTransaction call fails with the given revert reason. + * However, since Geth does not support revert reasons for sendTransaction, this + * falls back to expectTransactionFailedWithoutReasonAsync if the backing + * Ethereum node is Geth. + * @param p a Promise resulting from a sendTransaction call + * @param reason a specific revert reason * @returns a new Promise which will reject if the conditions are not met and * otherwise resolve with no value. */ -export function expectRevertOrOtherErrorAsync(p: Promise, otherError: string): PromiseLike { - return _expectEitherErrorAsync(p, constants.REVERT, otherError); -} +export async function expectTransactionFailedAsync(p: sendTransactionResult, reason: RevertReason): Promise { + // HACK(albrow): This dummy `catch` should not be necessary, but if you + // remove it, there is an uncaught exception and the Node process will + // forcibly exit. It's possible this is a false positive in + // make-promises-safe. + p.catch(e => { + _.noop(e); + }); -/** - * Rejects if the given Promise does not reject with a "revert" or "always - * failing transaction" error. - * @param p the Promise which is expected to reject - * @returns a new Promise which will reject if the conditions are not met and - * otherwise resolve with no value. - */ -export function expectRevertOrAlwaysFailingTransactionAsync(p: Promise): PromiseLike { - return expectRevertOrOtherErrorAsync(p, 'always failing transaction'); + const nodeType = await web3Wrapper.getNodeTypeAsync(); + switch (nodeType) { + case NodeType.Ganache: + return expect(p).to.be.rejectedWith(reason); + case NodeType.Geth: + logUtils.warn( + 'WARNING: Geth does not support revert reasons for sendTransaction. This test will pass if the transaction fails for any reason.', + ); + return expectTransactionFailedWithoutReasonAsync(p); + default: + throw new Error(`Unknown node type: ${nodeType}`); + } } /** - * Rejects if at least one the following conditions is not met: - * 1) The given Promise rejects with the given revert reason. - * 2) The given Promise rejects with an error containing "always failing transaction" - * 3) The given Promise fulfills with a txReceipt that has a status of 0 or '0', indicating the transaction failed. - * 4) The given Promise fulfills with a txHash and corresponding txReceipt has a status of 0 or '0'. - * @param p the Promise which is expected to reject - * @param reason a specific revert reason + * Resolves if the transaction fails without a revert reason, or if the + * corresponding transactionReceipt has a status of 0 or '0', indicating + * failure. + * @param p a Promise resulting from a sendTransaction call * @returns a new Promise which will reject if the conditions are not met and * otherwise resolve with no value. */ -export async function expectRevertReasonOrAlwaysFailingTransactionAsync( - p: Promise, - reason: RevertReason, -): Promise { +export async function expectTransactionFailedWithoutReasonAsync(p: sendTransactionResult): Promise { return p .then(async result => { - let txReceiptStatus: string | 0 | 1 | null; - if (typeof result === 'string') { - // Result is a txHash. We need to make a web3 call to get the receipt. + let txReceiptStatus: null | string | 0 | 1; + if (_.isString(result)) { + // Result is a txHash. We need to make a web3 call to get the + // receipt, then get the status from the receipt. const txReceipt = await web3Wrapper.awaitTransactionMinedAsync(result); txReceiptStatus = txReceipt.status; } else if ('status' in result) { - // Result is a TransactionReceiptWithDecodedLogs or TransactionReceipt - // and status is a field of result. + // Result is a transaction receipt, so we can get the status + // directly. txReceiptStatus = result.status; } else { - throw new Error('Unexpected result type'); + throw new Error('Unexpected result type: ' + typeof result); } expect(_.toString(txReceiptStatus)).to.equal( '0', - 'transactionReceipt had a non-zero status, indicating success', + 'Expected transaction to fail but receipt had a non-zero status, indicating success', ); }) - .catch(err => { - expect(err.message).to.satisfy( - (msg: string) => _.includes(msg, reason) || _.includes(msg, 'always failing transaction'), - `Expected ${reason} or 'always failing transaction' but error message was ${err.message}`, - ); + .catch(async err => { + // If the promise rejects, we expect a specific error message, + // depending on the backing Ethereum node type. + const errMessage = await _getTransactionFailedErrorMessageAsync(); + expect(err.message).to.include(errMessage); }); } /** - * Rejects if the given Promise does not reject with a "revert" or "Contract - * call failed" error. - * @param p the Promise which is expected to reject + * Resolves if the the contract call fails with the given revert reason. + * @param p a Promise resulting from a contract call + * @param reason a specific revert reason + * @returns a new Promise which will reject if the conditions are not met and + * otherwise resolve with no value. + */ +export async function expectContractCallFailed(p: Promise, reason: RevertReason): Promise { + return expect(p).to.be.rejectedWith(reason); +} + +/** + * Resolves if the contract call fails without a revert reason. + * @param p a Promise resulting from a contract call + * @returns a new Promise which will reject if the conditions are not met and + * otherwise resolve with no value. + */ +export async function expectContractCallFailedWithoutReasonAsync(p: Promise): Promise { + const errMessage = await _getContractCallFailedErrorMessageAsync(); + return expect(p).to.be.rejectedWith(errMessage); +} + +/** + * Resolves if the contract creation/deployment fails without a revert reason. + * @param p a Promise resulting from a contract creation/deployment * @returns a new Promise which will reject if the conditions are not met and * otherwise resolve with no value. */ -export function expectRevertOrContractCallFailedAsync(p: Promise): PromiseLike { - return expectRevertOrOtherErrorAsync(p, 'Contract call failed'); +export async function expectContractCreationFailedWithoutReason(p: Promise): Promise { + const errMessage = await _getTransactionFailedErrorMessageAsync(); + return expect(p).to.be.rejectedWith(errMessage); } diff --git a/packages/contracts/test/utils/constants.ts b/packages/contracts/test/utils/constants.ts index 8e68f376d..7f3ad62e1 100644 --- a/packages/contracts/test/utils/constants.ts +++ b/packages/contracts/test/utils/constants.ts @@ -18,7 +18,6 @@ const TESTRPC_PRIVATE_KEYS_STRINGS = [ export const constants = { INVALID_OPCODE: 'invalid opcode', - REVERT: 'revert', TESTRPC_NETWORK_ID: 50, // Note(albrow): In practice V8 and most other engines limit the minimum // interval for setInterval to 10ms. We still set it to 0 here in order to diff --git a/packages/contracts/test/utils/core_combinatorial_utils.ts b/packages/contracts/test/utils/core_combinatorial_utils.ts index 38723d53d..8c6c83014 100644 --- a/packages/contracts/test/utils/core_combinatorial_utils.ts +++ b/packages/contracts/test/utils/core_combinatorial_utils.ts @@ -17,7 +17,7 @@ import 'make-promises-safe'; import { ExchangeContract, FillContractEventArgs } from '../../generated_contract_wrappers/exchange'; import { artifacts } from './artifacts'; -import { expectRevertReasonOrAlwaysFailingTransactionAsync } from './assertions'; +import { expectTransactionFailedAsync } from './assertions'; import { AssetWrapper } from './asset_wrapper'; import { chaiSetup } from './chai_setup'; import { constants } from './constants'; @@ -418,7 +418,7 @@ export class CoreCombinatorialUtils { fillRevertReasonIfExists: RevertReason | undefined, ): Promise { if (!_.isUndefined(fillRevertReasonIfExists)) { - return expectRevertReasonOrAlwaysFailingTransactionAsync( + return expectTransactionFailedAsync( this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }), fillRevertReasonIfExists, ); diff --git a/packages/dev-utils/src/blockchain_lifecycle.ts b/packages/dev-utils/src/blockchain_lifecycle.ts index 587332f1a..abca6d386 100644 --- a/packages/dev-utils/src/blockchain_lifecycle.ts +++ b/packages/dev-utils/src/blockchain_lifecycle.ts @@ -1,11 +1,5 @@ import { logUtils } from '@0xproject/utils'; -import { uniqueVersionIds, Web3Wrapper } from '@0xproject/web3-wrapper'; -import { includes } from 'lodash'; - -enum NodeType { - Geth = 'GETH', - Ganache = 'GANACHE', -} +import { NodeType, Web3Wrapper } from '@0xproject/web3-wrapper'; // HACK(albrow): 🐉 We have to do this so that debug.setHead works correctly. // (Geth does not seem to like debug.setHead(0), so by sending some transactions @@ -23,7 +17,7 @@ export class BlockchainLifecycle { this._snapshotIdsStack = []; } public async startAsync(): Promise { - const nodeType = await this._getNodeTypeAsync(); + const nodeType = await this._web3Wrapper.getNodeTypeAsync(); switch (nodeType) { case NodeType.Ganache: const snapshotId = await this._web3Wrapper.takeSnapshotAsync(); @@ -44,7 +38,7 @@ export class BlockchainLifecycle { } } public async revertAsync(): Promise { - const nodeType = await this._getNodeTypeAsync(); + const nodeType = await this._web3Wrapper.getNodeTypeAsync(); switch (nodeType) { case NodeType.Ganache: const snapshotId = this._snapshotIdsStack.pop() as number; @@ -61,16 +55,6 @@ export class BlockchainLifecycle { throw new Error(`Unknown node type: ${nodeType}`); } } - private async _getNodeTypeAsync(): Promise { - const version = await this._web3Wrapper.getNodeVersionAsync(); - if (includes(version, uniqueVersionIds.geth)) { - return NodeType.Geth; - } else if (includes(version, uniqueVersionIds.ganache)) { - return NodeType.Ganache; - } else { - throw new Error(`Unknown client version: ${version}`); - } - } private async _mineMinimumBlocksAsync(): Promise { logUtils.warn('WARNING: minimum block number for tests not met. Mining additional blocks...'); if (this._addresses.length === 0) { diff --git a/packages/migrations/artifacts/2.0.0/ZRXToken.json b/packages/migrations/artifacts/2.0.0/ZRXToken.json index cad596044..2078bb4d6 100644 --- a/packages/migrations/artifacts/2.0.0/ZRXToken.json +++ b/packages/migrations/artifacts/2.0.0/ZRXToken.json @@ -228,39 +228,39 @@ "evm": { "bytecode": { "linkReferences": {}, - "object": "0x60806040526b033b2e3c9fd0803ce800000060035534801561002057600080fd5b506003543360009081526020819052604090205561067b806100436000396000f3006080604052600436106100985763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde03811461009d578063095ea7b31461012757806318160ddd1461016c57806323b872dd14610193578063313ce567146101ca57806370a08231146101f557806395d89b4114610223578063a9059cbb14610238578063dd62ed3e14610269575b600080fd5b3480156100a957600080fd5b506100b261029d565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100ec5781810151838201526020016100d4565b50505050905090810190601f1680156101195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013357600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff600435166024356102d4565b604080519115158252519081900360200190f35b34801561017857600080fd5b50610181610348565b60408051918252519081900360200190f35b34801561019f57600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff6004358116906024351660443561034e565b3480156101d657600080fd5b506101df6104e8565b6040805160ff9092168252519081900360200190f35b34801561020157600080fd5b5061018173ffffffffffffffffffffffffffffffffffffffff600435166104ed565b34801561022f57600080fd5b506100b2610515565b34801561024457600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff6004351660243561054c565b34801561027557600080fd5b5061018173ffffffffffffffffffffffffffffffffffffffff60043581169060243516610617565b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260016020908152604080832033845282528083205493835290829052812054909190831180159061039b5750828110155b80156103ce575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156104db5773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81101561046d5773ffffffffffffffffffffffffffffffffffffffff851660009081526001602090815260408083203384529091529020805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506104e0565b600091505b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b336000908152602081905260408120548211801590610592575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b1561060f57336000818152602081815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3506001610342565b506000610342565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152600160209081526040808320939094168252919091522054905600a165627a7a72305820a64d50ba7ca8023b64d00c49e38afa498258fdc2e4a694ef1c57201e9a757ec10029", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH12 0x33B2E3C9FD0803CE8000000 PUSH1 0x3 SSTORE CALLVALUE DUP1 ISZERO PUSH2 0x20 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x3 SLOAD CALLER PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SSTORE PUSH2 0x67B DUP1 PUSH2 0x43 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x98 JUMPI PUSH4 0xFFFFFFFF PUSH29 0x100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 CALLDATALOAD DIV AND PUSH4 0x6FDDE03 DUP2 EQ PUSH2 0x9D JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0x127 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0x16C JUMPI DUP1 PUSH4 0x23B872DD EQ PUSH2 0x193 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x1CA JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x1F5 JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x223 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x238 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x269 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0xA9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xB2 PUSH2 0x29D JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 DUP1 DUP3 MSTORE DUP4 MLOAD DUP2 DUP4 ADD MSTORE DUP4 MLOAD SWAP2 SWAP3 DUP4 SWAP3 SWAP1 DUP4 ADD SWAP2 DUP6 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xEC JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0xD4 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x119 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x133 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x2D4 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 ISZERO ISZERO DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x178 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH2 0x348 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x19F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH1 0x44 CALLDATALOAD PUSH2 0x34E JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x1D6 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1DF PUSH2 0x4E8 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x201 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH2 0x4ED JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x22F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xB2 PUSH2 0x515 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x244 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x54C JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x275 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH2 0x617 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x11 DUP2 MSTORE PUSH32 0x30782050726F746F636F6C20546F6B656E000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE DUP2 JUMP JUMPDEST CALLER PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND DUP1 DUP6 MSTORE SWAP1 DUP4 MSTORE DUP2 DUP5 KECCAK256 DUP7 SWAP1 SSTORE DUP2 MLOAD DUP7 DUP2 MSTORE SWAP2 MLOAD SWAP4 SWAP5 SWAP1 SWAP4 SWAP1 SWAP3 PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 SWAP3 DUP3 SWAP1 SUB ADD SWAP1 LOG3 POP PUSH1 0x1 JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x3 SLOAD DUP2 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE DUP3 MSTORE DUP1 DUP4 KECCAK256 SLOAD SWAP4 DUP4 MSTORE SWAP1 DUP3 SWAP1 MSTORE DUP2 KECCAK256 SLOAD SWAP1 SWAP2 SWAP1 DUP4 GT DUP1 ISZERO SWAP1 PUSH2 0x39B JUMPI POP DUP3 DUP2 LT ISZERO JUMPDEST DUP1 ISZERO PUSH2 0x3CE JUMPI POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP4 DUP2 ADD LT ISZERO JUMPDEST ISZERO PUSH2 0x4DB JUMPI PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 DUP1 DUP3 KECCAK256 DUP1 SLOAD DUP8 ADD SWAP1 SSTORE SWAP2 DUP8 AND DUP2 MSTORE KECCAK256 DUP1 SLOAD DUP5 SWAP1 SUB SWAP1 SSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 LT ISZERO PUSH2 0x46D JUMPI PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE SWAP1 SWAP2 MSTORE SWAP1 KECCAK256 DUP1 SLOAD DUP5 SWAP1 SUB SWAP1 SSTORE JUMPDEST DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF DUP6 PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 PUSH1 0x1 SWAP2 POP PUSH2 0x4E0 JUMP JUMPDEST PUSH1 0x0 SWAP2 POP JUMPDEST POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x12 DUP2 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x3 DUP2 MSTORE PUSH32 0x5A52580000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE DUP2 JUMP JUMPDEST CALLER PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 DUP2 KECCAK256 SLOAD DUP3 GT DUP1 ISZERO SWAP1 PUSH2 0x592 JUMPI POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP3 DUP2 ADD LT ISZERO JUMPDEST ISZERO PUSH2 0x60F JUMPI CALLER PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x20 DUP2 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 DUP1 SLOAD DUP8 SWAP1 SUB SWAP1 SSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND DUP1 DUP5 MSTORE SWAP3 DUP2 SWAP1 KECCAK256 DUP1 SLOAD DUP8 ADD SWAP1 SSTORE DUP1 MLOAD DUP7 DUP2 MSTORE SWAP1 MLOAD SWAP3 SWAP4 SWAP3 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP PUSH1 0x1 PUSH2 0x342 JUMP JUMPDEST POP PUSH1 0x0 PUSH2 0x342 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 DUP3 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP4 SWAP1 SWAP5 AND DUP3 MSTORE SWAP2 SWAP1 SWAP2 MSTORE KECCAK256 SLOAD SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0xa6 0x4d POP 0xba PUSH29 0xA8023B64D00C49E38AFA498258FDC2E4A694EF1C57201E9A757EC10029 ", - "sourceMap": "753:342:0:-;;;872:6;846:32;;1022:71;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1075:11:0;;1061:10;1052:8;:20;;;;;;;;;;:34;753:342;;;;;;" + "object": "0x60806040526b033b2e3c9fd0803ce800000060035534801561002057600080fd5b506003543360009081526020819052604090205561067b806100436000396000f3006080604052600436106100985763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde03811461009d578063095ea7b31461012757806318160ddd1461016c57806323b872dd14610193578063313ce567146101ca57806370a08231146101f557806395d89b4114610223578063a9059cbb14610238578063dd62ed3e14610269575b600080fd5b3480156100a957600080fd5b506100b261029d565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100ec5781810151838201526020016100d4565b50505050905090810190601f1680156101195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013357600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff600435166024356102d4565b604080519115158252519081900360200190f35b34801561017857600080fd5b50610181610348565b60408051918252519081900360200190f35b34801561019f57600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff6004358116906024351660443561034e565b3480156101d657600080fd5b506101df6104e8565b6040805160ff9092168252519081900360200190f35b34801561020157600080fd5b5061018173ffffffffffffffffffffffffffffffffffffffff600435166104ed565b34801561022f57600080fd5b506100b2610515565b34801561024457600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff6004351660243561054c565b34801561027557600080fd5b5061018173ffffffffffffffffffffffffffffffffffffffff60043581169060243516610617565b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260016020908152604080832033845282528083205493835290829052812054909190831180159061039b5750828110155b80156103ce575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156104db5773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81101561046d5773ffffffffffffffffffffffffffffffffffffffff851660009081526001602090815260408083203384529091529020805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506104e0565b600091505b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b336000908152602081905260408120548211801590610592575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b1561060f57336000818152602081815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3506001610342565b506000610342565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152600160209081526040808320939094168252919091522054905600a165627a7a72305820d9d363d7eef4f71b2db22174233e9d08dc044f8bfd3ec76c93b896b38fefdf0b0029", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH12 0x33B2E3C9FD0803CE8000000 PUSH1 0x3 SSTORE CALLVALUE DUP1 ISZERO PUSH2 0x20 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x3 SLOAD CALLER PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SSTORE PUSH2 0x67B DUP1 PUSH2 0x43 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x98 JUMPI PUSH4 0xFFFFFFFF PUSH29 0x100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 CALLDATALOAD DIV AND PUSH4 0x6FDDE03 DUP2 EQ PUSH2 0x9D JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0x127 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0x16C JUMPI DUP1 PUSH4 0x23B872DD EQ PUSH2 0x193 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x1CA JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x1F5 JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x223 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x238 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x269 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0xA9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xB2 PUSH2 0x29D JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 DUP1 DUP3 MSTORE DUP4 MLOAD DUP2 DUP4 ADD MSTORE DUP4 MLOAD SWAP2 SWAP3 DUP4 SWAP3 SWAP1 DUP4 ADD SWAP2 DUP6 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xEC JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0xD4 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x119 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x133 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x2D4 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 ISZERO ISZERO DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x178 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH2 0x348 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x19F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH1 0x44 CALLDATALOAD PUSH2 0x34E JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x1D6 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1DF PUSH2 0x4E8 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x201 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH2 0x4ED JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x22F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xB2 PUSH2 0x515 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x244 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x54C JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x275 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH2 0x617 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x11 DUP2 MSTORE PUSH32 0x30782050726F746F636F6C20546F6B656E000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE DUP2 JUMP JUMPDEST CALLER PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND DUP1 DUP6 MSTORE SWAP1 DUP4 MSTORE DUP2 DUP5 KECCAK256 DUP7 SWAP1 SSTORE DUP2 MLOAD DUP7 DUP2 MSTORE SWAP2 MLOAD SWAP4 SWAP5 SWAP1 SWAP4 SWAP1 SWAP3 PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 SWAP3 DUP3 SWAP1 SUB ADD SWAP1 LOG3 POP PUSH1 0x1 JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x3 SLOAD DUP2 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE DUP3 MSTORE DUP1 DUP4 KECCAK256 SLOAD SWAP4 DUP4 MSTORE SWAP1 DUP3 SWAP1 MSTORE DUP2 KECCAK256 SLOAD SWAP1 SWAP2 SWAP1 DUP4 GT DUP1 ISZERO SWAP1 PUSH2 0x39B JUMPI POP DUP3 DUP2 LT ISZERO JUMPDEST DUP1 ISZERO PUSH2 0x3CE JUMPI POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP4 DUP2 ADD LT ISZERO JUMPDEST ISZERO PUSH2 0x4DB JUMPI PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 DUP1 DUP3 KECCAK256 DUP1 SLOAD DUP8 ADD SWAP1 SSTORE SWAP2 DUP8 AND DUP2 MSTORE KECCAK256 DUP1 SLOAD DUP5 SWAP1 SUB SWAP1 SSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 LT ISZERO PUSH2 0x46D JUMPI PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE SWAP1 SWAP2 MSTORE SWAP1 KECCAK256 DUP1 SLOAD DUP5 SWAP1 SUB SWAP1 SSTORE JUMPDEST DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF DUP6 PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 PUSH1 0x1 SWAP2 POP PUSH2 0x4E0 JUMP JUMPDEST PUSH1 0x0 SWAP2 POP JUMPDEST POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x12 DUP2 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x3 DUP2 MSTORE PUSH32 0x5A52580000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE DUP2 JUMP JUMPDEST CALLER PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 DUP2 KECCAK256 SLOAD DUP3 GT DUP1 ISZERO SWAP1 PUSH2 0x592 JUMPI POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP3 DUP2 ADD LT ISZERO JUMPDEST ISZERO PUSH2 0x60F JUMPI CALLER PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x20 DUP2 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 DUP1 SLOAD DUP8 SWAP1 SUB SWAP1 SSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND DUP1 DUP5 MSTORE SWAP3 DUP2 SWAP1 KECCAK256 DUP1 SLOAD DUP8 ADD SWAP1 SSTORE DUP1 MLOAD DUP7 DUP2 MSTORE SWAP1 MLOAD SWAP3 SWAP4 SWAP3 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP PUSH1 0x1 PUSH2 0x342 JUMP JUMPDEST POP PUSH1 0x0 PUSH2 0x342 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 DUP3 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP4 SWAP1 SWAP5 AND DUP3 MSTORE SWAP2 SWAP1 SWAP2 MSTORE KECCAK256 SLOAD SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0xd9 0xd3 PUSH4 0xD7EEF4F7 SHL 0x2d 0xb2 0x21 PUSH21 0x233E9D08DC044F8BFD3EC76C93B896B38FEFDF0B00 0x29 ", + "sourceMap": "750:342:3:-;;;869:6;843:32;;1019:71;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1072:11:3;;1058:10;1049:8;:20;;;;;;;;;;:34;750:342;;;;;;" }, "deployedBytecode": { "linkReferences": {}, - "object": "0x6080604052600436106100985763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde03811461009d578063095ea7b31461012757806318160ddd1461016c57806323b872dd14610193578063313ce567146101ca57806370a08231146101f557806395d89b4114610223578063a9059cbb14610238578063dd62ed3e14610269575b600080fd5b3480156100a957600080fd5b506100b261029d565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100ec5781810151838201526020016100d4565b50505050905090810190601f1680156101195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013357600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff600435166024356102d4565b604080519115158252519081900360200190f35b34801561017857600080fd5b50610181610348565b60408051918252519081900360200190f35b34801561019f57600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff6004358116906024351660443561034e565b3480156101d657600080fd5b506101df6104e8565b6040805160ff9092168252519081900360200190f35b34801561020157600080fd5b5061018173ffffffffffffffffffffffffffffffffffffffff600435166104ed565b34801561022f57600080fd5b506100b2610515565b34801561024457600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff6004351660243561054c565b34801561027557600080fd5b5061018173ffffffffffffffffffffffffffffffffffffffff60043581169060243516610617565b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260016020908152604080832033845282528083205493835290829052812054909190831180159061039b5750828110155b80156103ce575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156104db5773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81101561046d5773ffffffffffffffffffffffffffffffffffffffff851660009081526001602090815260408083203384529091529020805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506104e0565b600091505b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b336000908152602081905260408120548211801590610592575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b1561060f57336000818152602081815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3506001610342565b506000610342565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152600160209081526040808320939094168252919091522054905600a165627a7a72305820a64d50ba7ca8023b64d00c49e38afa498258fdc2e4a694ef1c57201e9a757ec10029", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x98 JUMPI PUSH4 0xFFFFFFFF PUSH29 0x100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 CALLDATALOAD DIV AND PUSH4 0x6FDDE03 DUP2 EQ PUSH2 0x9D JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0x127 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0x16C JUMPI DUP1 PUSH4 0x23B872DD EQ PUSH2 0x193 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x1CA JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x1F5 JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x223 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x238 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x269 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0xA9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xB2 PUSH2 0x29D JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 DUP1 DUP3 MSTORE DUP4 MLOAD DUP2 DUP4 ADD MSTORE DUP4 MLOAD SWAP2 SWAP3 DUP4 SWAP3 SWAP1 DUP4 ADD SWAP2 DUP6 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xEC JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0xD4 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x119 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x133 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x2D4 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 ISZERO ISZERO DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x178 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH2 0x348 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x19F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH1 0x44 CALLDATALOAD PUSH2 0x34E JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x1D6 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1DF PUSH2 0x4E8 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x201 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH2 0x4ED JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x22F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xB2 PUSH2 0x515 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x244 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x54C JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x275 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH2 0x617 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x11 DUP2 MSTORE PUSH32 0x30782050726F746F636F6C20546F6B656E000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE DUP2 JUMP JUMPDEST CALLER PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND DUP1 DUP6 MSTORE SWAP1 DUP4 MSTORE DUP2 DUP5 KECCAK256 DUP7 SWAP1 SSTORE DUP2 MLOAD DUP7 DUP2 MSTORE SWAP2 MLOAD SWAP4 SWAP5 SWAP1 SWAP4 SWAP1 SWAP3 PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 SWAP3 DUP3 SWAP1 SUB ADD SWAP1 LOG3 POP PUSH1 0x1 JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x3 SLOAD DUP2 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE DUP3 MSTORE DUP1 DUP4 KECCAK256 SLOAD SWAP4 DUP4 MSTORE SWAP1 DUP3 SWAP1 MSTORE DUP2 KECCAK256 SLOAD SWAP1 SWAP2 SWAP1 DUP4 GT DUP1 ISZERO SWAP1 PUSH2 0x39B JUMPI POP DUP3 DUP2 LT ISZERO JUMPDEST DUP1 ISZERO PUSH2 0x3CE JUMPI POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP4 DUP2 ADD LT ISZERO JUMPDEST ISZERO PUSH2 0x4DB JUMPI PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 DUP1 DUP3 KECCAK256 DUP1 SLOAD DUP8 ADD SWAP1 SSTORE SWAP2 DUP8 AND DUP2 MSTORE KECCAK256 DUP1 SLOAD DUP5 SWAP1 SUB SWAP1 SSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 LT ISZERO PUSH2 0x46D JUMPI PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE SWAP1 SWAP2 MSTORE SWAP1 KECCAK256 DUP1 SLOAD DUP5 SWAP1 SUB SWAP1 SSTORE JUMPDEST DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF DUP6 PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 PUSH1 0x1 SWAP2 POP PUSH2 0x4E0 JUMP JUMPDEST PUSH1 0x0 SWAP2 POP JUMPDEST POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x12 DUP2 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x3 DUP2 MSTORE PUSH32 0x5A52580000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE DUP2 JUMP JUMPDEST CALLER PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 DUP2 KECCAK256 SLOAD DUP3 GT DUP1 ISZERO SWAP1 PUSH2 0x592 JUMPI POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP3 DUP2 ADD LT ISZERO JUMPDEST ISZERO PUSH2 0x60F JUMPI CALLER PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x20 DUP2 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 DUP1 SLOAD DUP8 SWAP1 SUB SWAP1 SSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND DUP1 DUP5 MSTORE SWAP3 DUP2 SWAP1 KECCAK256 DUP1 SLOAD DUP8 ADD SWAP1 SSTORE DUP1 MLOAD DUP7 DUP2 MSTORE SWAP1 MLOAD SWAP3 SWAP4 SWAP3 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP PUSH1 0x1 PUSH2 0x342 JUMP JUMPDEST POP PUSH1 0x0 PUSH2 0x342 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 DUP3 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP4 SWAP1 SWAP5 AND DUP3 MSTORE SWAP2 SWAP1 SWAP2 MSTORE KECCAK256 SLOAD SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0xa6 0x4d POP 0xba PUSH29 0xA8023B64D00C49E38AFA498258FDC2E4A694EF1C57201E9A757EC10029 ", - "sourceMap": "753:342:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;923:49;;8:9:-1;5:2;;;30:1;27;20:12;5:2;923:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;923:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1087:187:1;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1087:187:1;;;;;;;;;;;;;;;;;;;;;;;;;;;846:32:0;;8:9:-1;5:2;;;30:1;27;20:12;5:2;846:32:0;;;;;;;;;;;;;;;;;;;;1066:609:3;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1066:609:3;;;;;;;;;;;;;;805:35:0;;8:9:-1;5:2;;;30:1;27;20:12;5:2;805:35:0;;;;;;;;;;;;;;;;;;;;;;;982:99:1;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;982:99:1;;;;;;;978:37:0;;8:9:-1;5:2;;;30:1;27;20:12;5:2;978:37:0;;;;125:410:1;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;125:410:1;;;;;;;;;1280:126;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1280:126:1;;;;;;;;;;;;923:49:0;;;;;;;;;;;;;;;;;;;:::o;1087:187:1:-;1168:10;1144:4;1160:19;;;:7;:19;;;;;;;;;:29;;;;;;;;;;;:38;;;1208;;;;;;;1144:4;;1160:29;;1168:10;;1208:38;;;;;;;;-1:-1:-1;1263:4:1;1087:187;;;;;:::o;846:32:0:-;;;;:::o;1066:609:3:-;1198:14;;;1161:4;1198:14;;;:7;:14;;;;;;;;1213:10;1198:26;;;;;;;;1238:15;;;;;;;;;;1161:4;;1198:26;1238:25;-1:-1:-1;1238:25:3;;;:60;;;1292:6;1279:9;:19;;1238:60;:115;;;;-1:-1:-1;1340:13:3;;;:8;:13;;;;;;;;;;;1314:22;;;:39;;1238:115;1234:435;;;1378:13;;;;:8;:13;;;;;;;;;;;:23;;;;;;1415:15;;;;;;:25;;;;;;;768:10;1458:20;;1454:95;;;1498:14;;;;;;;:7;:14;;;;;;;;1513:10;1498:26;;;;;;;:36;;;;;;;1454:95;1578:3;1562:28;;1571:5;1562:28;;;1583:6;1562:28;;;;;;;;;;;;;;;;;;1611:4;1604:11;;;;1234:435;1653:5;1646:12;;1234:435;1066:609;;;;;;:::o;805:35:0:-;838:2;805:35;:::o;982:99:1:-;1058:16;;1035:4;1058:16;;;;;;;;;;;;982:99::o;978:37:0:-;;;;;;;;;;;;;;;;;;;:::o;125:410:1:-;276:10;178:4;267:20;;;;;;;;;;;:30;-1:-1:-1;267:30:1;;;:73;;-1:-1:-1;327:13:1;;;:8;:13;;;;;;;;;;;301:22;;;:39;;267:73;263:266;;;365:10;356:8;:20;;;;;;;;;;;:30;;;;;;;:20;400:13;;;;;;;;;:23;;;;;;437:33;;;;;;;400:13;;365:10;437:33;;;;;;;;;;;-1:-1:-1;491:4:1;484:11;;263:266;-1:-1:-1;521:5:1;514:12;;1280:126;1374:15;;;;1351:4;1374:15;;;:7;:15;;;;;;;;:25;;;;;;;;;;;;;1280:126::o" + "object": "0x6080604052600436106100985763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde03811461009d578063095ea7b31461012757806318160ddd1461016c57806323b872dd14610193578063313ce567146101ca57806370a08231146101f557806395d89b4114610223578063a9059cbb14610238578063dd62ed3e14610269575b600080fd5b3480156100a957600080fd5b506100b261029d565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100ec5781810151838201526020016100d4565b50505050905090810190601f1680156101195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013357600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff600435166024356102d4565b604080519115158252519081900360200190f35b34801561017857600080fd5b50610181610348565b60408051918252519081900360200190f35b34801561019f57600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff6004358116906024351660443561034e565b3480156101d657600080fd5b506101df6104e8565b6040805160ff9092168252519081900360200190f35b34801561020157600080fd5b5061018173ffffffffffffffffffffffffffffffffffffffff600435166104ed565b34801561022f57600080fd5b506100b2610515565b34801561024457600080fd5b5061015873ffffffffffffffffffffffffffffffffffffffff6004351660243561054c565b34801561027557600080fd5b5061018173ffffffffffffffffffffffffffffffffffffffff60043581169060243516610617565b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260016020908152604080832033845282528083205493835290829052812054909190831180159061039b5750828110155b80156103ce575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156104db5773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81101561046d5773ffffffffffffffffffffffffffffffffffffffff851660009081526001602090815260408083203384529091529020805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506104e0565b600091505b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b336000908152602081905260408120548211801590610592575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b1561060f57336000818152602081815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3506001610342565b506000610342565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152600160209081526040808320939094168252919091522054905600a165627a7a72305820d9d363d7eef4f71b2db22174233e9d08dc044f8bfd3ec76c93b896b38fefdf0b0029", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x98 JUMPI PUSH4 0xFFFFFFFF PUSH29 0x100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 CALLDATALOAD DIV AND PUSH4 0x6FDDE03 DUP2 EQ PUSH2 0x9D JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0x127 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0x16C JUMPI DUP1 PUSH4 0x23B872DD EQ PUSH2 0x193 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x1CA JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x1F5 JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x223 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x238 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x269 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0xA9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xB2 PUSH2 0x29D JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 DUP1 DUP3 MSTORE DUP4 MLOAD DUP2 DUP4 ADD MSTORE DUP4 MLOAD SWAP2 SWAP3 DUP4 SWAP3 SWAP1 DUP4 ADD SWAP2 DUP6 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xEC JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0xD4 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x119 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x133 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x2D4 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 ISZERO ISZERO DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x178 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH2 0x348 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x19F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH1 0x44 CALLDATALOAD PUSH2 0x34E JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x1D6 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1DF PUSH2 0x4E8 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x201 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH2 0x4ED JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x22F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xB2 PUSH2 0x515 JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x244 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x158 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD AND PUSH1 0x24 CALLDATALOAD PUSH2 0x54C JUMP JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x275 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x181 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x4 CALLDATALOAD DUP2 AND SWAP1 PUSH1 0x24 CALLDATALOAD AND PUSH2 0x617 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x11 DUP2 MSTORE PUSH32 0x30782050726F746F636F6C20546F6B656E000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE DUP2 JUMP JUMPDEST CALLER PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND DUP1 DUP6 MSTORE SWAP1 DUP4 MSTORE DUP2 DUP5 KECCAK256 DUP7 SWAP1 SSTORE DUP2 MLOAD DUP7 DUP2 MSTORE SWAP2 MLOAD SWAP4 SWAP5 SWAP1 SWAP4 SWAP1 SWAP3 PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 SWAP3 DUP3 SWAP1 SUB ADD SWAP1 LOG3 POP PUSH1 0x1 JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x3 SLOAD DUP2 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE DUP3 MSTORE DUP1 DUP4 KECCAK256 SLOAD SWAP4 DUP4 MSTORE SWAP1 DUP3 SWAP1 MSTORE DUP2 KECCAK256 SLOAD SWAP1 SWAP2 SWAP1 DUP4 GT DUP1 ISZERO SWAP1 PUSH2 0x39B JUMPI POP DUP3 DUP2 LT ISZERO JUMPDEST DUP1 ISZERO PUSH2 0x3CE JUMPI POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP4 DUP2 ADD LT ISZERO JUMPDEST ISZERO PUSH2 0x4DB JUMPI PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 DUP1 DUP3 KECCAK256 DUP1 SLOAD DUP8 ADD SWAP1 SSTORE SWAP2 DUP8 AND DUP2 MSTORE KECCAK256 DUP1 SLOAD DUP5 SWAP1 SUB SWAP1 SSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 LT ISZERO PUSH2 0x46D JUMPI PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE SWAP1 SWAP2 MSTORE SWAP1 KECCAK256 DUP1 SLOAD DUP5 SWAP1 SUB SWAP1 SSTORE JUMPDEST DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF DUP6 PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 PUSH1 0x1 SWAP2 POP PUSH2 0x4E0 JUMP JUMPDEST PUSH1 0x0 SWAP2 POP JUMPDEST POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x12 DUP2 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x3 DUP2 MSTORE PUSH32 0x5A52580000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE DUP2 JUMP JUMPDEST CALLER PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 DUP2 KECCAK256 SLOAD DUP3 GT DUP1 ISZERO SWAP1 PUSH2 0x592 JUMPI POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP3 DUP2 ADD LT ISZERO JUMPDEST ISZERO PUSH2 0x60F JUMPI CALLER PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x20 DUP2 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 DUP1 SLOAD DUP8 SWAP1 SUB SWAP1 SSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND DUP1 DUP5 MSTORE SWAP3 DUP2 SWAP1 KECCAK256 DUP1 SLOAD DUP8 ADD SWAP1 SSTORE DUP1 MLOAD DUP7 DUP2 MSTORE SWAP1 MLOAD SWAP3 SWAP4 SWAP3 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP PUSH1 0x1 PUSH2 0x342 JUMP JUMPDEST POP PUSH1 0x0 PUSH2 0x342 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 DUP3 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP4 SWAP1 SWAP5 AND DUP3 MSTORE SWAP2 SWAP1 SWAP2 MSTORE KECCAK256 SLOAD SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0xd9 0xd3 PUSH4 0xD7EEF4F7 SHL 0x2d 0xb2 0x21 PUSH21 0x233E9D08DC044F8BFD3EC76C93B896B38FEFDF0B00 0x29 ", + "sourceMap": "750:342:3:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;920:49;;8:9:-1;5:2;;;30:1;27;20:12;5:2;920:49:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;920:49:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1087:187:0;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1087:187:0;;;;;;;;;;;;;;;;;;;;;;;;;;;843:32:3;;8:9:-1;5:2;;;30:1;27;20:12;5:2;843:32:3;;;;;;;;;;;;;;;;;;;;1066:609:2;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1066:609:2;;;;;;;;;;;;;;802:35:3;;8:9:-1;5:2;;;30:1;27;20:12;5:2;802:35:3;;;;;;;;;;;;;;;;;;;;;;;982:99:0;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;982:99:0;;;;;;;975:37:3;;8:9:-1;5:2;;;30:1;27;20:12;5:2;975:37:3;;;;125:410:0;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;125:410:0;;;;;;;;;1280:126;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1280:126:0;;;;;;;;;;;;920:49:3;;;;;;;;;;;;;;;;;;;:::o;1087:187:0:-;1168:10;1144:4;1160:19;;;:7;:19;;;;;;;;;:29;;;;;;;;;;;:38;;;1208;;;;;;;1144:4;;1160:29;;1168:10;;1208:38;;;;;;;;-1:-1:-1;1263:4:0;1087:187;;;;;:::o;843:32:3:-;;;;:::o;1066:609:2:-;1198:14;;;1161:4;1198:14;;;:7;:14;;;;;;;;1213:10;1198:26;;;;;;;;1238:15;;;;;;;;;;1161:4;;1198:26;1238:25;-1:-1:-1;1238:25:2;;;:60;;;1292:6;1279:9;:19;;1238:60;:115;;;;-1:-1:-1;1340:13:2;;;:8;:13;;;;;;;;;;;1314:22;;;:39;;1238:115;1234:435;;;1378:13;;;;:8;:13;;;;;;;;;;;:23;;;;;;1415:15;;;;;;:25;;;;;;;768:10;1458:20;;1454:95;;;1498:14;;;;;;;:7;:14;;;;;;;;1513:10;1498:26;;;;;;;:36;;;;;;;1454:95;1578:3;1562:28;;1571:5;1562:28;;;1583:6;1562:28;;;;;;;;;;;;;;;;;;1611:4;1604:11;;;;1234:435;1653:5;1646:12;;1234:435;1066:609;;;;;;:::o;802:35:3:-;835:2;802:35;:::o;982:99:0:-;1058:16;;1035:4;1058:16;;;;;;;;;;;;982:99::o;975:37:3:-;;;;;;;;;;;;;;;;;;;:::o;125:410:0:-;276:10;178:4;267:20;;;;;;;;;;;:30;-1:-1:-1;267:30:0;;;:73;;-1:-1:-1;327:13:0;;;:8;:13;;;;;;;;;;;301:22;;;:39;;267:73;263:266;;;365:10;356:8;:20;;;;;;;;;;;:30;;;;;;;:20;400:13;;;;;;;;;:23;;;;;;437:33;;;;;;;400:13;;365:10;437:33;;;;;;;;;;;-1:-1:-1;491:4:0;484:11;;263:266;-1:-1:-1;521:5:0;514:12;;1280:126;1374:15;;;;1351:4;1374:15;;;:7;:15;;;;;;;;:25;;;;;;;;;;;;;1280:126::o" } } }, "sources": { - "current/tokens/ZRXToken/ZRXToken.sol": { + "1.0.0/ERC20Token/ERC20Token_v1.sol": { "id": 0 }, - "previous/ERC20Token/ERC20Token_v1.sol": { + "1.0.0/Token/Token_v1.sol": { "id": 1 }, - "previous/Token/Token_v1.sol": { + "1.0.0/UnlimitedAllowanceToken/UnlimitedAllowanceToken_v1.sol": { "id": 2 }, - "previous/UnlimitedAllowanceToken/UnlimitedAllowanceToken_v1.sol": { + "2.0.0/tokens/ZRXToken/ZRXToken.sol": { "id": 3 } }, "sourceCodes": { - "current/tokens/ZRXToken/ZRXToken.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.4.11;\n\nimport { UnlimitedAllowanceToken_v1 as UnlimitedAllowanceToken } from \"../../../previous/UnlimitedAllowanceToken/UnlimitedAllowanceToken_v1.sol\";\n\ncontract ZRXToken is UnlimitedAllowanceToken {\n\n uint8 constant public decimals = 18;\n uint public totalSupply = 10**27; // 1 billion tokens, 18 decimal places\n string constant public name = \"0x Protocol Token\";\n string constant public symbol = \"ZRX\";\n\n function ZRXToken() {\n balances[msg.sender] = totalSupply;\n }\n}\n", - "previous/ERC20Token/ERC20Token_v1.sol": "pragma solidity ^0.4.11;\n\nimport { Token_v1 as Token } from \"../Token/Token_v1.sol\";\n\ncontract ERC20Token_v1 is Token {\n\n function transfer(address _to, uint _value) returns (bool) {\n //Default assumes totalSupply can't be over max (2^256 - 1).\n if (balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {\n balances[msg.sender] -= _value;\n balances[_to] += _value;\n Transfer(msg.sender, _to, _value);\n return true;\n } else { return false; }\n }\n\n function transferFrom(address _from, address _to, uint _value) returns (bool) {\n if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {\n balances[_to] += _value;\n balances[_from] -= _value;\n allowed[_from][msg.sender] -= _value;\n Transfer(_from, _to, _value);\n return true;\n } else { return false; }\n }\n\n function balanceOf(address _owner) constant returns (uint) {\n return balances[_owner];\n }\n\n function approve(address _spender, uint _value) returns (bool) {\n allowed[msg.sender][_spender] = _value;\n Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function allowance(address _owner, address _spender) constant returns (uint) {\n return allowed[_owner][_spender];\n }\n\n mapping (address => uint) balances;\n mapping (address => mapping (address => uint)) allowed;\n uint public totalSupply;\n}\n", - "previous/Token/Token_v1.sol": "pragma solidity ^0.4.11;\n\ncontract Token_v1 {\n\n /// @return total amount of tokens\n function totalSupply() constant returns (uint supply) {}\n\n /// @param _owner The address from which the balance will be retrieved\n /// @return The balance\n function balanceOf(address _owner) constant returns (uint balance) {}\n\n /// @notice send `_value` token to `_to` from `msg.sender`\n /// @param _to The address of the recipient\n /// @param _value The amount of token to be transferred\n /// @return Whether the transfer was successful or not\n function transfer(address _to, uint _value) returns (bool success) {}\n\n /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`\n /// @param _from The address of the sender\n /// @param _to The address of the recipient\n /// @param _value The amount of token to be transferred\n /// @return Whether the transfer was successful or not\n function transferFrom(address _from, address _to, uint _value) returns (bool success) {}\n\n /// @notice `msg.sender` approves `_addr` to spend `_value` tokens\n /// @param _spender The address of the account able to transfer the tokens\n /// @param _value The amount of wei to be approved for transfer\n /// @return Whether the approval was successful or not\n function approve(address _spender, uint _value) returns (bool success) {}\n\n /// @param _owner The address of the account owning tokens\n /// @param _spender The address of the account able to transfer the tokens\n /// @return Amount of remaining tokens allowed to spent\n function allowance(address _owner, address _spender) constant returns (uint remaining) {}\n\n event Transfer(address indexed _from, address indexed _to, uint _value);\n event Approval(address indexed _owner, address indexed _spender, uint _value);\n}\n\n", - "previous/UnlimitedAllowanceToken/UnlimitedAllowanceToken_v1.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.4.11;\n\nimport { ERC20Token_v1 as ERC20Token } from \"../ERC20Token/ERC20Token_v1.sol\";\n\ncontract UnlimitedAllowanceToken_v1 is ERC20Token {\n\n uint constant MAX_UINT = 2**256 - 1;\n\n /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.\n /// @param _from Address to transfer from.\n /// @param _to Address to transfer to.\n /// @param _value Amount to transfer.\n /// @return Success of transfer.\n function transferFrom(address _from, address _to, uint _value)\n public\n returns (bool)\n {\n uint allowance = allowed[_from][msg.sender];\n if (balances[_from] >= _value\n && allowance >= _value\n && balances[_to] + _value >= balances[_to]\n ) {\n balances[_to] += _value;\n balances[_from] -= _value;\n if (allowance < MAX_UINT) {\n allowed[_from][msg.sender] -= _value;\n }\n Transfer(_from, _to, _value);\n return true;\n } else {\n return false;\n }\n }\n}\n" + "1.0.0/ERC20Token/ERC20Token_v1.sol": "pragma solidity ^0.4.11;\n\nimport { Token_v1 as Token } from \"../Token/Token_v1.sol\";\n\ncontract ERC20Token_v1 is Token {\n\n function transfer(address _to, uint _value) returns (bool) {\n //Default assumes totalSupply can't be over max (2^256 - 1).\n if (balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {\n balances[msg.sender] -= _value;\n balances[_to] += _value;\n Transfer(msg.sender, _to, _value);\n return true;\n } else { return false; }\n }\n\n function transferFrom(address _from, address _to, uint _value) returns (bool) {\n if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {\n balances[_to] += _value;\n balances[_from] -= _value;\n allowed[_from][msg.sender] -= _value;\n Transfer(_from, _to, _value);\n return true;\n } else { return false; }\n }\n\n function balanceOf(address _owner) constant returns (uint) {\n return balances[_owner];\n }\n\n function approve(address _spender, uint _value) returns (bool) {\n allowed[msg.sender][_spender] = _value;\n Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function allowance(address _owner, address _spender) constant returns (uint) {\n return allowed[_owner][_spender];\n }\n\n mapping (address => uint) balances;\n mapping (address => mapping (address => uint)) allowed;\n uint public totalSupply;\n}\n", + "1.0.0/Token/Token_v1.sol": "pragma solidity ^0.4.11;\n\ncontract Token_v1 {\n\n /// @return total amount of tokens\n function totalSupply() constant returns (uint supply) {}\n\n /// @param _owner The address from which the balance will be retrieved\n /// @return The balance\n function balanceOf(address _owner) constant returns (uint balance) {}\n\n /// @notice send `_value` token to `_to` from `msg.sender`\n /// @param _to The address of the recipient\n /// @param _value The amount of token to be transferred\n /// @return Whether the transfer was successful or not\n function transfer(address _to, uint _value) returns (bool success) {}\n\n /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`\n /// @param _from The address of the sender\n /// @param _to The address of the recipient\n /// @param _value The amount of token to be transferred\n /// @return Whether the transfer was successful or not\n function transferFrom(address _from, address _to, uint _value) returns (bool success) {}\n\n /// @notice `msg.sender` approves `_addr` to spend `_value` tokens\n /// @param _spender The address of the account able to transfer the tokens\n /// @param _value The amount of wei to be approved for transfer\n /// @return Whether the approval was successful or not\n function approve(address _spender, uint _value) returns (bool success) {}\n\n /// @param _owner The address of the account owning tokens\n /// @param _spender The address of the account able to transfer the tokens\n /// @return Amount of remaining tokens allowed to spent\n function allowance(address _owner, address _spender) constant returns (uint remaining) {}\n\n event Transfer(address indexed _from, address indexed _to, uint _value);\n event Approval(address indexed _owner, address indexed _spender, uint _value);\n}\n\n", + "1.0.0/UnlimitedAllowanceToken/UnlimitedAllowanceToken_v1.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.4.11;\n\nimport { ERC20Token_v1 as ERC20Token } from \"../ERC20Token/ERC20Token_v1.sol\";\n\ncontract UnlimitedAllowanceToken_v1 is ERC20Token {\n\n uint constant MAX_UINT = 2**256 - 1;\n\n /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.\n /// @param _from Address to transfer from.\n /// @param _to Address to transfer to.\n /// @param _value Amount to transfer.\n /// @return Success of transfer.\n function transferFrom(address _from, address _to, uint _value)\n public\n returns (bool)\n {\n uint allowance = allowed[_from][msg.sender];\n if (balances[_from] >= _value\n && allowance >= _value\n && balances[_to] + _value >= balances[_to]\n ) {\n balances[_to] += _value;\n balances[_from] -= _value;\n if (allowance < MAX_UINT) {\n allowed[_from][msg.sender] -= _value;\n }\n Transfer(_from, _to, _value);\n return true;\n } else {\n return false;\n }\n }\n}\n", + "2.0.0/tokens/ZRXToken/ZRXToken.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.4.11;\n\nimport { UnlimitedAllowanceToken_v1 as UnlimitedAllowanceToken } from \"../../../1.0.0/UnlimitedAllowanceToken/UnlimitedAllowanceToken_v1.sol\";\n\ncontract ZRXToken is UnlimitedAllowanceToken {\n\n uint8 constant public decimals = 18;\n uint public totalSupply = 10**27; // 1 billion tokens, 18 decimal places\n string constant public name = \"0x Protocol Token\";\n string constant public symbol = \"ZRX\";\n\n function ZRXToken() {\n balances[msg.sender] = totalSupply;\n }\n}\n" }, - "sourceTreeHashHex": "0xbaaa4c45ee7e505106ec3f265920d9be632c2dec05ba8ea8e7e7404805ee62a5", + "sourceTreeHashHex": "0xde47979523dda114901886ad7b4f9f43f0f3ccf10556e2b56d29370f0bc74d1d", "compiler": { "name": "solc", "version": "soljson-v0.4.24+commit.e67f0147.js", @@ -283,4 +283,4 @@ } }, "networks": {} -} +} \ No newline at end of file diff --git a/packages/web3-wrapper/src/index.ts b/packages/web3-wrapper/src/index.ts index b14fa7406..66ef0a784 100644 --- a/packages/web3-wrapper/src/index.ts +++ b/packages/web3-wrapper/src/index.ts @@ -1,2 +1,2 @@ -export { Web3Wrapper, uniqueVersionIds } from './web3_wrapper'; +export { Web3Wrapper, uniqueVersionIds, NodeType } from './web3_wrapper'; export { Web3WrapperErrors } from './types'; diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts index 6ea69883c..e4df31def 100644 --- a/packages/web3-wrapper/src/web3_wrapper.ts +++ b/packages/web3-wrapper/src/web3_wrapper.ts @@ -31,6 +31,12 @@ export const uniqueVersionIds = { ganache: 'EthereumJS TestRPC', }; +// NodeType represents the type of the backing Ethereum node. +export enum NodeType { + Geth = 'GETH', + Ganache = 'GANACHE', +} + /** * A wrapper around the Web3.js 0.x library that provides a consistent, clean promise-based interface. */ @@ -489,6 +495,21 @@ export class Web3Wrapper { public async setHeadAsync(blockNumber: number): Promise { await this._sendRawPayloadAsync({ method: 'debug_setHead', params: [this._web3.toHex(blockNumber)] }); } + /** + * Returns either NodeType.Geth or NodeType.Ganache depending on the type of + * the backing Ethereum node. Throws for any other type of node. This + * function caches the result and so subsequent calls are fast. + */ + public async getNodeTypeAsync(): Promise { + const version = await this.getNodeVersionAsync(); + if (_.includes(version, uniqueVersionIds.geth)) { + return NodeType.Geth; + } else if (_.includes(version, uniqueVersionIds.ganache)) { + return NodeType.Ganache; + } else { + throw new Error(`Unknown client version: ${version}`); + } + } private async _sendRawPayloadAsync(payload: Partial): Promise { const sendAsync = this._web3.currentProvider.sendAsync.bind(this._web3.currentProvider); const payloadWithDefaults = { -- cgit v1.2.3 From f2af6e4b3ae71abdd068a88bd5d686970649fe8d Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 3 Jul 2018 01:51:59 -0700 Subject: Add optional onClick to Link simple menu item --- packages/website/ts/components/ui/simple_menu.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/ui/simple_menu.tsx b/packages/website/ts/components/ui/simple_menu.tsx index c1cab07bd..74b8ef6ae 100644 --- a/packages/website/ts/components/ui/simple_menu.tsx +++ b/packages/website/ts/components/ui/simple_menu.tsx @@ -65,10 +65,15 @@ export const CopyAddressSimpleMenuItem: React.StatelessComponent = () => { +export interface GoToAccountManagementSimpleMenuItemProps { + onClick?: () => void; +} +export const GoToAccountManagementSimpleMenuItem: React.StatelessComponent< + GoToAccountManagementSimpleMenuItemProps +> = ({ onClick }) => { return ( - + ); }; -- cgit v1.2.3 From afbfc8ba1c8d4bf812e3087db50c6a9dd786be79 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 3 Jul 2018 09:06:29 -0700 Subject: Implement clickaway for wallet menu on mobile --- packages/website/ts/components/ui/drop_down.tsx | 32 +++++++++++++++--------- packages/website/ts/components/wallet/wallet.tsx | 6 +++-- 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/ui/drop_down.tsx b/packages/website/ts/components/ui/drop_down.tsx index c21c69993..4d5caef08 100644 --- a/packages/website/ts/components/ui/drop_down.tsx +++ b/packages/website/ts/components/ui/drop_down.tsx @@ -7,14 +7,20 @@ const DEFAULT_STYLE = { fontSize: 14, }; -interface DropDownProps { +export enum DropdownMouseEvent { + Hover = 'hover', + Click = 'click', +} + +export interface DropDownProps { activeNode: React.ReactNode; popoverContent: React.ReactNode; anchorOrigin: MaterialUIPosition; targetOrigin: MaterialUIPosition; style?: React.CSSProperties; zDepth?: number; - shouldWaitForClickToActivate?: boolean; + activateEvent?: DropdownMouseEvent; + closeEvent?: DropdownMouseEvent; } interface DropDownState { @@ -26,7 +32,8 @@ export class DropDown extends React.Component { public static defaultProps: Partial = { style: DEFAULT_STYLE, zDepth: 1, - shouldWaitForClickToActivate: false, + activateEvent: DropdownMouseEvent.Hover, + closeEvent: DropdownMouseEvent.Hover, }; private _isHovering: boolean; private _popoverCloseCheckIntervalId: number; @@ -67,7 +74,7 @@ export class DropDown extends React.Component { anchorOrigin={this.props.anchorOrigin} targetOrigin={this.props.targetOrigin} onRequestClose={this._closePopover.bind(this)} - useLayerForClickAway={false} + useLayerForClickAway={this.props.closeEvent === DropdownMouseEvent.Click} animated={false} zDepth={this.props.zDepth} > @@ -83,7 +90,7 @@ export class DropDown extends React.Component { ); } private _onActiveNodeClick(event: React.FormEvent): void { - if (this.props.shouldWaitForClickToActivate) { + if (this.props.activateEvent === DropdownMouseEvent.Click) { this.setState({ isDropDownOpen: true, anchorEl: event.currentTarget, @@ -92,28 +99,29 @@ export class DropDown extends React.Component { } private _onHover(event: React.FormEvent): void { this._isHovering = true; - if (!this.props.shouldWaitForClickToActivate) { + if (this.props.activateEvent === DropdownMouseEvent.Hover) { this._checkIfShouldOpenPopover(event); } } + private _onHoverOff(): void { + this._isHovering = false; + } private _checkIfShouldOpenPopover(event: React.FormEvent): void { if (this.state.isDropDownOpen) { return; // noop } - this.setState({ isDropDownOpen: true, anchorEl: event.currentTarget, }); } - private _onHoverOff(): void { - this._isHovering = false; - } private _checkIfShouldClosePopover(): void { - if (!this.state.isDropDownOpen || this._isHovering) { + if (!this.state.isDropDownOpen) { return; // noop } - this._closePopover(); + if (this.props.closeEvent === DropdownMouseEvent.Hover && !this._isHovering) { + this._closePopover(); + } } private _closePopover(): void { this.setState({ diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 875e6e78d..b891f873a 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -10,7 +10,7 @@ import firstBy = require('thenby'); import { Blockchain } from 'ts/blockchain'; import { AccountConnection } from 'ts/components/ui/account_connection'; import { Container } from 'ts/components/ui/container'; -import { DropDown } from 'ts/components/ui/drop_down'; +import { DropDown, DropdownMouseEvent } from 'ts/components/ui/drop_down'; import { IconButton } from 'ts/components/ui/icon_button'; import { Identicon } from 'ts/components/ui/identicon'; import { Island } from 'ts/components/ui/island'; @@ -194,6 +194,7 @@ export class Wallet extends React.Component { ); } private _renderConnectedHeaderRows(): React.ReactElement<{}> { + const isMobile = this.props.screenWidth === ScreenWidths.Sm; const userAddress = this.props.userAddress; const accountState = this._getAccountState(); const main = ( @@ -234,7 +235,8 @@ export class Wallet extends React.Component { anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} targetOrigin={{ horizontal: 'right', vertical: 'top' }} zDepth={1} - shouldWaitForClickToActivate={true} + activateEvent={DropdownMouseEvent.Click} + closeEvent={isMobile ? DropdownMouseEvent.Click : DropdownMouseEvent.Hover} /> ); return ( -- cgit v1.2.3 From 2d30c290e9d5420ef6ec9b622ebddf3995239ebc Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 3 Jul 2018 09:22:52 -0700 Subject: Remove InstallPrompt --- .../ts/components/top_bar/install_prompt.tsx | 59 ---------------------- .../ts/components/top_bar/provider_display.tsx | 2 - 2 files changed, 61 deletions(-) delete mode 100644 packages/website/ts/components/top_bar/install_prompt.tsx (limited to 'packages') diff --git a/packages/website/ts/components/top_bar/install_prompt.tsx b/packages/website/ts/components/top_bar/install_prompt.tsx deleted file mode 100644 index 8d1a9c48a..000000000 --- a/packages/website/ts/components/top_bar/install_prompt.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import RaisedButton from 'material-ui/RaisedButton'; -import * as React from 'react'; - -import { colors } from 'ts/style/colors'; -import { constants } from 'ts/utils/constants'; - -export interface InstallPromptProps { - onToggleLedgerDialog: () => void; -} - -export const InstallPrompt: React.StatelessComponent = ({ onToggleLedgerDialog }) => { - return ( -
-
- Choose a wallet: -
-
- -
-
-
or
-
-
-
-
Connect to a ledger hardware wallet
-
- -
-
- -
-
-
-
- ); -}; diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx index 74f9beedb..46a32a238 100644 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ b/packages/website/ts/components/top_bar/provider_display.tsx @@ -6,7 +6,6 @@ import Lock from 'material-ui/svg-icons/action/lock'; import * as React from 'react'; import { Blockchain } from 'ts/blockchain'; -import { InstallPrompt } from 'ts/components/top_bar/install_prompt'; import { AccountConnection } from 'ts/components/ui/account_connection'; import { Container } from 'ts/components/ui/container'; import { DropDown } from 'ts/components/ui/drop_down'; @@ -81,7 +80,6 @@ export class ProviderDisplay extends React.Component ); case AccountState.Disconnected: - return ; case AccountState.Locked: case AccountState.Loading: default: -- cgit v1.2.3 From c5fcea1dbd5e64e72eb5cf360558de9f9b886a16 Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Tue, 3 Jul 2018 10:40:54 -0700 Subject: Actually cache node type in web3-wrapper --- packages/web3-wrapper/src/web3_wrapper.ts | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'packages') diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts index e4df31def..c2754a13e 100644 --- a/packages/web3-wrapper/src/web3_wrapper.ts +++ b/packages/web3-wrapper/src/web3_wrapper.ts @@ -49,6 +49,7 @@ export class Web3Wrapper { private _web3: Web3; private _txDefaults: Partial; private _jsonRpcRequestId: number; + private _nodeType: NodeType | undefined; /** * Check if an address is a valid Ethereum address * @param address Address to check @@ -501,10 +502,15 @@ export class Web3Wrapper { * function caches the result and so subsequent calls are fast. */ public async getNodeTypeAsync(): Promise { + if (!_.isUndefined(this._nodeType)) { + return this._nodeType; + } const version = await this.getNodeVersionAsync(); if (_.includes(version, uniqueVersionIds.geth)) { + this._nodeType = NodeType.Geth; return NodeType.Geth; } else if (_.includes(version, uniqueVersionIds.ganache)) { + this._nodeType = NodeType.Ganache; return NodeType.Ganache; } else { throw new Error(`Unknown client version: ${version}`); -- cgit v1.2.3 From d2ebf4a7772070e3ec255d0551de8c9f2822d4c3 Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Tue, 3 Jul 2018 10:49:35 -0700 Subject: Add TransactionReceiptStatus type to ethereum-types --- packages/contracts/test/utils/assertions.ts | 4 ++-- packages/ethereum-types/src/index.ts | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/contracts/test/utils/assertions.ts b/packages/contracts/test/utils/assertions.ts index 89e90ad2f..c8031c8a1 100644 --- a/packages/contracts/test/utils/assertions.ts +++ b/packages/contracts/test/utils/assertions.ts @@ -2,7 +2,7 @@ import { RevertReason } from '@0xproject/types'; import { logUtils } from '@0xproject/utils'; import { NodeType } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; -import { TransactionReceipt, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; +import { TransactionReceipt, TransactionReceiptStatus, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import * as _ from 'lodash'; import { web3Wrapper } from './web3_wrapper'; @@ -93,7 +93,7 @@ export async function expectTransactionFailedAsync(p: sendTransactionResult, rea export async function expectTransactionFailedWithoutReasonAsync(p: sendTransactionResult): Promise { return p .then(async result => { - let txReceiptStatus: null | string | 0 | 1; + let txReceiptStatus: TransactionReceiptStatus; if (_.isString(result)) { // Result is a txHash. We need to make a web3 call to get the // receipt, then get the status from the receipt. diff --git a/packages/ethereum-types/src/index.ts b/packages/ethereum-types/src/index.ts index 499c84327..f4d445e3b 100644 --- a/packages/ethereum-types/src/index.ts +++ b/packages/ethereum-types/src/index.ts @@ -215,6 +215,8 @@ export interface TxDataPayable extends TxData { value?: BigNumber; } +export type TransactionReceiptStatus = null | string | 0 | 1; + export interface TransactionReceipt { blockHash: string; blockNumber: number; @@ -222,7 +224,7 @@ export interface TransactionReceipt { transactionIndex: number; from: string; to: string; - status: null | string | 0 | 1; + status: TransactionReceiptStatus; cumulativeGasUsed: number; gasUsed: number; contractAddress: string | null; -- cgit v1.2.3 From ce1542da4fbab26d589f07f006fb5328a28bb9dd Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Tue, 3 Jul 2018 10:59:45 -0700 Subject: Update CHANGELOG.json for ethereum-types and web3-wrapper --- packages/ethereum-types/CHANGELOG.json | 4 ++++ packages/web3-wrapper/CHANGELOG.json | 10 ++++++++++ 2 files changed, 14 insertions(+) (limited to 'packages') diff --git a/packages/ethereum-types/CHANGELOG.json b/packages/ethereum-types/CHANGELOG.json index ad532062f..351e9c23f 100644 --- a/packages/ethereum-types/CHANGELOG.json +++ b/packages/ethereum-types/CHANGELOG.json @@ -5,6 +5,10 @@ { "note": "Add `TraceParams` interface for `debug_traceTransaction` parameters", "pr": 675 + }, + { + "note": "Add `TransactionReceiptStatus` type", + "pr": 812 } ] }, diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json index 624ad7151..f8b1dab85 100644 --- a/packages/web3-wrapper/CHANGELOG.json +++ b/packages/web3-wrapper/CHANGELOG.json @@ -1,4 +1,14 @@ [ + { + "timestamp": 1529397769, + "version": "0.7.2", + "changes": [ + { + "note": "Add `getNodeTypeAsync` method", + "pr": 812 + } + ] + }, { "timestamp": 1529397769, "version": "0.7.1", -- cgit v1.2.3 From c30b42434a8999356d7537e50c88ea96481e8c60 Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 3 Jul 2018 11:31:40 -0700 Subject: Fix linting --- packages/website/ts/components/onboarding/onboarding_flow.tsx | 3 +-- packages/website/ts/components/onboarding/portal_onboarding_flow.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/onboarding/onboarding_flow.tsx b/packages/website/ts/components/onboarding/onboarding_flow.tsx index 9abbc1c82..c2b4a4ca7 100644 --- a/packages/website/ts/components/onboarding/onboarding_flow.tsx +++ b/packages/website/ts/components/onboarding/onboarding_flow.tsx @@ -1,13 +1,12 @@ -import * as _ from 'lodash'; import * as React from 'react'; import { Placement, Popper, PopperChildrenProps } from 'react-popper'; import { OnboardingCard } from 'ts/components/onboarding/onboarding_card'; -import { PointerDirection } from 'ts/components/ui/pointer'; import { ContinueButtonDisplay, OnboardingTooltip } from 'ts/components/onboarding/onboarding_tooltip'; import { Animation } from 'ts/components/ui/animation'; import { Container } from 'ts/components/ui/container'; import { Overlay } from 'ts/components/ui/overlay'; +import { PointerDirection } from 'ts/components/ui/pointer'; import { zIndex } from 'ts/style/z_index'; export interface FixedPositionSettings { diff --git a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx index 573196547..b7c5a9f64 100644 --- a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx +++ b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx @@ -10,10 +10,10 @@ import { CongratsOnboardingStep } from 'ts/components/onboarding/congrats_onboar import { InstallWalletOnboardingStep } from 'ts/components/onboarding/install_wallet_onboarding_step'; import { IntroOnboardingStep } from 'ts/components/onboarding/intro_onboarding_step'; import { + FixedPositionSettings, OnboardingFlow, Step, TargetPositionSettings, - FixedPositionSettings, } from 'ts/components/onboarding/onboarding_flow'; import { SetAllowancesOnboardingStep } from 'ts/components/onboarding/set_allowances_onboarding_step'; import { UnlockWalletOnboardingStep } from 'ts/components/onboarding/unlock_wallet_onboarding_step'; -- cgit v1.2.3 From 32c25a20341964498c3594758aa02908c98dbfc0 Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 3 Jul 2018 11:48:34 -0700 Subject: Persist whether onboarding is open or close across refreshes --- packages/website/ts/redux/store.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/website/ts/redux/store.ts b/packages/website/ts/redux/store.ts index 0d0e6cea1..2672e3f61 100644 --- a/packages/website/ts/redux/store.ts +++ b/packages/website/ts/redux/store.ts @@ -13,9 +13,11 @@ export const store: ReduxStore = createStore( ); store.subscribe( _.throttle(() => { + const state = store.getState(); // Persisted state stateStorage.saveState({ - hasPortalOnboardingBeenClosed: store.getState().hasPortalOnboardingBeenClosed, + hasPortalOnboardingBeenClosed: state.hasPortalOnboardingBeenClosed, + isPortalOnboardingShowing: state.isPortalOnboardingShowing, }); }, ONE_SECOND), ); -- cgit v1.2.3 From dc956020ef7c6d3f1880263700422b31253c8da3 Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Tue, 3 Jul 2018 12:55:05 -0700 Subject: Move NodeType caching out of web3-wrapper and into our internal code --- packages/contracts/test/utils/assertions.ts | 10 ++++++++-- packages/dev-utils/src/blockchain_lifecycle.ts | 12 ++++++++++-- packages/web3-wrapper/src/web3_wrapper.ts | 9 +-------- 3 files changed, 19 insertions(+), 12 deletions(-) (limited to 'packages') diff --git a/packages/contracts/test/utils/assertions.ts b/packages/contracts/test/utils/assertions.ts index c8031c8a1..112a470f6 100644 --- a/packages/contracts/test/utils/assertions.ts +++ b/packages/contracts/test/utils/assertions.ts @@ -9,12 +9,16 @@ import { web3Wrapper } from './web3_wrapper'; const expect = chai.expect; +let nodeType: NodeType | undefined; + // Represents the return value of a `sendTransaction` call. The Promise should // resolve with either a transaction receipt or a transaction hash. export type sendTransactionResult = Promise; async function _getGanacheOrGethError(ganacheError: string, gethError: string): Promise { - const nodeType = await web3Wrapper.getNodeTypeAsync(); + if (_.isUndefined(nodeType)) { + nodeType = await web3Wrapper.getNodeTypeAsync(); + } switch (nodeType) { case NodeType.Ganache: return ganacheError; @@ -68,7 +72,9 @@ export async function expectTransactionFailedAsync(p: sendTransactionResult, rea _.noop(e); }); - const nodeType = await web3Wrapper.getNodeTypeAsync(); + if (_.isUndefined(nodeType)) { + nodeType = await web3Wrapper.getNodeTypeAsync(); + } switch (nodeType) { case NodeType.Ganache: return expect(p).to.be.rejectedWith(reason); diff --git a/packages/dev-utils/src/blockchain_lifecycle.ts b/packages/dev-utils/src/blockchain_lifecycle.ts index abca6d386..9bd65ee5d 100644 --- a/packages/dev-utils/src/blockchain_lifecycle.ts +++ b/packages/dev-utils/src/blockchain_lifecycle.ts @@ -1,5 +1,6 @@ import { logUtils } from '@0xproject/utils'; import { NodeType, Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as _ from 'lodash'; // HACK(albrow): 🐉 We have to do this so that debug.setHead works correctly. // (Geth does not seem to like debug.setHead(0), so by sending some transactions @@ -12,12 +13,13 @@ export class BlockchainLifecycle { private _web3Wrapper: Web3Wrapper; private _snapshotIdsStack: number[]; private _addresses: string[] = []; + private _nodeType: NodeType | undefined; constructor(web3Wrapper: Web3Wrapper) { this._web3Wrapper = web3Wrapper; this._snapshotIdsStack = []; } public async startAsync(): Promise { - const nodeType = await this._web3Wrapper.getNodeTypeAsync(); + const nodeType = await this._getNodeTypeAsync(); switch (nodeType) { case NodeType.Ganache: const snapshotId = await this._web3Wrapper.takeSnapshotAsync(); @@ -38,7 +40,7 @@ export class BlockchainLifecycle { } } public async revertAsync(): Promise { - const nodeType = await this._web3Wrapper.getNodeTypeAsync(); + const nodeType = await this._getNodeTypeAsync(); switch (nodeType) { case NodeType.Ganache: const snapshotId = this._snapshotIdsStack.pop() as number; @@ -76,4 +78,10 @@ export class BlockchainLifecycle { } logUtils.warn('Done mining the minimum number of blocks.'); } + private async _getNodeTypeAsync(): Promise { + if (_.isUndefined(this._nodeType)) { + this._nodeType = await this._web3Wrapper.getNodeTypeAsync(); + } + return this._nodeType; + } } diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts index c2754a13e..b79ade278 100644 --- a/packages/web3-wrapper/src/web3_wrapper.ts +++ b/packages/web3-wrapper/src/web3_wrapper.ts @@ -49,7 +49,6 @@ export class Web3Wrapper { private _web3: Web3; private _txDefaults: Partial; private _jsonRpcRequestId: number; - private _nodeType: NodeType | undefined; /** * Check if an address is a valid Ethereum address * @param address Address to check @@ -498,19 +497,13 @@ export class Web3Wrapper { } /** * Returns either NodeType.Geth or NodeType.Ganache depending on the type of - * the backing Ethereum node. Throws for any other type of node. This - * function caches the result and so subsequent calls are fast. + * the backing Ethereum node. Throws for any other type of node. */ public async getNodeTypeAsync(): Promise { - if (!_.isUndefined(this._nodeType)) { - return this._nodeType; - } const version = await this.getNodeVersionAsync(); if (_.includes(version, uniqueVersionIds.geth)) { - this._nodeType = NodeType.Geth; return NodeType.Geth; } else if (_.includes(version, uniqueVersionIds.ganache)) { - this._nodeType = NodeType.Ganache; return NodeType.Ganache; } else { throw new Error(`Unknown client version: ${version}`); -- cgit v1.2.3