diff --git a/src/bridge/components/StatelessTransaction.js b/src/bridge/components/StatelessTransaction.js index e6b4a985b..527d3c946 100644 --- a/src/bridge/components/StatelessTransaction.js +++ b/src/bridge/components/StatelessTransaction.js @@ -1,244 +1,426 @@ -import { Nothing } from 'folktale/maybe' +import { Nothing, Just } from 'folktale/maybe' import React from 'react' import { Code, H3 } from './Base' import { Button } from './Base' import { CheckboxButton, Input, InnerLabel } from './Base' +import { Warning } from '../components/Base' -import { renderSignedTx, signTransaction } from '../lib/txn' +import { addressFromSecp256k1Public } from '../lib/wallet' +import { BRIDGE_ERROR } from '../lib/error' +import { ROUTE_NAMES } from '../lib/router' -const StatelessTransaction = props => { - const { web3, gasPrice, gasLimit, nonce, chainId } = props - const { setNonce, setChainId, setGasLimit, setGasPrice, showGasDetails, toggleGasDetails } = props - const { txn, stx, createUnsignedTxn } = props - const { canSign, canGenerate, canApprove } = props - const { setUserApproval, userApproval } = props - const { canSend, handleSubmit } = props +import { + sendSignedTransaction, + fromWei, + renderSignedTx, + signTransaction + } from '../lib/txn' + +class StatelessTransaction extends React.Component { + + constructor(props) { + super(props) + + this.state = { + gasPrice: '5', + gasLimit: '600000', + showGasDetails: false, + userApproval: false, + chainId: '', + nonce: '', + stx: Nothing(), + txn: Nothing(), + txError: Nothing(), + } + + this.createUnsignedTxn = this.createUnsignedTxn.bind(this) + this.submit = this.submit.bind(this) + this.setUserApproval = this.setUserApproval.bind(this) + this.setTxn = this.setTxn.bind(this) + this.setStx = this.setStx.bind(this) + this.sendTxn = this.sendTxn.bind(this) + this.setNonce = this.setNonce.bind(this) + this.setChainId = this.setChainId.bind(this) + this.setGasPrice = this.setGasPrice.bind(this) + this.setGasLimit = this.setGasLimit.bind(this) + this.rangeChange = this.rangeChange.bind(this) + this.toggleGasDetails = this.toggleGasDetails.bind(this) + } + + componentDidMount() { + const { props } = this + + const addr = props.wallet.matchWith({ + Just: wal => addressFromSecp256k1Public(wal.value.publicKey), + Nothing: () => { + throw BRIDGE_ERROR.MISSING_WALLET + } + }) + + props.web3.matchWith({ + Nothing: () => {}, + Just: (w3) => { + const validWeb3 = w3.value + + const getTxMetadata = [ + validWeb3.eth.getTransactionCount(addr), + validWeb3.eth.net.getId(), + validWeb3.eth.getGasPrice() + ]; + + Promise.all(getTxMetadata).then(r => { + const txMetadata = { + nonce: r[0], + chainId: r[1], + gasPrice: fromWei(r[2], 'gwei'), + }; + + this.setState({...txMetadata}) + + }) + } + }); + } + + submit(){ + const { props, state } = this + sendSignedTransaction(props.web3.value, state.stx) + .then(sent => { + props.setTxnHashCursor(sent) + props.popRoute() + + if (props.networkSeed) { + props.setNetworkSeedCache(props.networkSeed) + props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION, {promptKeyfile: true}) + } else { + props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION) + } + }) + .catch(err => { + if (err.map) { + this.setState({ txError: err.map(val => val.merge()) }) + } else { + this.setState({ txError: err }) + } + }) + } + + setUserApproval(){ + const {state} = this + this.setState({ userApproval: !state.userApproval }) + } + + toggleGasDetails() { + this.setState({ + showGasDetails: !this.state.showGasDetails + }) + } + + setStx(stx){ + this.setState({ + stx, + userApproval: false, + }) + } + + setTxn(txn){ + this.setState({ txn }) + } + + createUnsignedTxn() { + const txn = this.props.createUnsignedTxn() + + this.setState({ txn }) + } + + clearTxn() { + this.setState({ + userApproval: false, + txn: Nothing(), + stx: Nothing(), + }) + } + + setNonce(nonce){ + this.setState({ nonce }) + this.clearStx() + } + + setChainId(chainId){ + this.setState({ chainId }) + this.clearStx() + } + + setGasPrice(gasPrice) { + this.setState({ gasPrice }) + this.clearStx() + } + + rangeChange(e) { + this.setGasPrice(e.target.value); + } + + setGasLimit(gasLimit){ + this.setState({ gasLimit }) + this.clearStx() + } + + clearStx() { + this.setState({ + userApproval: false, + stx: Nothing(), + }) + } // TODO: Investigate - // setState doesn't seem to work in SetProxy/handleSubmit; + // setState doesn't seem to work in SetProxy/submit; // - TypeError: Cannot read property 'updater' of undefined // so just modifying the DOM manually here. (https://imgur.com/a/i0Qsyq1) - const handleRangeChange = (e) => { - setGasPrice(e.target.value); - } - - const sendTxn = (e) => { + sendTxn(e) { e.target.setAttribute("disabled", true); let spinner = e.target.querySelectorAll('.btn-spinner')[0]; spinner.classList.remove('hide'); - handleSubmit() - } - - const generateButtonColor = - Nothing.hasInstance(txn) - ? 'blue' - : 'green' - - const signerButtonColor = - Nothing.hasInstance(stx) - ? 'blue' - : 'green' - - const generateTxnButton = - - - const unsignedTxnDisplay = txn.matchWith({ - Nothing: _ => '', - Just: tx => - -

- { 'Unsigned Transaction' } -

