aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/components/eth_wrappers.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts/components/eth_wrappers.tsx')
-rw-r--r--packages/website/ts/components/eth_wrappers.tsx353
1 files changed, 353 insertions, 0 deletions
diff --git a/packages/website/ts/components/eth_wrappers.tsx b/packages/website/ts/components/eth_wrappers.tsx
new file mode 100644
index 000000000..58b73b11c
--- /dev/null
+++ b/packages/website/ts/components/eth_wrappers.tsx
@@ -0,0 +1,353 @@
+import {ZeroEx} from '0x.js';
+import BigNumber from 'bignumber.js';
+import * as _ from 'lodash';
+import Divider from 'material-ui/Divider';
+import {colors} from 'material-ui/styles';
+import {
+ Table,
+ TableBody,
+ TableHeader,
+ TableHeaderColumn,
+ TableRow,
+ TableRowColumn,
+} from 'material-ui/Table';
+import * as moment from 'moment';
+import * as React from 'react';
+import {Blockchain} from 'ts/blockchain';
+import {EthWethConversionButton} from 'ts/components/eth_weth_conversion_button';
+import {Dispatcher} from 'ts/redux/dispatcher';
+import {
+ OutdatedWrappedEtherByNetworkId,
+ Side,
+ Token,
+ TokenByAddress,
+ TokenState,
+ TokenStateByAddress,
+} from 'ts/types';
+import {configs} from 'ts/utils/configs';
+import {constants} from 'ts/utils/constants';
+
+const PRECISION = 5;
+const DATE_FORMAT = 'D/M/YY';
+const LIGHT_GRAY = '#A5A5A5';
+const ICON_DIMENSION = 40;
+const ETHER_ICON_PATH = '/images/ether.png';
+const OUTDATED_WETH_ICON_PATH = '/images/wrapped_eth_gray.png';
+
+interface OutdatedWETHAddressToIsStateLoaded {
+ [address: string]: boolean;
+}
+interface OutdatedWETHStateByAddress {
+ [address: string]: TokenState;
+}
+
+interface EthWrappersProps {
+ networkId: number;
+ blockchain: Blockchain;
+ dispatcher: Dispatcher;
+ tokenByAddress: TokenByAddress;
+ tokenStateByAddress: TokenStateByAddress;
+ userAddress: string;
+ userEtherBalance: BigNumber;
+}
+
+interface EthWrappersState {
+ outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded;
+ outdatedWETHStateByAddress: OutdatedWETHStateByAddress;
+}
+
+export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersState> {
+ constructor(props: EthWrappersProps) {
+ super(props);
+ const outdatedWETHAddresses = this.getOutdatedWETHAddresses();
+ const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
+ const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
+ _.each(outdatedWETHAddresses, outdatedWETHAddress => {
+ outdatedWETHAddressToIsStateLoaded[outdatedWETHAddress] = false;
+ outdatedWETHStateByAddress[outdatedWETHAddress] = {
+ balance: new BigNumber(0),
+ allowance: new BigNumber(0),
+ };
+ });
+ this.state = {
+ outdatedWETHAddressToIsStateLoaded,
+ outdatedWETHStateByAddress,
+ };
+ }
+ public componentDidMount() {
+ window.scrollTo(0, 0);
+ // tslint:disable-next-line:no-floating-promises
+ this.fetchOutdatedWETHStateAsync();
+ }
+ public render() {
+ const tokens = _.values(this.props.tokenByAddress);
+ const etherToken = _.find(tokens, {symbol: 'WETH'});
+ const etherTokenState = this.props.tokenStateByAddress[etherToken.address];
+ const wethBalance = ZeroEx.toUnitAmount(etherTokenState.balance, 18);
+ const isBidirectional = true;
+ return (
+ <div className="clearfix lg-px4 md-px4 sm-px2" style={{minHeight: 600}}>
+ <div className="relative">
+ <h3>ETH Wrapper</h3>
+ <div className="absolute" style={{top: 0, right: 0}}>
+ <a
+ target="_blank"
+ href="https://weth.io/"
+ style={{color: LIGHT_GRAY}}
+ >
+ <div className="flex">
+ <div>About Wrapped ETH</div>
+ <div className="pl1">
+ <i className="zmdi zmdi-open-in-new" />
+ </div>
+ </div>
+ </a>
+ </div>
+ </div>
+ <Divider />
+ <div>
+ <div className="py2">
+ Wrap ETH into an ERC20-compliant Ether token. 1 ETH = 1 WETH.
+ </div>
+ <div>
+ <Table
+ selectable={false}
+ style={{backgroundColor: colors.grey50}}
+ >
+ <TableHeader displaySelectAll={false} adjustForCheckbox={false}>
+ <TableRow>
+ <TableHeaderColumn>ETH Token</TableHeaderColumn>
+ <TableHeaderColumn>Balance</TableHeaderColumn>
+ <TableHeaderColumn className="center">
+ {this.renderActionColumnTitle(isBidirectional)}
+ </TableHeaderColumn>
+ </TableRow>
+ </TableHeader>
+ <TableBody displayRowCheckbox={false}>
+ <TableRow key="ETH">
+ <TableRowColumn className="py1">
+ <div className="flex">
+ <img
+ style={{width: ICON_DIMENSION, height: ICON_DIMENSION}}
+ src={ETHER_ICON_PATH}
+ />
+ <div className="mt2 ml2 sm-hide xs-hide">
+ Ether
+ </div>
+ </div>
+ </TableRowColumn>
+ <TableRowColumn>
+ {this.props.userEtherBalance.toFixed(PRECISION)} ETH
+ </TableRowColumn>
+ <TableRowColumn>
+ <EthWethConversionButton
+ isOutdatedWrappedEther={false}
+ direction={Side.deposit}
+ ethToken={etherToken}
+ ethTokenState={etherTokenState}
+ dispatcher={this.props.dispatcher}
+ blockchain={this.props.blockchain}
+ userEtherBalance={this.props.userEtherBalance}
+ />
+ </TableRowColumn>
+ </TableRow>
+ <TableRow key="WETH">
+ <TableRowColumn className="py1">
+ <div className="flex">
+ <img
+ style={{width: ICON_DIMENSION, height: ICON_DIMENSION}}
+ src={constants.iconUrlBySymbol.WETH}
+ />
+ <div className="mt2 ml2 sm-hide xs-hide">
+ Wrapped Ether
+ </div>
+ </div>
+ </TableRowColumn>
+ <TableRowColumn>
+ {wethBalance.toFixed(PRECISION)} WETH
+ </TableRowColumn>
+ <TableRowColumn>
+ <EthWethConversionButton
+ isOutdatedWrappedEther={false}
+ direction={Side.receive}
+ ethToken={etherToken}
+ ethTokenState={etherTokenState}
+ dispatcher={this.props.dispatcher}
+ blockchain={this.props.blockchain}
+ userEtherBalance={this.props.userEtherBalance}
+ />
+ </TableRowColumn>
+ </TableRow>
+ </TableBody>
+ </Table>
+ </div>
+ </div>
+ <div>
+ <h4>Outdated WETH</h4>
+ <Divider />
+ <div className="pt2" style={{lineHeight: 1.5}}>
+ The{' '}
+ <a
+ href="https://blog.0xproject.com/canonical-weth-a9aa7d0279dd"
+ target="_blank"
+ >
+ canonical WETH
+ </a> contract is updated when necessary.
+ Unwrap outdated WETH in order to
 retrieve your ETH and move it
+ to the updated WETH token.
+ </div>
+ <div>
+ <Table
+ selectable={false}
+ style={{backgroundColor: colors.grey50}}
+ >
+ <TableHeader displaySelectAll={false} adjustForCheckbox={false}>
+ <TableRow>
+ <TableHeaderColumn>WETH Version</TableHeaderColumn>
+ <TableHeaderColumn>Balance</TableHeaderColumn>
+ <TableHeaderColumn className="center">
+ {this.renderActionColumnTitle(!isBidirectional)}
+ </TableHeaderColumn>
+ </TableRow>
+ </TableHeader>
+ <TableBody displayRowCheckbox={false}>
+ {this.renderOutdatedWeths(etherToken, etherTokenState)}
+ </TableBody>
+ </Table>
+ </div>
+ </div>
+ </div>
+ );
+ }
+ private renderActionColumnTitle(isBidirectional: boolean) {
+ let iconClass = 'zmdi-long-arrow-right';
+ let leftSymbol = 'WETH';
+ let rightSymbol = 'ETH';
+ if (isBidirectional) {
+ iconClass = 'zmdi-swap';
+ leftSymbol = 'ETH';
+ rightSymbol = 'WETH';
+ }
+ return (
+ <div className="flex mx-auto" style={{width: 85}}>
+ <div style={{paddingTop: 3}}>{leftSymbol}</div>
+ <div className="px1">
+ <i
+ style={{fontSize: 18}}
+ className={`zmdi ${iconClass}`}
+ />
+ </div>
+ <div style={{paddingTop: 3}}>{rightSymbol}</div>
+ </div>
+ );
+ }
+ private renderOutdatedWeths(etherToken: Token, etherTokenState: TokenState) {
+ const rows = _.map(configs.outdatedWrappedEthers,
+ (outdatedWETHByNetworkId: OutdatedWrappedEtherByNetworkId) => {
+ const outdatedWETH = outdatedWETHByNetworkId[this.props.networkId];
+ const timestampMsRange = outdatedWETH.timestampMsRange;
+ let dateRange: string;
+ if (!_.isUndefined(timestampMsRange)) {
+ const startMoment = moment(timestampMsRange.startTimestampMs);
+ const endMoment = moment(timestampMsRange.endTimestampMs);
+ dateRange = `${startMoment.format(DATE_FORMAT)}-${endMoment.format(DATE_FORMAT)}`;
+ } else {
+ dateRange = '-';
+ }
+ const outdatedEtherToken = {
+ ...etherToken,
+ address: outdatedWETH.address,
+ };
+ const isStateLoaded = this.state.outdatedWETHAddressToIsStateLoaded[outdatedWETH.address];
+ const outdatedEtherTokenState = this.state.outdatedWETHStateByAddress[outdatedWETH.address];
+ const balanceInEthIfExists = isStateLoaded ?
+ ZeroEx.toUnitAmount(outdatedEtherTokenState.balance, 18).toFixed(PRECISION) :
+ undefined;
+ const onConversionSuccessful = this.onOutdatedConversionSuccessfulAsync.bind(this, outdatedWETH.address);
+ return (
+ <TableRow key={`weth-${outdatedWETH.address}`}>
+ <TableRowColumn className="py1">
+ <div className="flex">
+ <img
+ style={{width: ICON_DIMENSION, height: ICON_DIMENSION}}
+ src={OUTDATED_WETH_ICON_PATH}
+ />
+ <div className="mt2 ml2 sm-hide xs-hide">
+ {dateRange}
+ </div>
+ </div>
+ </TableRowColumn>
+ <TableRowColumn>
+ {isStateLoaded ?
+ `${balanceInEthIfExists} WETH` :
+ <i className="zmdi zmdi-spinner zmdi-hc-spin" />
+ }
+ </TableRowColumn>
+ <TableRowColumn>
+ <EthWethConversionButton
+ isDisabled={!isStateLoaded}
+ isOutdatedWrappedEther={true}
+ direction={Side.receive}
+ ethToken={outdatedEtherToken}
+ ethTokenState={outdatedEtherTokenState}
+ dispatcher={this.props.dispatcher}
+ blockchain={this.props.blockchain}
+ userEtherBalance={this.props.userEtherBalance}
+ onConversionSuccessful={onConversionSuccessful}
+ />
+ </TableRowColumn>
+ </TableRow>
+ );
+ });
+ return rows;
+ }
+ private async onOutdatedConversionSuccessfulAsync(outdatedWETHAddress: string) {
+ this.setState({
+ outdatedWETHAddressToIsStateLoaded: {
+ ...this.state.outdatedWETHAddressToIsStateLoaded,
+ [outdatedWETHAddress]: false,
+ },
+ });
+ const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
+ this.props.userAddress, outdatedWETHAddress,
+ );
+ this.setState({
+ outdatedWETHAddressToIsStateLoaded: {
+ ...this.state.outdatedWETHAddressToIsStateLoaded,
+ [outdatedWETHAddress]: true,
+ },
+ outdatedWETHStateByAddress: {
+ ...this.state.outdatedWETHStateByAddress,
+ [outdatedWETHAddress]: {
+ balance,
+ allowance,
+ },
+ },
+ });
+ }
+ private async fetchOutdatedWETHStateAsync() {
+ const outdatedWETHAddresses = this.getOutdatedWETHAddresses();
+ const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
+ const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
+ for (const address of outdatedWETHAddresses) {
+ const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
+ this.props.userAddress, address,
+ );
+ outdatedWETHStateByAddress[address] = {
+ balance,
+ allowance,
+ };
+ outdatedWETHAddressToIsStateLoaded[address] = true;
+ }
+ this.setState({
+ outdatedWETHStateByAddress,
+ outdatedWETHAddressToIsStateLoaded,
+ });
+ }
+ private getOutdatedWETHAddresses(): string[] {
+ const outdatedWETHAddresses = _.map(configs.outdatedWrappedEthers, outdatedWrappedEther => {
+ return outdatedWrappedEther[this.props.networkId].address;
+ });
+ return outdatedWETHAddresses;
+ }
+} // tslint:disable:max-file-line-count