diff --git a/src/bridge/Bridge.js b/src/bridge/Bridge.js index efcc8b32c..a962d227c 100644 --- a/src/bridge/Bridge.js +++ b/src/bridge/Bridge.js @@ -80,7 +80,8 @@ class Bridge extends React.Component { pointCursor: Maybe.Nothing(), pointCache: {}, // txn - txnHashCursor: Maybe.Nothing() + txnHashCursor: Maybe.Nothing(), + txnConfirmations: {} } this.pushRoute = this.pushRoute.bind(this) @@ -95,6 +96,7 @@ class Bridge extends React.Component { this.setAuthMnemonic = this.setAuthMnemonic.bind(this) this.setPointCursor = this.setPointCursor.bind(this) this.setTxnHashCursor = this.setTxnHashCursor.bind(this) + this.setTxnConfirmations = this.setTxnConfirmations.bind(this) this.setNetworkSeedCache = this.setNetworkSeedCache.bind(this) this.addToPointCache = this.addToPointCache.bind(this) } @@ -234,6 +236,12 @@ class Bridge extends React.Component { this.setState({ txnHashCursor }) } + setTxnConfirmations(txnHash, txnConfirmations) { + this.setState((prevState, _) => + ({txnConfirmations: { ...prevState.txnConfirmations, + [txnHash]: txnConfirmations}})) + } + render() { const { routeCrumbs, @@ -248,6 +256,7 @@ class Bridge extends React.Component { pointCursor, pointCache, txnHashCursor, + txnConfirmations, web3, contracts } = this.state @@ -300,7 +309,9 @@ class Bridge extends React.Component { setNetworkSeedCache= { this.setNetworkSeedCache } // txn setTxnHashCursor={ this.setTxnHashCursor } - txnHashCursor={ txnHashCursor } /> + txnHashCursor={ txnHashCursor } + setTxnConfirmations={ this.setTxnConfirmations } + txnConfirmations={ txnConfirmations } />
diff --git a/src/bridge/components/StatelessTransaction.js b/src/bridge/components/StatelessTransaction.js index 527d3c946..0e1541d27 100644 --- a/src/bridge/components/StatelessTransaction.js +++ b/src/bridge/components/StatelessTransaction.js @@ -85,7 +85,7 @@ class StatelessTransaction extends React.Component { submit(){ const { props, state } = this - sendSignedTransaction(props.web3.value, state.stx) + sendSignedTransaction(props.web3.value, state.stx, props.setTxnConfirmations) .then(sent => { props.setTxnHashCursor(sent) props.popRoute() diff --git a/src/bridge/lib/txn.js b/src/bridge/lib/txn.js index 48f3b34d9..1a9cc7da2 100644 --- a/src/bridge/lib/txn.js +++ b/src/bridge/lib/txn.js @@ -137,7 +137,7 @@ const signTransaction = async config => { setStx(Just(stx)) } -const sendSignedTransaction = (web3, stx) => { +const sendSignedTransaction = (web3, stx, confirmationCb) => { const txn = stx.matchWith({ Just: (tx) => tx.value, Nothing: () => { @@ -155,6 +155,10 @@ const sendSignedTransaction = (web3, stx) => { .on('receipt', txn => { resolve(Just(Ok(txn.transactionHash))) }) + .on('confirmation', (confirmationNum, txn) => { + confirmationCb(txn.transactionHash, confirmationNum + 1) + resolve(Just(Ok(txn.transactionHash))) + }) .on('error', err => { reject(Just(Error(err.message))) }) diff --git a/src/bridge/views/AcceptTransfer.js b/src/bridge/views/AcceptTransfer.js index 2e4d423d4..2095397e9 100644 --- a/src/bridge/views/AcceptTransfer.js +++ b/src/bridge/views/AcceptTransfer.js @@ -126,6 +126,7 @@ class AcceptTransfer extends React.Component { walletHdPath={props.walletHdPath} networkType={props.networkType} setTxnHashCursor={props.setTxnHashCursor} + setTxnConfirmations={props.setTxnConfirmations} popRoute={props.popRoute} pushRoute={props.pushRoute} // Other diff --git a/src/bridge/views/CancelTransfer.js b/src/bridge/views/CancelTransfer.js index e005499be..acacd9866 100644 --- a/src/bridge/views/CancelTransfer.js +++ b/src/bridge/views/CancelTransfer.js @@ -87,6 +87,7 @@ class CancelTransfer extends React.Component { walletHdPath={props.walletHdPath} networkType={props.networkType} setTxnHashCursor={props.setTxnHashCursor} + setTxnConfirmations={props.setTxnConfirmations} popRoute={props.popRoute} pushRoute={props.pushRoute} // Other diff --git a/src/bridge/views/CreateGalaxy.js b/src/bridge/views/CreateGalaxy.js index ebc96f613..28d734cd3 100644 --- a/src/bridge/views/CreateGalaxy.js +++ b/src/bridge/views/CreateGalaxy.js @@ -212,6 +212,7 @@ class CreateGalaxy extends React.Component { walletHdPath={props.walletHdPath} networkType={props.networkType} setTxnHashCursor={props.setTxnHashCursor} + setTxnConfirmations={props.setTxnConfirmations} popRoute={props.popRoute} pushRoute={props.pushRoute} // Other diff --git a/src/bridge/views/IssueChild.js b/src/bridge/views/IssueChild.js index b94e5b529..8a5ef3332 100644 --- a/src/bridge/views/IssueChild.js +++ b/src/bridge/views/IssueChild.js @@ -303,6 +303,7 @@ class IssueChild extends React.Component { walletHdPath={props.walletHdPath} networkType={props.networkType} setTxnHashCursor={props.setTxnHashCursor} + setTxnConfirmations={props.setTxnConfirmations} popRoute={props.popRoute} pushRoute={props.pushRoute} // Other diff --git a/src/bridge/views/SentTransaction.js b/src/bridge/views/SentTransaction.js index 4a82b334d..ccd9405d3 100644 --- a/src/bridge/views/SentTransaction.js +++ b/src/bridge/views/SentTransaction.js @@ -1,3 +1,4 @@ +import Maybe from 'folktale/maybe' import React from 'react' import { Row, Col, H1, H3, P, Warning, Anchor } from '../components/Base' import { Button } from '../components/Base' @@ -6,55 +7,100 @@ import { ROUTE_NAMES } from '../lib/router' import { BRIDGE_ERROR, renderTxnError } from '../lib/error' import { NETWORK_NAMES } from '../lib/network' -const Success = (props) => { - - const esvisible = - props.networkType === NETWORK_NAMES.ROPSTEN || - props.networkType === NETWORK_NAMES.MAINNET - - const esdomain = - props.networkType === NETWORK_NAMES.ROPSTEN - ? "ropsten.etherscan.io" - : "etherscan.io" - - const esmessage = - esvisible === true - ? "If you’d like to keep track of it, click the Etherscan link below." - : '' - - const esanchor = - esvisible === false - ?
- : - {'View on Etherscan ↗'} - - return ( - - -

{ 'Your Transaction was Sent' }

+class Success extends React.Component { + + constructor(props) { + super(props) + + this.state = { + pending: '.', + interval: null + } + } + + componentDidMount() { + const nextDot = {'.': '..', + '..': '...', + '...': '.'} + + const interval = setInterval(() => { + this.setState(({ pending }) => ({pending: nextDot[pending]})) + }, 1000) + this.setState({interval: interval}) + } + + componentWillUnmount() { + clearInterval(this.state.interval) + } + + render() { + + const { props, state } = this + const { networkType, hash, txnConfirmations } = props + const { pending } = state + + const esvisible = + networkType === NETWORK_NAMES.ROPSTEN || + networkType === NETWORK_NAMES.MAINNET + + const esdomain = + networkType === NETWORK_NAMES.ROPSTEN + ? "ropsten.etherscan.io" + : "etherscan.io" + + const esmessage = + esvisible === true + ? "If you’d like to keep track of it, click the Etherscan link below." + : '' -

- { - `We sent your transaction to the chain. It can take some time to + const esanchor = + esvisible === false + ? null + : + {'View on Etherscan ↗'} + + + const confirmations = Maybe.fromNullable(txnConfirmations[hash]).getOrElse(0) + + const requiredConfirmations = 1 + + const status = confirmations < requiredConfirmations ? + `Pending${pending}` : `Confirmed! (x${confirmations} confirmations)!` + + return ( + + +

{ 'Your Transaction was Sent' }

+ +

+ { + `We sent your transaction to the chain. It can take some time to execute, especially if the network is busy. ${esmessage}` - } -

+ } +

-

{ 'Transaction Hash' }

-

- { props.hash } -

+

{ 'Transaction Hash' }

+

+ { hash } +

- { esanchor } +

{ 'Transaction Status' }

+

+ { status } +

+

+ { esanchor } +

- -
- ) + + + ) + } } const Failure = (props) => @@ -76,7 +122,7 @@ const Failure = (props) => const SentTransaction = (props) => { - const { web3, txnHashCursor, networkType, popRoute, pushRoute } = props + const { web3, txnHashCursor, networkType, popRoute, pushRoute, txnConfirmations} = props const { setPointCursor, pointCursor } = props const promptKeyfile = props.routeData && props.routeData.promptKeyfile @@ -97,6 +143,7 @@ const SentTransaction = (props) => { }) diff --git a/src/bridge/views/SetKeys.js b/src/bridge/views/SetKeys.js index 8efe7263d..bea67392f 100644 --- a/src/bridge/views/SetKeys.js +++ b/src/bridge/views/SetKeys.js @@ -194,6 +194,7 @@ class SetKeys extends React.Component { walletHdPath={props.walletHdPath} networkType={props.networkType} setTxnHashCursor={props.setTxnHashCursor} + setTxnConfirmations={props.setTxnConfirmations} popRoute={props.popRoute} pushRoute={props.pushRoute} // Tx diff --git a/src/bridge/views/SetProxy.js b/src/bridge/views/SetProxy.js index 3da633645..37c9ca694 100644 --- a/src/bridge/views/SetProxy.js +++ b/src/bridge/views/SetProxy.js @@ -162,6 +162,7 @@ class SetProxy extends React.Component { walletHdPath={props.walletHdPath} networkType={props.networkType} setTxnHashCursor={props.setTxnHashCursor} + setTxnConfirmations={props.setTxnConfirmations} popRoute={props.popRoute} pushRoute={props.pushRoute} // Other diff --git a/src/bridge/views/Transfer.js b/src/bridge/views/Transfer.js index 03ed0136c..66cb2f3af 100644 --- a/src/bridge/views/Transfer.js +++ b/src/bridge/views/Transfer.js @@ -132,6 +132,7 @@ class Transfer extends React.Component { walletHdPath={props.walletHdPath} networkType={props.networkType} setTxnHashCursor={props.setTxnHashCursor} + setTxnConfirmations={props.setTxnConfirmations} popRoute={props.popRoute} pushRoute={props.pushRoute} // Checks