- - { JSON.stringify(tx.value, null, 2) } - -
- }) + this.submit() + } - const gasPriceRangeDialogue = ( - -
-
- Gas Price: - {gasPrice} gwei + render() { + const { web3, canGenerate } = this.props + const { gasPrice, gasLimit, nonce, chainId, + txn, stx, userApproval, showGasDetails } = this.state + + const { setNonce, setChainId, setGasLimit, setGasPrice, toggleGasDetails, + setUserApproval, sendTxn, createUnsignedTxn } = this + + const { state } = this + + const canSign = Just.hasInstance(txn) + const canApprove = Just.hasInstance(stx) + const canSend = Just.hasInstance(stx) && userApproval === true + + const generateButtonColor = + Nothing.hasInstance(txn) + ? 'blue' + : 'green' + + const signerButtonColor = + Nothing.hasInstance(stx) + ? 'blue' + : 'green' + + const generateTxnButton = + + + const unsignedTxnDisplay = txn.matchWith({ + Nothing: _ => '', + Just: tx => + +

+ { 'Unsigned Transaction' } +

+ + { JSON.stringify(tx.value, null, 2) } + +
+ }) + + const gasPriceRangeDialogue = ( + +
+
+ Gas Price: + {gasPrice} gwei +
+
+ Max transaction fee: + {(gasPrice * gasLimit) / 1000000000} eth +
-
- Max transaction fee: - {(gasPrice * gasLimit) / 1000000000} eth + + + +
+
Cheap
+
Fast
-
- - - -
-
Cheap
-
Fast
-
-
- ) - - const toggleGasDetailsDialogue = ( - Gas Details - ) - - const gasPriceDialogue = - - - { 'Gas Price (gwei)' } - - - - const gasLimitDialogue = - - - { 'Gas Limit' } - - - - const nonceDialogue = - - - { 'Nonce' } - - - - const chainDialogue = - - - { 'Chain ID' } - - - - const onlineParamsDialogue = web3.matchWith({ - Just: _ =>
, - Nothing: _ => - - { nonceDialogue } - { chainDialogue } - }) - - const signTxnButton = - - - const signedTxnDisplay = stx.matchWith({ - Nothing: _ => '', - Just: tx => - -

- { 'Signed Transaction' } -

- - { JSON.stringify(renderSignedTx(tx.value), null, 2) } - -
- }) - - const confirmButton = - -
- { `I approve this transaction and wish to send.` } -
-
- - const sendTxnButton = - - - const sendDialogue = web3.matchWith({ - Nothing: _ => '', - Just: _ => - - { confirmButton } - { sendTxnButton } - - }) + ) + + const toggleGasDetailsDialogue = ( + Gas Details + ) + + const gasPriceDialogue = + + + { 'Gas Price (gwei)' } + + - return ( - - { generateTxnButton } - { unsignedTxnDisplay } + const gasLimitDialogue = + + + { 'Gas Limit' } + + - { gasPriceRangeDialogue } - { toggleGasDetailsDialogue } + const nonceDialogue = + + + { 'Nonce' } + + - { showGasDetails && + const chainDialogue = + + + { 'Chain ID' } + + + + const onlineParamsDialogue = web3.matchWith({ + Just: _ =>
, + Nothing: _ => + + { nonceDialogue } + { chainDialogue } + + }) + + const signTxnButton = + + + const signedTxnDisplay = stx.matchWith({ + Nothing: _ => '', + Just: tx => + +

+ { 'Signed Transaction' } +

+ + { JSON.stringify(renderSignedTx(tx.value), null, 2) } + +
+ }) + + const confirmButton = +
- { gasPriceDialogue } - { gasLimitDialogue } + { `I approve this transaction and wish to send.` }
- } - { onlineParamsDialogue } +
- { signTxnButton } + const sendTxnButton = + - { signedTxnDisplay } - { sendDialogue } - - ) + const sendDialogue = web3.matchWith({ + Nothing: _ => '', + Just: _ => + + { confirmButton } + { sendTxnButton } + + }) + + const txnErrorDialogue = Nothing.hasInstance(state.txError) + ? '' + : +

+ { + 'There was an error sending your transaction.' + } +

+ { state.txError.value } +
+ + return ( + + { generateTxnButton } + { unsignedTxnDisplay } + + { gasPriceRangeDialogue } + { toggleGasDetailsDialogue } + + { showGasDetails && +
+ { gasPriceDialogue } + { gasLimitDialogue } +
+ } + { onlineParamsDialogue } + + { signTxnButton } + + { signedTxnDisplay } + { sendDialogue } + + { txnErrorDialogue } +
+ ) + } } export default StatelessTransaction diff --git a/src/bridge/style/extend.css b/src/bridge/style/extend.css index 172c7b442..95ec103c0 100644 --- a/src/bridge/style/extend.css +++ b/src/bridge/style/extend.css @@ -466,6 +466,11 @@ code { cursor: pointer; } +.text-link { + cursor: pointer; + text-decoration: underline; +} + .keyfile { white-space: pre-wrap; word-break: break-word; diff --git a/src/bridge/views/AcceptTransfer.js b/src/bridge/views/AcceptTransfer.js index 5553a36d1..2e4d423d4 100644 --- a/src/bridge/views/AcceptTransfer.js +++ b/src/bridge/views/AcceptTransfer.js @@ -1,6 +1,6 @@ -import { Just, Nothing } from 'folktale/maybe' +import { Just } from 'folktale/maybe' import React from 'react' -import { Row, Col, H1, H3, P, Warning } from '../components/Base' +import { Row, Col, H1, P } from '../components/Base' import { InnerLabel, AddressInput, ShowBlockie, Anchor } from '../components/Base' import * as azimuth from 'azimuth-js' import * as ob from 'urbit-ob' @@ -8,8 +8,6 @@ import * as ob from 'urbit-ob' import StatelessTransaction from '../components/StatelessTransaction' import { BRIDGE_ERROR } from '../lib/error' import { NETWORK_NAMES } from '../lib/network' -import { ROUTE_NAMES } from '../lib/router' -import { sendSignedTransaction, fromWei } from '../lib/txn' import { isValidAddress, addressFromSecp256k1Public } from '../lib/wallet' class AcceptTransfer extends React.Component { @@ -32,144 +30,17 @@ class AcceptTransfer extends React.Component { this.state = { receivingAddress: receivingAddress, - txn: Nothing(), - txError: Nothing(), incomingPoint: incomingPoint, - userApproval: false, - nonce: '', - gasPrice: '5', - showGasDetails: false, - chainId: '', - gasLimit: '600000', - stx: Nothing(), } this.handleAddressInput = this.handleAddressInput.bind(this) - this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this) - this.handleSubmit = this.handleSubmit.bind(this) - this.handleSetUserApproval = this.handleSetUserApproval.bind(this) - this.handleSetTxn = this.handleSetTxn.bind(this) - this.handleSetStx = this.handleSetStx.bind(this) - this.handleSetNonce = this.handleSetNonce.bind(this) - this.handleSetChainId = this.handleSetChainId.bind(this) - this.handleSetGasPrice = this.handleSetGasPrice.bind(this) - this.handleSetGasLimit = this.handleSetGasLimit.bind(this) - this.toggleGasDetails = this.toggleGasDetails.bind(this) - } - - toggleGasDetails() { - this.setState({ - showGasDetails: !this.state.showGasDetails - }) - } - - componentDidMount() { - const { props } = this - - const addr = props.wallet.matchWith({ - Just: wal => addressFromSecp256k1Public(wal.value.publicKey), - Nothing: () => { - throw BRIDGE_ERROR.MISSING_WALLET - } - }) - - props.web3.matchWith({ - Nothing: () => {}, - Just: (w3) => { - const validWeb3 = w3.value - - const getTxMetadata = [ - validWeb3.eth.getTransactionCount(addr), - validWeb3.eth.net.getId(), - validWeb3.eth.getGasPrice() - ]; - - Promise.all(getTxMetadata).then(r => { - const txMetadata = { - nonce: r[0], - chainId: r[1], - gasPrice: fromWei(r[2], 'gwei'), - }; - - this.setState({...txMetadata}) - - }) - } - }); + this.createUnsignedTxn = this.createUnsignedTxn.bind(this) + this.statelessRef = React.createRef(); } handleAddressInput(proxyAddress) { this.setState({ proxyAddress }) - this.handleClearTxn() - } - - handleCreateUnsignedTxn() { - const txn = this.createUnsignedTxn() - this.setState({ txn }) - } - - handleSetUserApproval(){ - const {state} = this - this.setState({ userApproval: !state.userApproval }) - } - - handleSetTxn(txn){ - this.setState({ txn }) - } - - handleSetStx(stx){ - this.setState({ - stx, - userApproval: false, - }) - } - - handleSetNonce(nonce){ - this.setState({ nonce }) - this.handleClearStx() - } - - handleSetChainId(chainId){ - this.setState({ chainId }) - this.handleClearStx() - } - - handleSetGasPrice(gasPrice){ - this.setState({ gasPrice }) - this.handleClearStx() - } - - handleSetGasLimit(gasLimit){ - this.setState({ gasLimit }) - this.handleClearStx() - } - - handleClearStx() { - this.setState({ - userApproval: false, - stx: Nothing(), - }) - } - - handleClearTxn() { - this.setState({ - userApproval: false, - txn: Nothing(), - stx: Nothing(), - }) - } - - handleSubmit() { - const { props, state } = this - sendSignedTransaction(props.web3.value, state.stx) - .then(sent => { - props.setTxnHashCursor(sent) - props.popRoute() - props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION) - }) - .catch(err => { - this.setState({ txError: err.map(val => val.merge()) }) - }) + this.statelessRef.current.clearTxn() } createUnsignedTxn() { @@ -200,15 +71,9 @@ class AcceptTransfer extends React.Component { } render() { - const { state, props } = this const validAddress = isValidAddress(state.receivingAddress) const canGenerate = validAddress === true - const canSign = Just.hasInstance(state.txn) - const canApprove = Just.hasInstance(state.stx) - const canSend = - Just.hasInstance(state.stx) - && state.userApproval === true const esvisible = props.networkType === NETWORK_NAMES.ROPSTEN || @@ -260,46 +125,13 @@ class AcceptTransfer extends React.Component { walletType={props.walletType} walletHdPath={props.walletHdPath} networkType={props.networkType} - // Tx - txn={state.txn} - stx={state.stx} - // Tx details - nonce={state.nonce} - gasPrice={state.gasPrice} - chainId={state.chainId} - gasLimit={state.gasLimit} - showGasDetails={state.showGasDetails} - toggleGasDetails={this.toggleGasDetails} - // Checks - userApproval={state.userApproval} + setTxnHashCursor={props.setTxnHashCursor} + popRoute={props.popRoute} + pushRoute={props.pushRoute} + // Other canGenerate={ canGenerate } - canSign={ canSign } - canApprove={ canApprove } - canSend={ canSend } - // Methods - createUnsignedTxn={this.handleCreateUnsignedTxn} - setUserApproval={this.handleSetUserApproval} - setTxn={this.handleSetTxn} - setStx={this.handleSetStx} - setNonce={this.handleSetNonce} - setChainId={this.handleSetChainId} - setGasPrice={this.handleSetGasPrice} - setGasLimit={this.handleSetGasLimit} - handleSubmit={this.handleSubmit} /> - - { - Nothing.hasInstance(state.txError) - ? '' - : -

- { - 'There was an error sending your transaction.' - } -

- { state.txError.value } -
- } - + createUnsignedTxn={this.createUnsignedTxn} + ref={ this.statelessRef } /> ) diff --git a/src/bridge/views/CancelTransfer.js b/src/bridge/views/CancelTransfer.js index fef449503..e005499be 100644 --- a/src/bridge/views/CancelTransfer.js +++ b/src/bridge/views/CancelTransfer.js @@ -1,23 +1,12 @@ import Maybe from 'folktale/maybe' import React from 'react' -import { Row, Col, H1, P, Warning, H3 } from '../components/Base' +import { Row, Col, H1, P } from '../components/Base' import * as azimuth from 'azimuth-js' import * as ob from 'urbit-ob' import StatelessTransaction from '../components/StatelessTransaction' import { BRIDGE_ERROR } from '../lib/error' import { ETH_ZERO_ADDR } from '../lib/wallet' -import { ROUTE_NAMES } from '../lib/router' - -import { - sendSignedTransaction, - fromWei, - } from '../lib/txn' - -import { - addressFromSecp256k1Public, -} from '../lib/wallet' - class CancelTransfer extends React.Component { constructor(props) { @@ -32,150 +21,10 @@ class CancelTransfer extends React.Component { this.state = { proxyAddress: '', - txn: Maybe.Nothing(), - txError: Maybe.Nothing(), pointInTransfer: pointInTransfer, - userApproval: false, - nonce: '', - gasPrice: '5', - showGasDetails: false, - chainId: '', - gasLimit: '600000', - stx: Maybe.Nothing(), } - // Transaction - this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this) - this.handleSubmit = this.handleSubmit.bind(this) - this.handleSetUserApproval = this.handleSetUserApproval.bind(this) - this.handleSetTxn = this.handleSetTxn.bind(this) - this.handleSetStx = this.handleSetStx.bind(this) - this.handleSetNonce = this.handleSetNonce.bind(this) - this.handleSetChainId = this.handleSetChainId.bind(this) - this.handleSetGasPrice = this.handleSetGasPrice.bind(this) - this.handleSetGasLimit = this.handleSetGasLimit.bind(this) - this.toggleGasDetails = this.toggleGasDetails.bind(this) - } - toggleGasDetails() { - this.setState({ - showGasDetails: !this.state.showGasDetails - }) - } - - componentDidMount() { - const { props } = this - - const addr = props.wallet.matchWith({ - Just: wal => addressFromSecp256k1Public(wal.value.publicKey), - Nothing: () => { - throw BRIDGE_ERROR.MISSING_WALLET - } - }) - - props.web3.matchWith({ - Nothing: () => {}, - Just: (w3) => { - const validWeb3 = w3.value - - const getTxMetadata = [ - validWeb3.eth.getTransactionCount(addr), - validWeb3.eth.net.getId(), - validWeb3.eth.getGasPrice() - ]; - - Promise.all(getTxMetadata).then(r => { - const txMetadata = { - nonce: r[0], - chainId: r[1], - gasPrice: fromWei(r[2], 'gwei'), - }; - - this.setState({...txMetadata}) - - }) - } - }); - - } - - - - handleCreateUnsignedTxn() { - const txn = this.createUnsignedTxn() - this.setState({ txn }) - } - - - - handleSetUserApproval(){ - const {state} = this - this.setState({ userApproval: !state.userApproval }) - } - - - - handleSetTxn(txn){ - this.setState({ txn }) - } - - - - handleSetStx(stx){ - this.setState({ - stx, - userApproval: false, - }) - } - - - - handleSetNonce(nonce){ - this.setState({ nonce }) - this.handleClearStx() - } - - - - handleSetChainId(chainId){ - this.setState({ chainId }) - this.handleClearStx() - } - - - - handleSetGasPrice(gasPrice){ - this.setState({ gasPrice }) - this.handleClearStx() - } - - - - handleSetGasLimit(gasLimit){ - this.setState({ gasLimit }) - this.handleClearStx() - } - - - - handleClearStx() { - this.setState({ - userApproval: false, - stx: Maybe.Nothing(), - }) - } - - - handleSubmit(){ - const { props, state } = this - sendSignedTransaction(props.web3.value, state.stx) - .then(sent => { - props.setTxnHashCursor(sent) - props.popRoute() - props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION) - }) - .catch(err => { - this.setState({ txError: err.map(val => val.merge()) }) - }) + this.createUnsignedTxn = this.createUnsignedTxn.bind(this) } createUnsignedTxn() { @@ -204,7 +53,6 @@ class CancelTransfer extends React.Component { return Maybe.Just(txn) } - render() { const { props, state } = this @@ -217,10 +65,6 @@ class CancelTransfer extends React.Component { // const canGenerate = validAddress === true const canGenerate = true - const canSign = Maybe.Just.hasInstance(state.txn) - const canApprove = Maybe.Just.hasInstance(state.stx) - const canSend = Maybe.Just.hasInstance(state.stx) && state.userApproval === true - return ( @@ -242,46 +86,12 @@ class CancelTransfer extends React.Component { walletType={props.walletType} walletHdPath={props.walletHdPath} networkType={props.networkType} - // Tx - txn={state.txn} - stx={state.stx} - // Tx details - nonce={state.nonce} - gasPrice={state.gasPrice} - chainId={state.chainId} - gasLimit={state.gasLimit} - showGasDetails={state.showGasDetails} - toggleGasDetails={this.toggleGasDetails} - // Checks - userApproval={state.userApproval} + setTxnHashCursor={props.setTxnHashCursor} + popRoute={props.popRoute} + pushRoute={props.pushRoute} + // Other canGenerate={ canGenerate } - canSign={ canSign } - canApprove={ canApprove } - canSend={ canSend } - // Methods - createUnsignedTxn={this.handleCreateUnsignedTxn} - setUserApproval={this.handleSetUserApproval} - setTxn={this.handleSetTxn} - setStx={this.handleSetStx} - setNonce={this.handleSetNonce} - setChainId={this.handleSetChainId} - setGasPrice={this.handleSetGasPrice} - setGasLimit={this.handleSetGasLimit} - handleSubmit={this.handleSubmit} /> - - { - Maybe.Nothing.hasInstance(state.txError) - ? '' - : -

- { - 'There was an error sending your transaction.' - } -

- { state.txError.value } -
- } - + createUnsignedTxn={this.createUnsignedTxn} />
) diff --git a/src/bridge/views/CreateGalaxy.js b/src/bridge/views/CreateGalaxy.js index d67515dab..ebc96f613 100644 --- a/src/bridge/views/CreateGalaxy.js +++ b/src/bridge/views/CreateGalaxy.js @@ -9,16 +9,8 @@ import { InnerLabel, GalaxyInput, AddressInput, ValidatedSigil, ShowBlockie } fr import StatelessTransaction from '../components/StatelessTransaction' import { BRIDGE_ERROR } from '../lib/error' - import { NETWORK_NAMES } from '../lib/network' - -import { - sendSignedTransaction, - getTxnInfo, - canDecodePatp -} from '../lib/txn' - -import { ROUTE_NAMES } from '../lib/router' +import { canDecodePatp } from '../lib/txn' import { addressFromSecp256k1Public, @@ -61,54 +53,23 @@ class CreateGalaxy extends React.Component { galaxyOwner: galaxyOwner, galaxyName: '', isAvailable: null, - txApproval: false, - nonce: '', - gasPrice: '5', - showGasDetails: false, - chainId: '', - txInfo: '', - gasLimit: '600000', - txn: Maybe.Nothing(), - stx: Maybe.Nothing(), } this.handleAddressInput = this.handleAddressInput.bind(this) this.handleGalaxyNameInput = this.handleGalaxyNameInput.bind(this) this.confirmAvailability = this.confirmAvailability.bind(this) - this.handleSubmit = this.handleSubmit.bind(this) - this.toggleGasDetails = this.toggleGasDetails.bind(this) - } - - toggleGasDetails() { - this.setState({ - showGasDetails: !this.state.showGasDetails - }) + this.createUnsignedTxn = this.createUnsignedTxn.bind(this) + this.statelessRef = React.createRef(); } - componentDidMount() { - const { props } = this - const addr = props.wallet.matchWith({ - Just: wal => addressFromSecp256k1Public(wal.value.publicKey), - Nothing: () => { - throw BRIDGE_ERROR.MISSING_WALLET - } - }) - - // getTxnInfo(props.web3.value, addr).then(txInfo => this.setState(txInfo)) - props.web3.map(w3 => getTxnInfo(w3, addr) - .then(txInfo => this.setState(txInfo)) - ) - } - - handleGalaxyNameInput = (galaxyName) => { this.setState({ galaxyName, isAvailable: null }) - this.clearTransaction() + this.statelessRef.current.clearTxn() } handleAddressInput = (galaxyOwner) => { this.setState({ galaxyOwner }) - this.clearTransaction() + this.statelessRef.current.clearTxn() } createUnsignedTxn = () => { @@ -133,18 +94,7 @@ class CreateGalaxy extends React.Component { state.galaxyOwner ) - this.setState({ txn: Maybe.Just(txn) }) - } - - - handleSubmit = () => { - const { props, state } = this - sendSignedTransaction(props.web3.value, state.stx) - .then(sent => { - props.setTxnHashCursor(sent) - props.popRoute() - props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION) - }) + return Maybe.Just(txn) } confirmAvailability = async () => { @@ -174,21 +124,16 @@ class CreateGalaxy extends React.Component { this.setState({ isAvailable: available }) } - - clearTransaction = () => { - this.setState({ - txApproval: false, - txn: Maybe.Nothing(), - stx: Maybe.Nothing(), - }) - } - render() { const { props, state } = this const validAddress = isValidAddress(state.galaxyOwner) const validGalaxy = isValidGalaxy(state.galaxyName) + const canGenerate = validAddress === true && + validGalaxy === true && + state.isAvailable === true + const esvisible = props.networkType === NETWORK_NAMES.ROPSTEN || props.networkType === NETWORK_NAMES.MAINNET @@ -259,43 +204,20 @@ class CreateGalaxy extends React.Component { this.createUnsignedTxn()} - clearTransaction={() => this.clearTransaction()} - setApproval={() => this.setState({txApproval: !state.txApproval})} - setTxn={txn => this.setState({txn})} - setStx={stx => this.setState({stx})} - setNonce={nonce => this.setState({nonce})} - setChainId={chainId => this.setState({chainId})} - setGasPrice={gasPrice => this.setState({gasPrice})} - setGasLimit={gasLimit => this.setState({gasLimit})} - handleSubmit={this.handleSubmit} /> + setTxnHashCursor={props.setTxnHashCursor} + popRoute={props.popRoute} + pushRoute={props.pushRoute} + // Other + ref={this.statelessRef} + canGenerate={canGenerate} + createUnsignedTxn={this.createUnsignedTxn} /> diff --git a/src/bridge/views/IssueChild.js b/src/bridge/views/IssueChild.js index 6bdb6f958..b94e5b529 100644 --- a/src/bridge/views/IssueChild.js +++ b/src/bridge/views/IssueChild.js @@ -3,23 +3,21 @@ import React from 'react' import { azimuth, ecliptic } from 'azimuth-js' import * as ob from 'urbit-ob' -import { Row, Col, H1, H3, P, Anchor, Warning } from '../components/Base' +import { Row, Col, H1, P, Anchor } from '../components/Base' import { Button, ShowBlockie, ValidatedSigil } from '../components/Base' import { PointInput, AddressInput, InnerLabel } from '../components/Base' import StatelessTransaction from '../components/StatelessTransaction' -import { ROUTE_NAMES } from '../lib/router' import { NETWORK_NAMES } from '../lib/network' import { BRIDGE_ERROR } from '../lib/error' import { getSpawnCandidate } from '../lib/child' -import { canDecodePatp, sendSignedTransaction, fromWei } from '../lib/txn' +import { canDecodePatp } from '../lib/txn' import { ETH_ZERO_ADDR, isValidAddress, - eqAddr, - addressFromSecp256k1Public + eqAddr } from '../lib/wallet' class IssueChild extends React.Component { @@ -43,100 +41,35 @@ class IssueChild extends React.Component { ] this.state = { - txError: Nothing(), receivingAddress: '', issuingPoint: issuingPoint, desiredPoint: '', isAvailable: Nothing(), // use Nothing to allow attempt when offline - userApproval: false, - nonce: '', - gasPrice: '5', - showGasDetails: false, - chainId: '', - gasLimit: '600000', - txn: Nothing(), - stx: Nothing(), suggestions: suggestions, } this.handlePointInput = this.handlePointInput.bind(this) this.handleAddressInput = this.handleAddressInput.bind(this) this.handleConfirmAvailability = this.handleConfirmAvailability.bind(this) - this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this) - this.handleSubmit = this.handleSubmit.bind(this) - this.handleSetUserApproval = this.handleSetUserApproval.bind(this) - this.handleSetTxn = this.handleSetTxn.bind(this) - this.handleSetStx = this.handleSetStx.bind(this) - this.handleSetNonce = this.handleSetNonce.bind(this) - this.handleSetChainId = this.handleSetChainId.bind(this) - this.handleSetGasPrice = this.handleSetGasPrice.bind(this) - this.handleSetGasLimit = this.handleSetGasLimit.bind(this) - this.toggleGasDetails = this.toggleGasDetails.bind(this) + this.createUnsignedTxn = this.createUnsignedTxn.bind(this) + this.statelessRef = React.createRef(); } - toggleGasDetails() { - this.setState({ - showGasDetails: !this.state.showGasDetails - }) - } - - componentDidMount() { - const { props } = this - - const addr = props.wallet.matchWith({ - Just: wal => addressFromSecp256k1Public(wal.value.publicKey), - Nothing: () => { - throw BRIDGE_ERROR.MISSING_WALLET - } - }) - - props.web3.matchWith({ - Nothing: () => {}, - Just: (w3) => { - const validWeb3 = w3.value - - const getTxMetadata = [ - validWeb3.eth.getTransactionCount(addr), - validWeb3.eth.net.getId(), - validWeb3.eth.getGasPrice() - ] - - Promise.all(getTxMetadata).then(r => { - const txMetadata = { - nonce: r[0], - chainId: r[1], - gasPrice: fromWei(r[2], 'gwei'), - } - - this.setState({...txMetadata}) - - }) - } - }) - - } - - - handleAddressInput = (receivingAddress) => { this.setState({ receivingAddress }) - this.handleClearTxn() + this.statelessRef.current.clearTxn() } - - handlePointInput(desiredPoint) { if (desiredPoint.length < 15) { this.setState({ desiredPoint, isAvailable: Nothing() }) - this.handleClearTxn() + this.statelessRef.current.clearTxn() } } - - handleConfirmAvailability() { this.confirmPointAvailability().then(r => { this.setState({ @@ -146,106 +79,6 @@ class IssueChild extends React.Component { } - - - handleCreateUnsignedTxn() { - const txn = this.createUnsignedTxn() - this.setState({ txn }) - } - - - handleSetUserApproval(){ - const {state} = this - this.setState({ userApproval: !state.userApproval }) - } - - - - handleSetTxn(txn){ - this.setState({ txn }) - } - - - - handleSetStx(stx){ - this.setState({ - stx, - userApproval: false, - }) - } - - - - handleSetNonce(nonce){ - this.setState({ nonce }) - this.handleClearStx() - } - - - - handleSetChainId(chainId){ - this.setState({ chainId }) - this.handleClearStx() - } - - - - handleSetGasPrice(gasPrice){ - this.setState({ gasPrice }) - this.handleClearStx() - } - - - - handleSetGasLimit(gasLimit){ - this.setState({ gasLimit }) - this.handleClearStx() - } - - - - handleClearStx() { - this.setState({ - userApproval: false, - stx: Nothing(), - }) - } - - - - handleClearTxn() { - this.setState({ - userApproval: false, - txn: Nothing(), - stx: Nothing(), - }) - } - - - - handleClearTransaction() { - this.setState({ - userApproval: false, - txn: Nothing(), - stx: Nothing(), - }) - } - - - - handleSubmit(){ - const { props, state } = this - sendSignedTransaction(props.web3.value, state.stx) - .then(sent => { - props.setTxnHashCursor(sent) - props.popRoute() - props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION) - }) - .catch(err => { - this.setState({ txError: err.map(val => val.merge()) }) - }) - } - async confirmPointAvailability() { const { contracts } = this.props const { desiredPoint } = this.state @@ -307,8 +140,6 @@ class IssueChild extends React.Component { return Just(txn) } - - buttonTriState() { const a = this.state.isAvailable if (Nothing.hasInstance(a)) return 'blue' @@ -316,8 +147,6 @@ class IssueChild extends React.Component { if (a.value === true) return 'green' } - - buttonTriStateText() { const a = this.state.isAvailable if (Nothing.hasInstance(a)) return 'Confirm Availablility' @@ -343,7 +172,6 @@ class IssueChild extends React.Component { return vpatp && vchild } - render() { const { props, state } = this @@ -362,12 +190,6 @@ class IssueChild extends React.Component { } }) - const canSign = Just.hasInstance(state.txn) - const canApprove = Just.hasInstance(state.stx) - const canSend = - Just.hasInstance(state.stx) - && state.userApproval === true - const esvisible = props.networkType === NETWORK_NAMES.ROPSTEN || props.networkType === NETWORK_NAMES.MAINNET @@ -480,46 +302,13 @@ class IssueChild extends React.Component { walletType={props.walletType} walletHdPath={props.walletHdPath} networkType={props.networkType} - // Tx - txn={state.txn} - stx={state.stx} - // Tx details - nonce={state.nonce} - gasPrice={state.gasPrice} - showGasDetails={state.showGasDetails} - toggleGasDetails={this.toggleGasDetails} - chainId={state.chainId} - gasLimit={state.gasLimit} - // Checks - userApproval={state.userApproval} - canGenerate={ canGenerate } - canSign={ canSign } - canApprove={ canApprove } - canSend={ canSend } - // Methods - createUnsignedTxn={this.handleCreateUnsignedTxn} - setUserApproval={this.handleSetUserApproval} - setTxn={this.handleSetTxn} - setStx={this.handleSetStx} - setNonce={this.handleSetNonce} - setChainId={this.handleSetChainId} - setGasPrice={this.handleSetGasPrice} - setGasLimit={this.handleSetGasLimit} - handleSubmit={this.handleSubmit} /> - - { - Nothing.hasInstance(state.txError) - ? '' - : -

- { - 'There was an error sending your transaction.' - } -

- { state.txError.value } -
- } - + setTxnHashCursor={props.setTxnHashCursor} + popRoute={props.popRoute} + pushRoute={props.pushRoute} + // Other + canGenerate={canGenerate} + createUnsignedTxn={this.createUnsignedTxn} + ref={this.statelessRef} /> ) diff --git a/src/bridge/views/Point/Actions.js b/src/bridge/views/Point/Actions.js index 4f77b82db..4eacd52ca 100644 --- a/src/bridge/views/Point/Actions.js +++ b/src/bridge/views/Point/Actions.js @@ -30,7 +30,6 @@ const Actions = (props) => { eqAddr(details.value.owner, addr) && details.value.active }) - const canSetManagementProxy = pointDetails.matchWith({ Nothing: _ => false, Just: details => diff --git a/src/bridge/views/SetKeys.js b/src/bridge/views/SetKeys.js index f93a3c8fe..8efe7263d 100644 --- a/src/bridge/views/SetKeys.js +++ b/src/bridge/views/SetKeys.js @@ -2,22 +2,14 @@ import React from 'react' import Maybe from 'folktale/maybe' import * as azimuth from 'azimuth-js' import * as ob from 'urbit-ob' -import { Row, Col, H1, P, Warning, H3 } from '../components/Base' +import { Row, Col, H1, P, Warning } from '../components/Base' import StatelessTransaction from '../components/StatelessTransaction' import { BRIDGE_ERROR } from '../lib/error' -import { ROUTE_NAMES } from '../lib/router' -import { attemptSeedDerivation, genKey } from '../lib/keys' - -import saveAs from 'file-saver' +import { attemptSeedDerivation } from '../lib/keys' import * as kg from '../../../node_modules/urbit-key-generation/dist/index' -import { - sendSignedTransaction, - fromWei, - } from '../lib/txn' - import { addressFromSecp256k1Public, addHexPrefix @@ -42,36 +34,12 @@ class SetKeys extends React.Component { point: point, cryptoSuiteVersion: 1, continuity: false, - txn: Maybe.Nothing(), - txError: Maybe.Nothing(), isManagementSeed: false, - userApproval: false, - nonce: '', - gasPrice: '5', - showGasDetails: false, - chainId: '', - gasLimit: '600000', - stx: Maybe.Nothing(), } this.handleNetworkSeedInput = this.handleNetworkSeedInput.bind(this) // Transaction - this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this) - this.handleSubmit = this.handleSubmit.bind(this) - this.handleSetUserApproval = this.handleSetUserApproval.bind(this) - this.handleSetTxn = this.handleSetTxn.bind(this) - this.handleSetStx = this.handleSetStx.bind(this) - this.handleSetNonce = this.handleSetNonce.bind(this) - this.handleSetChainId = this.handleSetChainId.bind(this) - this.handleSetGasPrice = this.handleSetGasPrice.bind(this) - this.handleSetGasLimit = this.handleSetGasLimit.bind(this) - this.toggleGasDetails = this.toggleGasDetails.bind(this) - } - - toggleGasDetails() { - this.setState({ - showGasDetails: !this.state.showGasDetails - }) + this.createUnsignedTxn = this.createUnsignedTxn.bind(this) } componentDidMount() { @@ -87,30 +55,6 @@ class SetKeys extends React.Component { }) this.determineManagementSeed(props.contracts.value, addr) - - props.web3.matchWith({ - Nothing: () => {}, - Just: (w3) => { - const validWeb3 = w3.value - - const getTxMetadata = [ - validWeb3.eth.getTransactionCount(addr), - validWeb3.eth.net.getId(), - validWeb3.eth.getGasPrice() - ]; - - Promise.all(getTxMetadata).then(r => { - const txMetadata = { - nonce: r[0], - chainId: r[1], - gasPrice: fromWei(r[2], 'gwei'), - }; - - this.setState({...txMetadata}) - - }) - } - }); } async determineManagementSeed(ctrcs, addr) { @@ -154,126 +98,6 @@ class SetKeys extends React.Component { this.setState({ networkSeed }) } - handleCreateUnsignedTxn() { - const txn = this.createUnsignedTxn() - this.setState({ txn }) - } - - - handleSetUserApproval(){ - const {state} = this - this.setState({ userApproval: !state.userApproval }) - } - - - - handleSetTxn(txn){ - this.setState({ txn }) - } - - - - handleSetStx(stx){ - this.setState({ - stx, - userApproval: false, - }) - } - - - - handleSetNonce(nonce){ - this.setState({ nonce }) - this.handleClearStx() - } - - - - handleSetChainId(chainId){ - this.setState({ chainId }) - this.handleClearStx() - } - - - - handleSetGasPrice(gasPrice){ - this.setState({ gasPrice }) - this.handleClearStx() - } - - - - handleSetGasLimit(gasLimit){ - this.setState({ gasLimit }) - this.handleClearStx() - } - - - - handleClearStx() { - this.setState({ - userApproval: false, - stx: Maybe.Nothing(), - }) - } - - - - - handleClearTxn() { - this.setState({ - userApproval: false, - txn: Maybe.Nothing(), - stx: Maybe.Nothing(), - }) - } - - - - handleClearTransaction() { - this.setState({ - userApproval: false, - txn: Maybe.Nothing(), - stx: Maybe.Nothing(), - }) - } - - downloadKeyfile(networkSeed) { - const { pointCache } = this.props - const { pointCursor } = this.props - - const point = pointCursor.matchWith({ - Just: (pt) => pt.value, - Nothing: () => { - throw BRIDGE_ERROR.MISSING_POINT - } - }) - - const pointDetails = - point in pointCache - ? pointCache[point] - : (() => { throw BRIDGE_ERROR.MISSING_POINT })() - - const revision = parseInt(pointDetails.keyRevisionNumber) - const keyfile = genKey(networkSeed, point, revision) - let blob = new Blob([keyfile], {type:"text/plain;charset=utf-8"}); - saveAs(blob, `${ob.patp(point).slice(1)}-${revision}.key`) - } - - handleSubmit(){ - const { props, state } = this - sendSignedTransaction(props.web3.value, state.stx) - .then(sent => { - props.setNetworkSeedCache(this.state.networkSeed) - props.setTxnHashCursor(sent) - props.popRoute() - props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION, {promptKeyfile: true}) - }) - .catch(err => { - this.setState({ txError: err.map(val => val.merge()) }) - }) - } - createUnsignedTxn() { const { state, props } = this @@ -322,13 +146,6 @@ class SetKeys extends React.Component { state.networkSeed.length === 64 && state.networkSeed.length === 64 - const canSign = Maybe.Just.hasInstance(state.txn) - const canApprove = Maybe.Just.hasInstance(state.stx) - - const canSend = - Maybe.Just.hasInstance(state.stx) - && state.userApproval === true - const pointDetails = state.point in props.pointCache ? props.pointCache[state.point] @@ -376,45 +193,14 @@ class SetKeys extends React.Component { walletType={props.walletType} walletHdPath={props.walletHdPath} networkType={props.networkType} + setTxnHashCursor={props.setTxnHashCursor} + popRoute={props.popRoute} + pushRoute={props.pushRoute} // Tx - txn={state.txn} - stx={state.stx} - // Tx details - nonce={state.nonce} - gasPrice={state.gasPrice} - chainId={state.chainId} - gasLimit={state.gasLimit} - showGasDetails={state.showGasDetails} - toggleGasDetails={this.toggleGasDetails} - // Checks - userApproval={state.userApproval} canGenerate={ canGenerate } - canSign={ canSign } - canApprove={ canApprove } - canSend={ canSend } - // Methods - createUnsignedTxn={this.handleCreateUnsignedTxn} - setUserApproval={this.handleSetUserApproval} - setTxn={this.handleSetTxn} - setStx={this.handleSetStx} - setNonce={this.handleSetNonce} - setChainId={this.handleSetChainId} - setGasPrice={this.handleSetGasPrice} - setGasLimit={this.handleSetGasLimit} - handleSubmit={this.handleSubmit} /> - - { - Maybe.Nothing.hasInstance(state.txError) - ? '' - : -

- { - 'There was an error sending your transaction.' - } -

- { state.txError.value } -
- } + createUnsignedTxn={this.createUnsignedTxn} + networkSeed={ state.networkSeed } + setNetworkSeedCache={ props.setNetworkSeedCache } /> diff --git a/src/bridge/views/SetProxy.js b/src/bridge/views/SetProxy.js index 1e4a525a6..3da633645 100644 --- a/src/bridge/views/SetProxy.js +++ b/src/bridge/views/SetProxy.js @@ -1,8 +1,8 @@ import Maybe from 'folktale/maybe' import React from 'react' import * as azimuth from 'azimuth-js' -import { Row, Col, H1, H3, P, InnerLabel, ShowBlockie, Anchor } from '../components/Base' -import { AddressInput, Warning } from '../components/Base' +import { Row, Col, H1, P, InnerLabel, ShowBlockie, Anchor } from '../components/Base' +import { AddressInput } from '../components/Base' import * as ob from 'urbit-ob' import { PROXY_TYPE, renderProxyType } from '../lib/proxy' @@ -12,17 +12,7 @@ import { NETWORK_NAMES } from '../lib/network' import StatelessTransaction from '../components/StatelessTransaction' -import { ROUTE_NAMES } from '../lib/router' - -import { - sendSignedTransaction, - fromWei, - } from '../lib/txn' - -import { - isValidAddress, - addressFromSecp256k1Public, -} from '../lib/wallet' +import { isValidAddress } from '../lib/wallet' const SetManagementProxy = (props) => addressFromSecp256k1Public(wal.value.publicKey), - Nothing: () => { - throw BRIDGE_ERROR.MISSING_WALLET - } - }) - - props.web3.matchWith({ - Nothing: () => {}, - Just: (w3) => { - const validWeb3 = w3.value - - const getTxMetadata = [ - validWeb3.eth.getTransactionCount(addr), - validWeb3.eth.net.getId(), - validWeb3.eth.getGasPrice() - ]; - - Promise.all(getTxMetadata).then(r => { - const txMetadata = { - nonce: r[0], - chainId: r[1], - gasPrice: fromWei(r[2], 'gwei'), - }; - - this.setState({...txMetadata}) - - }) - } - }); - - } - - - handleAddressInput(proxyAddress) { this.setState({ proxyAddress }) - this.handleClearTxn() - } - - - handleCreateUnsignedTxn() { - const txn = this.createUnsignedTxn() - this.setState({ txn }) - } - - - handleSetUserApproval(){ - const {state} = this - this.setState({ userApproval: !state.userApproval }) - } - - - - handleSetTxn(txn){ - this.setState({ txn }) - } - - - - handleSetStx(stx){ - this.setState({ - stx, - userApproval: false, - }) - } - - - handleSetNonce(nonce){ - this.setState({ nonce }) - this.handleClearStx() + this.statelessRef.current.clearTxn() } - - - handleSetChainId(chainId){ - this.setState({ chainId }) - this.handleClearStx() - } - - - - handleSetGasPrice(gasPrice){ - this.setState({ gasPrice }) - this.handleClearStx() - } - - - - handleSetGasLimit(gasLimit){ - this.setState({ gasLimit }) - this.handleClearStx() - } - - - - handleClearStx() { - this.setState({ - userApproval: false, - stx: Maybe.Nothing(), - }) - } - - - - handleClearTxn() { - this.setState({ - userApproval: false, - txn: Maybe.Nothing(), - stx: Maybe.Nothing(), - }) - } - - - - handleClearTransaction() { - this.setState({ - userApproval: false, - txn: Maybe.Nothing(), - stx: Maybe.Nothing(), - }) - } - - - - handleSubmit(){ - const { props, state } = this - sendSignedTransaction(props.web3.value, state.stx) - .then(sent => { - props.setTxnHashCursor(sent) - props.popRoute() - props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION) - }) - .catch(err => { - this.setState({ txError: err.map(val => val.merge()) }) - }) - } - - createUnsignedTxn(proxyAddress) { const { state, props } = this @@ -270,19 +99,12 @@ class SetProxy extends React.Component { } render() { - const { props, state } = this const renderedProxyType = renderProxyType(props.proxyType) - const validAddress = isValidAddress(state.proxyAddress) - const canGenerate = validAddress === true - const canSign = Maybe.Just.hasInstance(state.txn) - const canApprove = Maybe.Just.hasInstance(state.stx) - const canSend = Maybe.Just.hasInstance(state.stx) && state.userApproval === true - const esvisible = props.networkType === NETWORK_NAMES.ROPSTEN || props.networkType === NETWORK_NAMES.MAINNET @@ -339,46 +161,13 @@ class SetProxy extends React.Component { walletType={props.walletType} walletHdPath={props.walletHdPath} networkType={props.networkType} - // Tx - txn={state.txn} - stx={state.stx} - // Tx details - nonce={state.nonce} - gasPrice={state.gasPrice} - chainId={state.chainId} - gasLimit={state.gasLimit} - showGasDetails={state.showGasDetails} - toggleGasDetails={this.toggleGasDetails} - // Checks - userApproval={state.userApproval} - canGenerate={ canGenerate } - canSign={ canSign } - canApprove={ canApprove } - canSend={ canSend } - // Methods - createUnsignedTxn={this.handleCreateUnsignedTxn} - setUserApproval={this.handleSetUserApproval} - setTxn={this.handleSetTxn} - setStx={this.handleSetStx} - setNonce={this.handleSetNonce} - setChainId={this.handleSetChainId} - setGasPrice={this.handleSetGasPrice} - setGasLimit={this.handleSetGasLimit} - handleSubmit={this.handleSubmit} /> - - { - Maybe.Nothing.hasInstance(state.txError) - ? '' - : -

- { - 'There was an error sending your transaction.' - } -

- { state.txError.value } -
- } - + setTxnHashCursor={props.setTxnHashCursor} + popRoute={props.popRoute} + pushRoute={props.pushRoute} + // Other + ref={this.statelessRef} + createUnsignedTxn={this.createUnsignedTxn} + canGenerate={ canGenerate } /> ) diff --git a/src/bridge/views/Transfer.js b/src/bridge/views/Transfer.js index 6f69fc657..03ed0136c 100644 --- a/src/bridge/views/Transfer.js +++ b/src/bridge/views/Transfer.js @@ -4,22 +4,15 @@ import * as azimuth from 'azimuth-js' import * as ob from 'urbit-ob' import { Row, Col, H1, InnerLabel, ShowBlockie, P, Anchor } from '../components/Base' -import { AddressInput, Warning, H3 } from '../components/Base' +import { AddressInput } from '../components/Base' import StatelessTransaction from '../components/StatelessTransaction' import { BRIDGE_ERROR } from '../lib/error' import { NETWORK_NAMES } from '../lib/network' -import { ROUTE_NAMES } from '../lib/router' import { - sendSignedTransaction, - fromWei, - } from '../lib/txn' - - import { - isValidAddress, - addressFromSecp256k1Public - } from '../lib/wallet' + isValidAddress +} from '../lib/wallet' class Transfer extends React.Component { constructor(props) { @@ -33,191 +26,26 @@ class Transfer extends React.Component { }) this.state = { - txError: Maybe.Nothing(), receivingAddress: '', issuingPoint: issuingPoint, - userApproval: false, - nonce: '', - gasPrice: '5', - showGasDetails: false, - chainId: '', - gasLimit: '600000', - txn: Maybe.Nothing(), - stx: Maybe.Nothing(), } - this.handleAddressInput = this.handleAddressInput.bind(this) - // Transaction - this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this) - this.handleSubmit = this.handleSubmit.bind(this) - this.handleSetUserApproval = this.handleSetUserApproval.bind(this) - this.handleSetTxn = this.handleSetTxn.bind(this) - this.handleSetStx = this.handleSetStx.bind(this) - this.handleSetNonce = this.handleSetNonce.bind(this) - this.handleSetChainId = this.handleSetChainId.bind(this) - this.handleSetGasPrice = this.handleSetGasPrice.bind(this) - this.handleSetGasLimit = this.handleSetGasLimit.bind(this) - this.toggleGasDetails = this.toggleGasDetails.bind(this) - } - - toggleGasDetails() { - this.setState({ - showGasDetails: !this.state.showGasDetails - }) - } - - componentDidMount() { - const { props } = this - - const addr = props.wallet.matchWith({ - Just: wal => addressFromSecp256k1Public(wal.value.publicKey), - Nothing: () => { - throw BRIDGE_ERROR.MISSING_WALLET - } - }) - - props.web3.matchWith({ - Nothing: () => {}, - Just: (w3) => { - const validWeb3 = w3.value - - const getTxMetadata = [ - validWeb3.eth.getTransactionCount(addr), - validWeb3.eth.net.getId(), - validWeb3.eth.getGasPrice() - ]; - - Promise.all(getTxMetadata).then(r => { - const txMetadata = { - nonce: r[0], - chainId: r[1], - gasPrice: fromWei(r[2], 'gwei'), - }; - - this.setState({...txMetadata}) - - }) - } - }); + this.handleAddressInput = this.handleAddressInput.bind(this) + this.createUnsignedTxn = this.createUnsignedTxn.bind(this) + this.statelessRef = React.createRef(); } - - handleAddressInput(receivingAddress) { this.setState({ receivingAddress }) - this.handleClearTxn() + this.statelessRef.current.clearTxn() } - - handleConfirmAvailability() { this.confirmPointAvailability().then(r => { this.setState({ isAvailable: r }) }) } - - - handleCreateUnsignedTxn() { - const txn = this.createUnsignedTxn() - this.setState({ txn }) - } - - - handleSetUserApproval(){ - const {state} = this - this.setState({ userApproval: !state.userApproval }) - } - - - - handleSetTxn(txn){ - this.setState({ txn }) - } - - - - handleSetStx(stx){ - this.setState({ - stx, - userApproval: false, - }) - } - - - - handleSetNonce(nonce){ - this.setState({ nonce }) - this.handleClearStx() - } - - - - handleSetChainId(chainId){ - this.setState({ chainId }) - this.handleClearStx() - } - - - - handleSetGasPrice(gasPrice){ - this.setState({ gasPrice }) - this.handleClearStx() - } - - - - handleSetGasLimit(gasLimit){ - this.setState({ gasLimit }) - this.handleClearStx() - } - - - - handleClearStx() { - this.setState({ - userApproval: false, - stx: Maybe.Nothing(), - }) - } - - - - handleClearTxn() { - this.setState({ - userApproval: false, - txn: Maybe.Nothing(), - stx: Maybe.Nothing(), - }) - } - - - - handleClearTransaction() { - this.setState({ - userApproval: false, - txn: Maybe.Nothing(), - stx: Maybe.Nothing(), - }) - } - - - - handleSubmit(){ - const { props, state } = this - sendSignedTransaction(props.web3.value, state.stx) - .then(sent => { - props.setTxnHashCursor(sent) - props.popRoute() - props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION) - }) - .catch(err => { - this.setState({ txError: err.map(val => val.merge()) }) - }) - } - - - createUnsignedTxn() { const { state, props } = this @@ -244,19 +72,12 @@ class Transfer extends React.Component { return Maybe.Just(txn) } - - render() { const { props, state } = this const validAddress = isValidAddress(state.receivingAddress) - const canGenerate = validAddress === true - const canSign = Maybe.Just.hasInstance(state.txn) - const canApprove = Maybe.Just.hasInstance(state.stx) - const canSend = Maybe.Just.hasInstance(state.stx) && state.userApproval === true - const esvisible = props.networkType === NETWORK_NAMES.ROPSTEN || props.networkType === NETWORK_NAMES.MAINNET @@ -310,46 +131,15 @@ class Transfer extends React.Component { walletType={props.walletType} walletHdPath={props.walletHdPath} networkType={props.networkType} - // Tx - txn={state.txn} - stx={state.stx} - // Tx details - nonce={state.nonce} - gasPrice={state.gasPrice} - chainId={state.chainId} - gasLimit={state.gasLimit} - showGasDetails={state.showGasDetails} - toggleGasDetails={this.toggleGasDetails} + setTxnHashCursor={props.setTxnHashCursor} + popRoute={props.popRoute} + pushRoute={props.pushRoute} // Checks userApproval={state.userApproval} canGenerate={ canGenerate } - canSign={ canSign } - canApprove={ canApprove } - canSend={ canSend } // Methods - createUnsignedTxn={this.handleCreateUnsignedTxn} - setUserApproval={this.handleSetUserApproval} - setTxn={this.handleSetTxn} - setStx={this.handleSetStx} - setNonce={this.handleSetNonce} - setChainId={this.handleSetChainId} - setGasPrice={this.handleSetGasPrice} - setGasLimit={this.handleSetGasLimit} - handleSubmit={this.handleSubmit} /> - - { - Maybe.Nothing.hasInstance(state.txError) - ? '' - : -

- { - 'There was an error sending your transaction.' - } -

- { state.txError.value } -
- } - + createUnsignedTxn={this.createUnsignedTxn} + ref={this.statelessRef} /> ) diff --git a/src/common/components/AppNavigation.js b/src/common/components/AppNavigation.js index 7e43b8b8c..1efd17ec4 100644 --- a/src/common/components/AppNavigation.js +++ b/src/common/components/AppNavigation.js @@ -23,17 +23,17 @@ class AppNavigation extends React.Component { let style = { position: "fixed", bottom: "10px", - right: "10px" + right: "10px", + "text-decoration": "underline", + cursor: "pointer" } return ( - {buttonText} - + ) } }