on master help sign in
Merge pull request #96 from urbit/stateless-transaction

Move common transaction state/mutations into statelessTransaction

commitbf5e9bb8c36e9f59e8ad0d34148d1df0571a0640 authorChristopher Johnson <chris@cjohnson.io> dateMon 8 Apr 2019, 10:15 (8 years ago) parentd9433544a7ff4d
11 files changed+491−1587
src/bridge/components/StatelessTransaction.js+397−215 src/bridge/style/extend.css+5 src/bridge/views/AcceptTransfer.js+11−179 src/bridge/views/CancelTransfer.js+7−197 src/bridge/views/CreateGalaxy.js+18−96 src/bridge/views/IssueChild.js+14−225 src/bridge/views/Point/Actions.js−1 src/bridge/views/SetKeys.js+9−223 src/bridge/views/SetProxy.js+13−224 src/bridge/views/Transfer.js+12−222 src/common/components/AppNavigation.js+5−5
src/bridge/components/StatelessTransaction.js+397−215
@@ -1,244 +1,426 @@
1−import { Nothing } from 'folktale/maybe'
1+import { Nothing, Just } from 'folktale/maybe'
22import React from 'react'
33
44import { Code, H3 } from './Base'
55import { Button } from './Base'
66import { CheckboxButton, Input, InnerLabel } from './Base'
7+import { Warning } from '../components/Base'
78
8−import { renderSignedTx, signTransaction } from '../lib/txn'
9+import { addressFromSecp256k1Public } from '../lib/wallet'
10+import { BRIDGE_ERROR } from '../lib/error'
11+import { ROUTE_NAMES } from '../lib/router'
912
10−const StatelessTransaction = props => {
11− const { web3, gasPrice, gasLimit, nonce, chainId } = props
12− const { setNonce, setChainId, setGasLimit, setGasPrice, showGasDetails, toggleGasDetails } = props
13− const { txn, stx, createUnsignedTxn } = props
14− const { canSign, canGenerate, canApprove } = props
15− const { setUserApproval, userApproval } = props
16− const { canSend, handleSubmit } = props
13+import {
14+ sendSignedTransaction,
15+ fromWei,
16+ renderSignedTx,
17+ signTransaction
18+ } from '../lib/txn'
19+
20+class StatelessTransaction extends React.Component {
21+
22+ constructor(props) {
23+ super(props)
24+
25+ this.state = {
26+ gasPrice: '5',
27+ gasLimit: '600000',
28+ showGasDetails: false,
29+ userApproval: false,
30+ chainId: '',
31+ nonce: '',
32+ stx: Nothing(),
33+ txn: Nothing(),
34+ txError: Nothing(),
35+ }
36+
37+ this.createUnsignedTxn = this.createUnsignedTxn.bind(this)
38+ this.submit = this.submit.bind(this)
39+ this.setUserApproval = this.setUserApproval.bind(this)
40+ this.setTxn = this.setTxn.bind(this)
41+ this.setStx = this.setStx.bind(this)
42+ this.sendTxn = this.sendTxn.bind(this)
43+ this.setNonce = this.setNonce.bind(this)
44+ this.setChainId = this.setChainId.bind(this)
45+ this.setGasPrice = this.setGasPrice.bind(this)
46+ this.setGasLimit = this.setGasLimit.bind(this)
47+ this.rangeChange = this.rangeChange.bind(this)
48+ this.toggleGasDetails = this.toggleGasDetails.bind(this)
49+ }
50+
51+ componentDidMount() {
52+ const { props } = this
53+
54+ const addr = props.wallet.matchWith({
55+ Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
56+ Nothing: () => {
57+ throw BRIDGE_ERROR.MISSING_WALLET
58+ }
59+ })
60+
61+ props.web3.matchWith({
62+ Nothing: () => {},
63+ Just: (w3) => {
64+ const validWeb3 = w3.value
65+
66+ const getTxMetadata = [
67+ validWeb3.eth.getTransactionCount(addr),
68+ validWeb3.eth.net.getId(),
69+ validWeb3.eth.getGasPrice()
70+ ];
71+
72+ Promise.all(getTxMetadata).then(r => {
73+ const txMetadata = {
74+ nonce: r[0],
75+ chainId: r[1],
76+ gasPrice: fromWei(r[2], 'gwei'),
77+ };
78+
79+ this.setState({...txMetadata})
80+
81+ })
82+ }
83+ });
84+ }
85+
86+ submit(){
87+ const { props, state } = this
88+ sendSignedTransaction(props.web3.value, state.stx)
89+ .then(sent => {
90+ props.setTxnHashCursor(sent)
91+ props.popRoute()
92+
93+ if (props.networkSeed) {
94+ props.setNetworkSeedCache(props.networkSeed)
95+ props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION, {promptKeyfile: true})
96+ } else {
97+ props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
98+ }
99+ })
100+ .catch(err => {
101+ if (err.map) {
102+ this.setState({ txError: err.map(val => val.merge()) })
103+ } else {
104+ this.setState({ txError: err })
105+ }
106+ })
107+ }
108+
109+ setUserApproval(){
110+ const {state} = this
111+ this.setState({ userApproval: !state.userApproval })
112+ }
113+
114+ toggleGasDetails() {
115+ this.setState({
116+ showGasDetails: !this.state.showGasDetails
117+ })
118+ }
119+
120+ setStx(stx){
121+ this.setState({
122+ stx,
123+ userApproval: false,
124+ })
125+ }
126+
127+ setTxn(txn){
128+ this.setState({ txn })
129+ }
130+
131+ createUnsignedTxn() {
132+ const txn = this.props.createUnsignedTxn()
133+
134+ this.setState({ txn })
135+ }
136+
137+ clearTxn() {
138+ this.setState({
139+ userApproval: false,
140+ txn: Nothing(),
141+ stx: Nothing(),
142+ })
143+ }
144+
145+ setNonce(nonce){
146+ this.setState({ nonce })
147+ this.clearStx()
148+ }
149+
150+ setChainId(chainId){
151+ this.setState({ chainId })
152+ this.clearStx()
153+ }
154+
155+ setGasPrice(gasPrice) {
156+ this.setState({ gasPrice })
157+ this.clearStx()
158+ }
159+
160+ rangeChange(e) {
161+ this.setGasPrice(e.target.value);
162+ }
163+
164+ setGasLimit(gasLimit){
165+ this.setState({ gasLimit })
166+ this.clearStx()
167+ }
168+
169+ clearStx() {
170+ this.setState({
171+ userApproval: false,
172+ stx: Nothing(),
173+ })
174+ }
17175
18176 // TODO: Investigate
19− // setState doesn't seem to work in SetProxy/handleSubmit;
177+ // setState doesn't seem to work in SetProxy/submit;
20178 // - TypeError: Cannot read property 'updater' of undefined
21179 // so just modifying the DOM manually here. (https://imgur.com/a/i0Qsyq1)
22180
23− const handleRangeChange = (e) => {
24− setGasPrice(e.target.value);
25− }
26−
27− const sendTxn = (e) => {
181+ sendTxn(e) {
28182 e.target.setAttribute("disabled", true);
29183 let spinner = e.target.querySelectorAll('.btn-spinner')[0];
30184 spinner.classList.remove('hide');
31− handleSubmit()
32− }
33−
34− const generateButtonColor =
35− Nothing.hasInstance(txn)
36− ? 'blue'
37− : 'green'
38−
39− const signerButtonColor =
40− Nothing.hasInstance(stx)
41− ? 'blue'
42− : 'green'
43−
44− const generateTxnButton =
45− <Button
46− className={ 'mt-8' }
47− disabled={ !canGenerate }
48− prop-color={ generateButtonColor }
49− prop-size={ 'lg wide' }
50− onClick={ createUnsignedTxn }
51− >
52− { 'Generate Transaction' }
53− </Button>
54−
55− const unsignedTxnDisplay = txn.matchWith({
56− Nothing: _ => '',
57− Just: tx =>
58− <React.Fragment>
59− <H3 className={ 'mt-8' }>
60− { 'Unsigned Transaction' }
61− </H3>
62− <Code>
63− { JSON.stringify(tx.value, null, 2) }
64− </Code>
65− </React.Fragment>
66− })
185+ this.submit()
186+ }
67187
68− const gasPriceRangeDialogue = (
69− <React.Fragment>
70− <div className="mt-12 flex space-between align-baseline">
71− <div>
72− <span>Gas Price:</span>
73− <span className="ml-4 text-700 text-sm">{gasPrice} gwei</span>
188+ render() {
189+ const { web3, canGenerate } = this.props
190+ const { gasPrice, gasLimit, nonce, chainId,
191+ txn, stx, userApproval, showGasDetails } = this.state
192+
193+ const { setNonce, setChainId, setGasLimit, setGasPrice, toggleGasDetails,
194+ setUserApproval, sendTxn, createUnsignedTxn } = this
195+
196+ const { state } = this
197+
198+ const canSign = Just.hasInstance(txn)
199+ const canApprove = Just.hasInstance(stx)
200+ const canSend = Just.hasInstance(stx) && userApproval === true
201+
202+ const generateButtonColor =
203+ Nothing.hasInstance(txn)
204+ ? 'blue'
205+ : 'green'
206+
207+ const signerButtonColor =
208+ Nothing.hasInstance(stx)
209+ ? 'blue'
210+ : 'green'
211+
212+ const generateTxnButton =
213+ <Button
214+ className={ 'mt-8' }
215+ disabled={ !canGenerate }
216+ prop-color={ generateButtonColor }
217+ prop-size={ 'lg wide' }
218+ onClick={ createUnsignedTxn }
219+ >
220+ { 'Generate Transaction' }
221+ </Button>
222+
223+ const unsignedTxnDisplay = txn.matchWith({
224+ Nothing: _ => '',
225+ Just: tx =>
226+ <React.Fragment>
227+ <H3 className={ 'mt-8' }>
228+ { 'Unsigned Transaction' }
229+ </H3>
230+ <Code>
231+ { JSON.stringify(tx.value, null, 2) }
232+ </Code>
233+ </React.Fragment>
234+ })
235+
236+ const gasPriceRangeDialogue = (
237+ <React.Fragment>
238+ <div className="mt-12 flex space-between align-baseline">
239+ <div>
240+ <span>Gas Price:</span>
241+ <span className="ml-4 text-700 text-sm">{gasPrice} gwei</span>
242+ </div>
243+ <div className="text-sm">
244+ <span>Max transaction fee: </span>
245+ <span className="text-700">{(gasPrice * gasLimit) / 1000000000} eth</span>
246+ </div>
74247 </div>
75− <div className="text-sm">
76− <span>Max transaction fee: </span>
77− <span className="text-700">{(gasPrice * gasLimit) / 1000000000} eth</span>
248+
249+ <input
250+ className="mt-4"
251+ type="range"
252+ min="2"
253+ max="20"
254+ list="gweiVals"
255+ value={gasPrice}
256+ onChange={this.rangeChange}
257+ />
258+
259+ <div className="flex space-between text-sm mb-8">
260+ <div>Cheap</div>
261+ <div>Fast</div>
78262 </div>
79− </div>
80−
81− <input
82− className="mt-4"
83− type="range"
84− min="2"
85− max="20"
86− list="gweiVals"
87− value={gasPrice}
88− onChange={handleRangeChange}
89− />
90−
91− <div className="flex space-between text-sm mb-8">
92− <div>Cheap</div>
93− <div>Fast</div>
94− </div>
95− </React.Fragment>
96− )
97−
98− const toggleGasDetailsDialogue = (
99− <a href="javascript:void(0)" onClick={toggleGasDetails}>Gas Details</a>
100− )
101−
102− const gasPriceDialogue =
103− <Input
104− className={ 'mono mt-4' }
105− prop-size={ 'md' }
106− prop-format={ 'innerLabel' }
107− value={ gasPrice }
108− onChange={ setGasPrice }
109− >
110− <InnerLabel>
111− { 'Gas Price (gwei)' }
112− </InnerLabel>
113− </Input>
114−
115− const gasLimitDialogue =
116− <Input
117− className={ 'mono mt-4' }
118− prop-size={ 'md' }
119− prop-format={ 'innerLabel' }
120− value={ gasLimit }
121− onChange={ setGasLimit }>
122− <InnerLabel>
123− { 'Gas Limit' }
124− </InnerLabel>
125− </Input>
126−
127− const nonceDialogue =
128− <Input
129− className={ 'mono mt-4' }
130− prop-size={ 'md' }
131− prop-format={ 'innerLabel' }
132− value={ nonce }
133− onChange={ setNonce }
134− >
135− <InnerLabel>
136− { 'Nonce' }
137− </InnerLabel>
138− </Input>
139−
140− const chainDialogue =
141− <Input
142− className={ 'mono mt-4 mb-8' }
143− prop-size={ 'md' }
144− prop-format={ 'innerLabel' }
145− value={ chainId }
146− onChange={ setChainId }
147− >
148− <InnerLabel>
149− { 'Chain ID' }
150− </InnerLabel>
151− </Input>
152−
153− const onlineParamsDialogue = web3.matchWith({
154− Just: _ => <div />,
155− Nothing: _ =>
156− <React.Fragment>
157− { nonceDialogue }
158− { chainDialogue }
159263 </React.Fragment>
160− })
161−
162− const signTxnButton =
163− <Button
164− disabled={ !canSign }
165− className={ 'mt-8' }
166− prop-size={ 'lg wide' }
167− prop-color={ signerButtonColor }
168− onClick={ () => signTransaction(props) }
169− >
170− { 'Sign Transaction' }
171− </Button>
172−
173− const signedTxnDisplay = stx.matchWith({
174− Nothing: _ => '',
175− Just: tx =>
176− <React.Fragment>
177− <H3 className={ 'mt-8' }>
178− { 'Signed Transaction' }
179− </H3>
180− <Code>
181− { JSON.stringify(renderSignedTx(tx.value), null, 2) }
182− </Code>
183− </React.Fragment>
184− })
185−
186− const confirmButton =
187− <CheckboxButton
188− className={ 'mt-8' }
189− disabled={ !canApprove }
190− onClick={ setUserApproval }
191− state={ userApproval }
192− >
193− <div>
194− { `I approve this transaction and wish to send.` }
195− </div>
196− </CheckboxButton>
197−
198− const sendTxnButton =
199− <Button
200− prop-size={ 'xl wide' }
201− className={ 'mt-8' }
202− disabled={ !canSend }
203− onClick={ sendTxn }
204− >
205− <span className="relative">
206− <span className="btn-spinner hide"></span>
207− { 'Send Transaction' }
208− </span>
209− </Button>
210−
211− const sendDialogue = web3.matchWith({
212− Nothing: _ => '',
213− Just: _ =>
214− <React.Fragment>
215− { confirmButton }
216− { sendTxnButton }
217− </React.Fragment>
218− })
264+ )
265+
266+ const toggleGasDetailsDialogue = (
267+ <span className="text-link" onClick={toggleGasDetails}>Gas Details</span>
268+ )
269+
270+ const gasPriceDialogue =
271+ <Input
272+ className={ 'mono mt-4' }
273+ prop-size={ 'md' }
274+ prop-format={ 'innerLabel' }
275+ value={ gasPrice }
276+ onChange={ setGasPrice }
277+ >
278+ <InnerLabel>
279+ { 'Gas Price (gwei)' }
280+ </InnerLabel>
281+ </Input>
219282
220− return (
221− <React.Fragment>
222− { generateTxnButton }
223− { unsignedTxnDisplay }
283+ const gasLimitDialogue =
284+ <Input
285+ className={ 'mono mt-4' }
286+ prop-size={ 'md' }
287+ prop-format={ 'innerLabel' }
288+ value={ gasLimit }
289+ onChange={ setGasLimit }>
290+ <InnerLabel>
291+ { 'Gas Limit' }
292+ </InnerLabel>
293+ </Input>
224294
225− { gasPriceRangeDialogue }
226− { toggleGasDetailsDialogue }
295+ const nonceDialogue =
296+ <Input
297+ className={ 'mono mt-4' }
298+ prop-size={ 'md' }
299+ prop-format={ 'innerLabel' }
300+ value={ nonce }
301+ onChange={ setNonce }
302+ >
303+ <InnerLabel>
304+ { 'Nonce' }
305+ </InnerLabel>
306+ </Input>
227307
228− { showGasDetails &&
308+ const chainDialogue =
309+ <Input
310+ className={ 'mono mt-4 mb-8' }
311+ prop-size={ 'md' }
312+ prop-format={ 'innerLabel' }
313+ value={ chainId }
314+ onChange={ setChainId }
315+ >
316+ <InnerLabel>
317+ { 'Chain ID' }
318+ </InnerLabel>
319+ </Input>
320+
321+ const onlineParamsDialogue = web3.matchWith({
322+ Just: _ => <div />,
323+ Nothing: _ =>
324+ <React.Fragment>
325+ { nonceDialogue }
326+ { chainDialogue }
327+ </React.Fragment>
328+ })
329+
330+ const signTxnButton =
331+ <Button
332+ disabled={ !canSign }
333+ className={ 'mt-8' }
334+ prop-size={ 'lg wide' }
335+ prop-color={ signerButtonColor }
336+ onClick={ () => signTransaction({...this.props, ...this.state, setStx: this.setStx}) }
337+ >
338+ { 'Sign Transaction' }
339+ </Button>
340+
341+ const signedTxnDisplay = stx.matchWith({
342+ Nothing: _ => '',
343+ Just: tx =>
344+ <React.Fragment>
345+ <H3 className={ 'mt-8' }>
346+ { 'Signed Transaction' }
347+ </H3>
348+ <Code>
349+ { JSON.stringify(renderSignedTx(tx.value), null, 2) }
350+ </Code>
351+ </React.Fragment>
352+ })
353+
354+ const confirmButton =
355+ <CheckboxButton
356+ className={ 'mt-8' }
357+ disabled={ !canApprove }
358+ onClick={ setUserApproval }
359+ state={ userApproval }
360+ >
229361 <div>
230− { gasPriceDialogue }
231− { gasLimitDialogue }
362+ { `I approve this transaction and wish to send.` }
232363 </div>
233− }
234− { onlineParamsDialogue }
364+ </CheckboxButton>
235365
236− { signTxnButton }
366+ const sendTxnButton =
367+ <Button
368+ prop-size={ 'xl wide' }
369+ className={ 'mt-8' }
370+ disabled={ !canSend }
371+ onClick={ sendTxn }
372+ >
373+ <span className="relative">
374+ <span className="btn-spinner hide"></span>
375+ { 'Send Transaction' }
376+ </span>
377+ </Button>
237378
238− { signedTxnDisplay }
239− { sendDialogue }
240− </React.Fragment>
241− )
379+ const sendDialogue = web3.matchWith({
380+ Nothing: _ => '',
381+ Just: _ =>
382+ <React.Fragment>
383+ { confirmButton }
384+ { sendTxnButton }
385+ </React.Fragment>
386+ })
387+
388+ const txnErrorDialogue = Nothing.hasInstance(state.txError)
389+ ? ''
390+ : <Warning className={'mt-8'}>
391+ <H3 style={{marginTop: 0, paddingTop: 0}}>
392+ {
393+ 'There was an error sending your transaction.'
394+ }
395+ </H3>
396+ { state.txError.value }
397+ </Warning>
398+
399+ return (
400+ <React.Fragment>
401+ { generateTxnButton }
402+ { unsignedTxnDisplay }
403+
404+ { gasPriceRangeDialogue }
405+ { toggleGasDetailsDialogue }
406+
407+ { showGasDetails &&
408+ <div>
409+ { gasPriceDialogue }
410+ { gasLimitDialogue }
411+ </div>
412+ }
413+ { onlineParamsDialogue }
414+
415+ { signTxnButton }
416+
417+ { signedTxnDisplay }
418+ { sendDialogue }
419+
420+ { txnErrorDialogue }
421+ </React.Fragment>
422+ )
423+ }
242424}
243425
244426export default StatelessTransaction
src/bridge/style/extend.css+5
@@ -466,6 +466,11 @@ code {
466466 cursor: pointer;
467467}
468468
469+.text-link {
470+ cursor: pointer;
471+ text-decoration: underline;
472+}
473+
469474.keyfile {
470475 white-space: pre-wrap;
471476 word-break: break-word;
src/bridge/views/AcceptTransfer.js+11−179
@@ -1,6 +1,6 @@
1−import { Just, Nothing } from 'folktale/maybe'
1+import { Just } from 'folktale/maybe'
22import React from 'react'
3−import { Row, Col, H1, H3, P, Warning } from '../components/Base'
3+import { Row, Col, H1, P } from '../components/Base'
44import { InnerLabel, AddressInput, ShowBlockie, Anchor } from '../components/Base'
55import * as azimuth from 'azimuth-js'
66import * as ob from 'urbit-ob'
@@ -8,8 +8,6 @@ import * as ob from 'urbit-ob'
88import StatelessTransaction from '../components/StatelessTransaction'
99import { BRIDGE_ERROR } from '../lib/error'
1010import { NETWORK_NAMES } from '../lib/network'
11−import { ROUTE_NAMES } from '../lib/router'
12−import { sendSignedTransaction, fromWei } from '../lib/txn'
1311import { isValidAddress, addressFromSecp256k1Public } from '../lib/wallet'
1412
1513class AcceptTransfer extends React.Component {
@@ -32,144 +30,17 @@ class AcceptTransfer extends React.Component {
3230
3331 this.state = {
3432 receivingAddress: receivingAddress,
35− txn: Nothing(),
36− txError: Nothing(),
3733 incomingPoint: incomingPoint,
38− userApproval: false,
39− nonce: '',
40− gasPrice: '5',
41− showGasDetails: false,
42− chainId: '',
43− gasLimit: '600000',
44− stx: Nothing(),
4534 }
4635
4736 this.handleAddressInput = this.handleAddressInput.bind(this)
48− this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this)
49− this.handleSubmit = this.handleSubmit.bind(this)
50− this.handleSetUserApproval = this.handleSetUserApproval.bind(this)
51− this.handleSetTxn = this.handleSetTxn.bind(this)
52− this.handleSetStx = this.handleSetStx.bind(this)
53− this.handleSetNonce = this.handleSetNonce.bind(this)
54− this.handleSetChainId = this.handleSetChainId.bind(this)
55− this.handleSetGasPrice = this.handleSetGasPrice.bind(this)
56− this.handleSetGasLimit = this.handleSetGasLimit.bind(this)
57− this.toggleGasDetails = this.toggleGasDetails.bind(this)
58− }
59−
60− toggleGasDetails() {
61− this.setState({
62− showGasDetails: !this.state.showGasDetails
63− })
64− }
65−
66− componentDidMount() {
67− const { props } = this
68−
69− const addr = props.wallet.matchWith({
70− Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
71− Nothing: () => {
72− throw BRIDGE_ERROR.MISSING_WALLET
73− }
74− })
75−
76− props.web3.matchWith({
77− Nothing: () => {},
78− Just: (w3) => {
79− const validWeb3 = w3.value
80−
81− const getTxMetadata = [
82− validWeb3.eth.getTransactionCount(addr),
83− validWeb3.eth.net.getId(),
84− validWeb3.eth.getGasPrice()
85− ];
86−
87− Promise.all(getTxMetadata).then(r => {
88− const txMetadata = {
89− nonce: r[0],
90− chainId: r[1],
91− gasPrice: fromWei(r[2], 'gwei'),
92− };
93−
94− this.setState({...txMetadata})
95−
96− })
97− }
98− });
37+ this.createUnsignedTxn = this.createUnsignedTxn.bind(this)
38+ this.statelessRef = React.createRef();
9939 }
10040
10141 handleAddressInput(proxyAddress) {
10242 this.setState({ proxyAddress })
103− this.handleClearTxn()
104− }
105−
106− handleCreateUnsignedTxn() {
107− const txn = this.createUnsignedTxn()
108− this.setState({ txn })
109− }
110−
111− handleSetUserApproval(){
112− const {state} = this
113− this.setState({ userApproval: !state.userApproval })
114− }
115−
116− handleSetTxn(txn){
117− this.setState({ txn })
118− }
119−
120− handleSetStx(stx){
121− this.setState({
122− stx,
123− userApproval: false,
124− })
125− }
126−
127− handleSetNonce(nonce){
128− this.setState({ nonce })
129− this.handleClearStx()
130− }
131−
132− handleSetChainId(chainId){
133− this.setState({ chainId })
134− this.handleClearStx()
135− }
136−
137− handleSetGasPrice(gasPrice){
138− this.setState({ gasPrice })
139− this.handleClearStx()
140− }
141−
142− handleSetGasLimit(gasLimit){
143− this.setState({ gasLimit })
144− this.handleClearStx()
145− }
146−
147− handleClearStx() {
148− this.setState({
149− userApproval: false,
150− stx: Nothing(),
151− })
152− }
153−
154− handleClearTxn() {
155− this.setState({
156− userApproval: false,
157− txn: Nothing(),
158− stx: Nothing(),
159− })
160− }
161−
162− handleSubmit() {
163− const { props, state } = this
164− sendSignedTransaction(props.web3.value, state.stx)
165− .then(sent => {
166− props.setTxnHashCursor(sent)
167− props.popRoute()
168− props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
169− })
170− .catch(err => {
171− this.setState({ txError: err.map(val => val.merge()) })
172− })
43+ this.statelessRef.current.clearTxn()
17344 }
17445
17546 createUnsignedTxn() {
@@ -200,15 +71,9 @@ class AcceptTransfer extends React.Component {
20071 }
20172
20273 render() {
203−
20474 const { state, props } = this
20575 const validAddress = isValidAddress(state.receivingAddress)
20676 const canGenerate = validAddress === true
207− const canSign = Just.hasInstance(state.txn)
208− const canApprove = Just.hasInstance(state.stx)
209− const canSend =
210− Just.hasInstance(state.stx)
211− && state.userApproval === true
21277
21378 const esvisible =
21479 props.networkType === NETWORK_NAMES.ROPSTEN ||
@@ -260,46 +125,13 @@ class AcceptTransfer extends React.Component {
260125 walletType={props.walletType}
261126 walletHdPath={props.walletHdPath}
262127 networkType={props.networkType}
263− // Tx
264− txn={state.txn}
265− stx={state.stx}
266− // Tx details
267− nonce={state.nonce}
268− gasPrice={state.gasPrice}
269− chainId={state.chainId}
270− gasLimit={state.gasLimit}
271− showGasDetails={state.showGasDetails}
272− toggleGasDetails={this.toggleGasDetails}
273− // Checks
274− userApproval={state.userApproval}
128+ setTxnHashCursor={props.setTxnHashCursor}
129+ popRoute={props.popRoute}
130+ pushRoute={props.pushRoute}
131+ // Other
275132 canGenerate={ canGenerate }
276− canSign={ canSign }
277− canApprove={ canApprove }
278− canSend={ canSend }
279− // Methods
280− createUnsignedTxn={this.handleCreateUnsignedTxn}
281− setUserApproval={this.handleSetUserApproval}
282− setTxn={this.handleSetTxn}
283− setStx={this.handleSetStx}
284− setNonce={this.handleSetNonce}
285− setChainId={this.handleSetChainId}
286− setGasPrice={this.handleSetGasPrice}
287− setGasLimit={this.handleSetGasLimit}
288− handleSubmit={this.handleSubmit} />
289−
290− {
291− Nothing.hasInstance(state.txError)
292− ? ''
293− : <Warning className={'mt-8'}>
294− <H3 style={{marginTop: 0, paddingTop: 0}}>
295− {
296− 'There was an error sending your transaction.'
297− }
298− </H3>
299− { state.txError.value }
300− </Warning>
301− }
302−
133+ createUnsignedTxn={this.createUnsignedTxn}
134+ ref={ this.statelessRef } />
303135 </Col>
304136 </Row>
305137 )
src/bridge/views/CancelTransfer.js+7−197
@@ -1,23 +1,12 @@
11import Maybe from 'folktale/maybe'
22import React from 'react'
3−import { Row, Col, H1, P, Warning, H3 } from '../components/Base'
3+import { Row, Col, H1, P } from '../components/Base'
44import * as azimuth from 'azimuth-js'
55import * as ob from 'urbit-ob'
66
77import StatelessTransaction from '../components/StatelessTransaction'
88import { BRIDGE_ERROR } from '../lib/error'
99import { ETH_ZERO_ADDR } from '../lib/wallet'
10−import { ROUTE_NAMES } from '../lib/router'
11−
12−import {
13− sendSignedTransaction,
14− fromWei,
15− } from '../lib/txn'
16−
17−import {
18− addressFromSecp256k1Public,
19−} from '../lib/wallet'
20−
2110
2211class CancelTransfer extends React.Component {
2312 constructor(props) {
@@ -32,150 +21,10 @@ class CancelTransfer extends React.Component {
3221
3322 this.state = {
3423 proxyAddress: '',
35− txn: Maybe.Nothing(),
36− txError: Maybe.Nothing(),
3724 pointInTransfer: pointInTransfer,
38− userApproval: false,
39− nonce: '',
40− gasPrice: '5',
41− showGasDetails: false,
42− chainId: '',
43− gasLimit: '600000',
44− stx: Maybe.Nothing(),
4525 }
46− // Transaction
47− this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this)
48− this.handleSubmit = this.handleSubmit.bind(this)
49− this.handleSetUserApproval = this.handleSetUserApproval.bind(this)
50− this.handleSetTxn = this.handleSetTxn.bind(this)
51− this.handleSetStx = this.handleSetStx.bind(this)
52− this.handleSetNonce = this.handleSetNonce.bind(this)
53− this.handleSetChainId = this.handleSetChainId.bind(this)
54− this.handleSetGasPrice = this.handleSetGasPrice.bind(this)
55− this.handleSetGasLimit = this.handleSetGasLimit.bind(this)
56− this.toggleGasDetails = this.toggleGasDetails.bind(this)
57− }
5826
59− toggleGasDetails() {
60− this.setState({
61− showGasDetails: !this.state.showGasDetails
62− })
63− }
64−
65− componentDidMount() {
66− const { props } = this
67−
68− const addr = props.wallet.matchWith({
69− Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
70− Nothing: () => {
71− throw BRIDGE_ERROR.MISSING_WALLET
72− }
73− })
74−
75− props.web3.matchWith({
76− Nothing: () => {},
77− Just: (w3) => {
78− const validWeb3 = w3.value
79−
80− const getTxMetadata = [
81− validWeb3.eth.getTransactionCount(addr),
82− validWeb3.eth.net.getId(),
83− validWeb3.eth.getGasPrice()
84− ];
85−
86− Promise.all(getTxMetadata).then(r => {
87− const txMetadata = {
88− nonce: r[0],
89− chainId: r[1],
90− gasPrice: fromWei(r[2], 'gwei'),
91− };
92−
93− this.setState({...txMetadata})
94−
95− })
96− }
97− });
98−
99− }
100−
101−
102−
103− handleCreateUnsignedTxn() {
104− const txn = this.createUnsignedTxn()
105− this.setState({ txn })
106− }
107−
108−
109−
110− handleSetUserApproval(){
111− const {state} = this
112− this.setState({ userApproval: !state.userApproval })
113− }
114−
115−
116−
117− handleSetTxn(txn){
118− this.setState({ txn })
119− }
120−
121−
122−
123− handleSetStx(stx){
124− this.setState({
125− stx,
126− userApproval: false,
127− })
128− }
129−
130−
131−
132− handleSetNonce(nonce){
133− this.setState({ nonce })
134− this.handleClearStx()
135− }
136−
137−
138−
139− handleSetChainId(chainId){
140− this.setState({ chainId })
141− this.handleClearStx()
142− }
143−
144−
145−
146− handleSetGasPrice(gasPrice){
147− this.setState({ gasPrice })
148− this.handleClearStx()
149− }
150−
151−
152−
153− handleSetGasLimit(gasLimit){
154− this.setState({ gasLimit })
155− this.handleClearStx()
156− }
157−
158−
159−
160− handleClearStx() {
161− this.setState({
162− userApproval: false,
163− stx: Maybe.Nothing(),
164− })
165− }
166−
167−
168− handleSubmit(){
169− const { props, state } = this
170− sendSignedTransaction(props.web3.value, state.stx)
171− .then(sent => {
172− props.setTxnHashCursor(sent)
173− props.popRoute()
174− props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
175− })
176− .catch(err => {
177− this.setState({ txError: err.map(val => val.merge()) })
178− })
27+ this.createUnsignedTxn = this.createUnsignedTxn.bind(this)
17928 }
18029
18130 createUnsignedTxn() {
@@ -204,7 +53,6 @@ class CancelTransfer extends React.Component {
20453 return Maybe.Just(txn)
20554 }
20655
207−
20856 render() {
20957 const { props, state } = this
21058
@@ -217,10 +65,6 @@ class CancelTransfer extends React.Component {
21765 // const canGenerate = validAddress === true
21866
21967 const canGenerate = true
220− const canSign = Maybe.Just.hasInstance(state.txn)
221− const canApprove = Maybe.Just.hasInstance(state.stx)
222− const canSend = Maybe.Just.hasInstance(state.stx) && state.userApproval === true
223−
22468
22569 return (
22670 <Row>
@@ -242,46 +86,12 @@ class CancelTransfer extends React.Component {
24286 walletType={props.walletType}
24387 walletHdPath={props.walletHdPath}
24488 networkType={props.networkType}
245− // Tx
246− txn={state.txn}
247− stx={state.stx}
248− // Tx details
249− nonce={state.nonce}
250− gasPrice={state.gasPrice}
251− chainId={state.chainId}
252− gasLimit={state.gasLimit}
253− showGasDetails={state.showGasDetails}
254− toggleGasDetails={this.toggleGasDetails}
255− // Checks
256− userApproval={state.userApproval}
89+ setTxnHashCursor={props.setTxnHashCursor}
90+ popRoute={props.popRoute}
91+ pushRoute={props.pushRoute}
92+ // Other
25793 canGenerate={ canGenerate }
258− canSign={ canSign }
259− canApprove={ canApprove }
260− canSend={ canSend }
261− // Methods
262− createUnsignedTxn={this.handleCreateUnsignedTxn}
263− setUserApproval={this.handleSetUserApproval}
264− setTxn={this.handleSetTxn}
265− setStx={this.handleSetStx}
266− setNonce={this.handleSetNonce}
267− setChainId={this.handleSetChainId}
268− setGasPrice={this.handleSetGasPrice}
269− setGasLimit={this.handleSetGasLimit}
270− handleSubmit={this.handleSubmit} />
271−
272− {
273− Maybe.Nothing.hasInstance(state.txError)
274− ? ''
275− : <Warning className={'mt-8'}>
276− <H3 style={{marginTop: 0, paddingTop: 0}}>
277− {
278− 'There was an error sending your transaction.'
279− }
280− </H3>
281− { state.txError.value }
282− </Warning>
283− }
284−
94+ createUnsignedTxn={this.createUnsignedTxn} />
28595 </Col>
28696 </Row>
28797 )
src/bridge/views/CreateGalaxy.js+18−96
@@ -9,16 +9,8 @@ import { InnerLabel, GalaxyInput, AddressInput, ValidatedSigil, ShowBlockie } fr
99import StatelessTransaction from '../components/StatelessTransaction'
1010
1111import { BRIDGE_ERROR } from '../lib/error'
12−
1312import { NETWORK_NAMES } from '../lib/network'
14−
15−import {
16− sendSignedTransaction,
17− getTxnInfo,
18− canDecodePatp
19−} from '../lib/txn'
20−
21−import { ROUTE_NAMES } from '../lib/router'
13+import { canDecodePatp } from '../lib/txn'
2214
2315import {
2416 addressFromSecp256k1Public,
@@ -61,54 +53,23 @@ class CreateGalaxy extends React.Component {
6153 galaxyOwner: galaxyOwner,
6254 galaxyName: '',
6355 isAvailable: null,
64− txApproval: false,
65− nonce: '',
66− gasPrice: '5',
67− showGasDetails: false,
68− chainId: '',
69− txInfo: '',
70− gasLimit: '600000',
71− txn: Maybe.Nothing(),
72− stx: Maybe.Nothing(),
7356 }
7457
7558 this.handleAddressInput = this.handleAddressInput.bind(this)
7659 this.handleGalaxyNameInput = this.handleGalaxyNameInput.bind(this)
7760 this.confirmAvailability = this.confirmAvailability.bind(this)
78− this.handleSubmit = this.handleSubmit.bind(this)
79− this.toggleGasDetails = this.toggleGasDetails.bind(this)
80− }
81−
82− toggleGasDetails() {
83− this.setState({
84− showGasDetails: !this.state.showGasDetails
85− })
61+ this.createUnsignedTxn = this.createUnsignedTxn.bind(this)
62+ this.statelessRef = React.createRef();
8663 }
8764
88− componentDidMount() {
89− const { props } = this
90− const addr = props.wallet.matchWith({
91− Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
92− Nothing: () => {
93− throw BRIDGE_ERROR.MISSING_WALLET
94− }
95− })
96−
97− // getTxnInfo(props.web3.value, addr).then(txInfo => this.setState(txInfo))
98− props.web3.map(w3 => getTxnInfo(w3, addr)
99− .then(txInfo => this.setState(txInfo))
100− )
101− }
102−
103−
10465 handleGalaxyNameInput = (galaxyName) => {
10566 this.setState({ galaxyName, isAvailable: null })
106− this.clearTransaction()
67+ this.statelessRef.current.clearTxn()
10768 }
10869
10970 handleAddressInput = (galaxyOwner) => {
11071 this.setState({ galaxyOwner })
111− this.clearTransaction()
72+ this.statelessRef.current.clearTxn()
11273 }
11374
11475 createUnsignedTxn = () => {
@@ -133,18 +94,7 @@ class CreateGalaxy extends React.Component {
13394 state.galaxyOwner
13495 )
13596
136− this.setState({ txn: Maybe.Just(txn) })
137− }
138−
139−
140− handleSubmit = () => {
141− const { props, state } = this
142− sendSignedTransaction(props.web3.value, state.stx)
143− .then(sent => {
144− props.setTxnHashCursor(sent)
145− props.popRoute()
146− props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
147− })
97+ return Maybe.Just(txn)
14898 }
14999
150100 confirmAvailability = async () => {
@@ -174,21 +124,16 @@ class CreateGalaxy extends React.Component {
174124 this.setState({ isAvailable: available })
175125 }
176126
177−
178− clearTransaction = () => {
179− this.setState({
180− txApproval: false,
181− txn: Maybe.Nothing(),
182− stx: Maybe.Nothing(),
183− })
184− }
185−
186127 render() {
187128 const { props, state } = this
188129
189130 const validAddress = isValidAddress(state.galaxyOwner)
190131 const validGalaxy = isValidGalaxy(state.galaxyName)
191132
133+ const canGenerate = validAddress === true &&
134+ validGalaxy === true &&
135+ state.isAvailable === true
136+
192137 const esvisible =
193138 props.networkType === NETWORK_NAMES.ROPSTEN ||
194139 props.networkType === NETWORK_NAMES.MAINNET
@@ -259,43 +204,20 @@ class CreateGalaxy extends React.Component {
259204 </Button>
260205
261206 <StatelessTransaction
262− address={state.galaxyOwner}
263− shipName={state.galaxyName}
264− isAvailable={state.isAvailable}
207+ // Upper scope
265208 web3={props.web3}
266209 contracts={props.contracts}
267210 wallet={props.wallet}
268211 walletType={props.walletType}
269212 walletHdPath={props.walletHdPath}
270213 networkType={props.networkType}
271− // Tx
272− txApproval={state.txApproval}
273− txn={state.txn}
274− stx={state.stx}
275− nonce={state.nonce}
276− gasPrice={state.gasPrice}
277− showGasDetails={state.showGasDetails}
278− toggleGasDetails={this.toggleGasDetails}
279− chainId={state.chainId}
280− gasLimit={state.gasLimit}
281− canGenerate={
282− validAddress === true &&
283− validGalaxy === true &&
284− state.isAvailable === true
285− }
286− canSign={Maybe.Just.hasInstance(state.txn)}
287− canSend={Maybe.Just.hasInstance(state.stx)}
288− // Methods
289− createUnsignedTxn={() => this.createUnsignedTxn()}
290− clearTransaction={() => this.clearTransaction()}
291− setApproval={() => this.setState({txApproval: !state.txApproval})}
292− setTxn={txn => this.setState({txn})}
293− setStx={stx => this.setState({stx})}
294− setNonce={nonce => this.setState({nonce})}
295− setChainId={chainId => this.setState({chainId})}
296− setGasPrice={gasPrice => this.setState({gasPrice})}
297− setGasLimit={gasLimit => this.setState({gasLimit})}
298− handleSubmit={this.handleSubmit} />
214+ setTxnHashCursor={props.setTxnHashCursor}
215+ popRoute={props.popRoute}
216+ pushRoute={props.pushRoute}
217+ // Other
218+ ref={this.statelessRef}
219+ canGenerate={canGenerate}
220+ createUnsignedTxn={this.createUnsignedTxn} />
299221
300222 </Col>
301223 </Row>
src/bridge/views/IssueChild.js+14−225
@@ -3,23 +3,21 @@ import React from 'react'
33import { azimuth, ecliptic } from 'azimuth-js'
44import * as ob from 'urbit-ob'
55
6−import { Row, Col, H1, H3, P, Anchor, Warning } from '../components/Base'
6+import { Row, Col, H1, P, Anchor } from '../components/Base'
77import { Button, ShowBlockie, ValidatedSigil } from '../components/Base'
88import { PointInput, AddressInput, InnerLabel } from '../components/Base'
99
1010import StatelessTransaction from '../components/StatelessTransaction'
1111
12−import { ROUTE_NAMES } from '../lib/router'
1312import { NETWORK_NAMES } from '../lib/network'
1413import { BRIDGE_ERROR } from '../lib/error'
1514import { getSpawnCandidate } from '../lib/child'
16−import { canDecodePatp, sendSignedTransaction, fromWei } from '../lib/txn'
15+import { canDecodePatp } from '../lib/txn'
1716
1817import {
1918 ETH_ZERO_ADDR,
2019 isValidAddress,
21− eqAddr,
22− addressFromSecp256k1Public
20+ eqAddr
2321} from '../lib/wallet'
2422
2523class IssueChild extends React.Component {
@@ -43,100 +41,35 @@ class IssueChild extends React.Component {
4341 ]
4442
4543 this.state = {
46− txError: Nothing(),
4744 receivingAddress: '',
4845 issuingPoint: issuingPoint,
4946 desiredPoint: '',
5047 isAvailable: Nothing(), // use Nothing to allow attempt when offline
51− userApproval: false,
52− nonce: '',
53− gasPrice: '5',
54− showGasDetails: false,
55− chainId: '',
56− gasLimit: '600000',
57− txn: Nothing(),
58− stx: Nothing(),
5948 suggestions: suggestions,
6049 }
6150
6251 this.handlePointInput = this.handlePointInput.bind(this)
6352 this.handleAddressInput = this.handleAddressInput.bind(this)
6453 this.handleConfirmAvailability = this.handleConfirmAvailability.bind(this)
65− this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this)
66− this.handleSubmit = this.handleSubmit.bind(this)
67− this.handleSetUserApproval = this.handleSetUserApproval.bind(this)
68− this.handleSetTxn = this.handleSetTxn.bind(this)
69− this.handleSetStx = this.handleSetStx.bind(this)
70− this.handleSetNonce = this.handleSetNonce.bind(this)
71− this.handleSetChainId = this.handleSetChainId.bind(this)
72− this.handleSetGasPrice = this.handleSetGasPrice.bind(this)
73− this.handleSetGasLimit = this.handleSetGasLimit.bind(this)
74− this.toggleGasDetails = this.toggleGasDetails.bind(this)
54+ this.createUnsignedTxn = this.createUnsignedTxn.bind(this)
55+ this.statelessRef = React.createRef();
7556 }
7657
77− toggleGasDetails() {
78− this.setState({
79− showGasDetails: !this.state.showGasDetails
80− })
81− }
82−
83− componentDidMount() {
84− const { props } = this
85−
86− const addr = props.wallet.matchWith({
87− Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
88− Nothing: () => {
89− throw BRIDGE_ERROR.MISSING_WALLET
90− }
91− })
92−
93− props.web3.matchWith({
94− Nothing: () => {},
95− Just: (w3) => {
96− const validWeb3 = w3.value
97−
98− const getTxMetadata = [
99− validWeb3.eth.getTransactionCount(addr),
100− validWeb3.eth.net.getId(),
101− validWeb3.eth.getGasPrice()
102− ]
103−
104− Promise.all(getTxMetadata).then(r => {
105− const txMetadata = {
106− nonce: r[0],
107− chainId: r[1],
108− gasPrice: fromWei(r[2], 'gwei'),
109− }
110−
111− this.setState({...txMetadata})
112−
113− })
114− }
115− })
116−
117− }
118−
119−
120−
12158 handleAddressInput = (receivingAddress) => {
12259 this.setState({ receivingAddress })
123− this.handleClearTxn()
60+ this.statelessRef.current.clearTxn()
12461 }
12562
126−
127−
12863 handlePointInput(desiredPoint) {
12964 if (desiredPoint.length < 15) {
13065 this.setState({
13166 desiredPoint,
13267 isAvailable: Nothing()
13368 })
134− this.handleClearTxn()
69+ this.statelessRef.current.clearTxn()
13570 }
13671 }
13772
138−
139−
14073 handleConfirmAvailability() {
14174 this.confirmPointAvailability().then(r => {
14275 this.setState({
@@ -146,106 +79,6 @@ class IssueChild extends React.Component {
14679
14780 }
14881
149−
150−
151− handleCreateUnsignedTxn() {
152− const txn = this.createUnsignedTxn()
153− this.setState({ txn })
154− }
155−
156−
157− handleSetUserApproval(){
158− const {state} = this
159− this.setState({ userApproval: !state.userApproval })
160− }
161−
162−
163−
164− handleSetTxn(txn){
165− this.setState({ txn })
166− }
167−
168−
169−
170− handleSetStx(stx){
171− this.setState({
172− stx,
173− userApproval: false,
174− })
175− }
176−
177−
178−
179− handleSetNonce(nonce){
180− this.setState({ nonce })
181− this.handleClearStx()
182− }
183−
184−
185−
186− handleSetChainId(chainId){
187− this.setState({ chainId })
188− this.handleClearStx()
189− }
190−
191−
192−
193− handleSetGasPrice(gasPrice){
194− this.setState({ gasPrice })
195− this.handleClearStx()
196− }
197−
198−
199−
200− handleSetGasLimit(gasLimit){
201− this.setState({ gasLimit })
202− this.handleClearStx()
203− }
204−
205−
206−
207− handleClearStx() {
208− this.setState({
209− userApproval: false,
210− stx: Nothing(),
211− })
212− }
213−
214−
215−
216− handleClearTxn() {
217− this.setState({
218− userApproval: false,
219− txn: Nothing(),
220− stx: Nothing(),
221− })
222− }
223−
224−
225−
226− handleClearTransaction() {
227− this.setState({
228− userApproval: false,
229− txn: Nothing(),
230− stx: Nothing(),
231− })
232− }
233−
234−
235−
236− handleSubmit(){
237− const { props, state } = this
238− sendSignedTransaction(props.web3.value, state.stx)
239− .then(sent => {
240− props.setTxnHashCursor(sent)
241− props.popRoute()
242− props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
243− })
244− .catch(err => {
245− this.setState({ txError: err.map(val => val.merge()) })
246− })
247− }
248−
24982 async confirmPointAvailability() {
25083 const { contracts } = this.props
25184 const { desiredPoint } = this.state
@@ -307,8 +140,6 @@ class IssueChild extends React.Component {
307140 return Just(txn)
308141 }
309142
310−
311−
312143 buttonTriState() {
313144 const a = this.state.isAvailable
314145 if (Nothing.hasInstance(a)) return 'blue'
@@ -316,8 +147,6 @@ class IssueChild extends React.Component {
316147 if (a.value === true) return 'green'
317148 }
318149
319−
320−
321150 buttonTriStateText() {
322151 const a = this.state.isAvailable
323152 if (Nothing.hasInstance(a)) return 'Confirm Availablility'
@@ -343,7 +172,6 @@ class IssueChild extends React.Component {
343172 return vpatp && vchild
344173 }
345174
346−
347175 render() {
348176 const { props, state } = this
349177
@@ -362,12 +190,6 @@ class IssueChild extends React.Component {
362190 }
363191 })
364192
365− const canSign = Just.hasInstance(state.txn)
366− const canApprove = Just.hasInstance(state.stx)
367− const canSend =
368− Just.hasInstance(state.stx)
369− && state.userApproval === true
370−
371193 const esvisible =
372194 props.networkType === NETWORK_NAMES.ROPSTEN ||
373195 props.networkType === NETWORK_NAMES.MAINNET
@@ -480,46 +302,13 @@ class IssueChild extends React.Component {
480302 walletType={props.walletType}
481303 walletHdPath={props.walletHdPath}
482304 networkType={props.networkType}
483− // Tx
484− txn={state.txn}
485− stx={state.stx}
486− // Tx details
487− nonce={state.nonce}
488− gasPrice={state.gasPrice}
489− showGasDetails={state.showGasDetails}
490− toggleGasDetails={this.toggleGasDetails}
491− chainId={state.chainId}
492− gasLimit={state.gasLimit}
493− // Checks
494− userApproval={state.userApproval}
495− canGenerate={ canGenerate }
496− canSign={ canSign }
497− canApprove={ canApprove }
498− canSend={ canSend }
499− // Methods
500− createUnsignedTxn={this.handleCreateUnsignedTxn}
501− setUserApproval={this.handleSetUserApproval}
502− setTxn={this.handleSetTxn}
503− setStx={this.handleSetStx}
504− setNonce={this.handleSetNonce}
505− setChainId={this.handleSetChainId}
506− setGasPrice={this.handleSetGasPrice}
507− setGasLimit={this.handleSetGasLimit}
508− handleSubmit={this.handleSubmit} />
509−
510− {
511− Nothing.hasInstance(state.txError)
512− ? ''
513− : <Warning className={'mt-8'}>
514− <H3 style={{marginTop: 0, paddingTop: 0}}>
515− {
516− 'There was an error sending your transaction.'
517− }
518− </H3>
519− { state.txError.value }
520− </Warning>
521− }
522−
305+ setTxnHashCursor={props.setTxnHashCursor}
306+ popRoute={props.popRoute}
307+ pushRoute={props.pushRoute}
308+ // Other
309+ canGenerate={canGenerate}
310+ createUnsignedTxn={this.createUnsignedTxn}
311+ ref={this.statelessRef} />
523312 </Col>
524313 </Row>
525314 )
src/bridge/views/Point/Actions.js−1
@@ -30,7 +30,6 @@ const Actions = (props) => {
3030 eqAddr(details.value.owner, addr) && details.value.active
3131 })
3232
33−
3433 const canSetManagementProxy = pointDetails.matchWith({
3534 Nothing: _ => false,
3635 Just: details =>
src/bridge/views/SetKeys.js+9−223
@@ -2,22 +2,14 @@ import React from 'react'
22import Maybe from 'folktale/maybe'
33import * as azimuth from 'azimuth-js'
44import * as ob from 'urbit-ob'
5−import { Row, Col, H1, P, Warning, H3 } from '../components/Base'
5+import { Row, Col, H1, P, Warning } from '../components/Base'
66
77import StatelessTransaction from '../components/StatelessTransaction'
88import { BRIDGE_ERROR } from '../lib/error'
9−import { ROUTE_NAMES } from '../lib/router'
10−import { attemptSeedDerivation, genKey } from '../lib/keys'
11−
12−import saveAs from 'file-saver'
9+import { attemptSeedDerivation } from '../lib/keys'
1310
1411import * as kg from '../../../node_modules/urbit-key-generation/dist/index'
1512
16−import {
17− sendSignedTransaction,
18− fromWei,
19− } from '../lib/txn'
20−
2113import {
2214 addressFromSecp256k1Public,
2315 addHexPrefix
@@ -42,36 +34,12 @@ class SetKeys extends React.Component {
4234 point: point,
4335 cryptoSuiteVersion: 1,
4436 continuity: false,
45− txn: Maybe.Nothing(),
46− txError: Maybe.Nothing(),
4737 isManagementSeed: false,
48− userApproval: false,
49− nonce: '',
50− gasPrice: '5',
51− showGasDetails: false,
52− chainId: '',
53− gasLimit: '600000',
54− stx: Maybe.Nothing(),
5538 }
5639
5740 this.handleNetworkSeedInput = this.handleNetworkSeedInput.bind(this)
5841 // Transaction
59− this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this)
60− this.handleSubmit = this.handleSubmit.bind(this)
61− this.handleSetUserApproval = this.handleSetUserApproval.bind(this)
62− this.handleSetTxn = this.handleSetTxn.bind(this)
63− this.handleSetStx = this.handleSetStx.bind(this)
64− this.handleSetNonce = this.handleSetNonce.bind(this)
65− this.handleSetChainId = this.handleSetChainId.bind(this)
66− this.handleSetGasPrice = this.handleSetGasPrice.bind(this)
67− this.handleSetGasLimit = this.handleSetGasLimit.bind(this)
68− this.toggleGasDetails = this.toggleGasDetails.bind(this)
69− }
70−
71− toggleGasDetails() {
72− this.setState({
73− showGasDetails: !this.state.showGasDetails
74− })
42+ this.createUnsignedTxn = this.createUnsignedTxn.bind(this)
7543 }
7644
7745 componentDidMount() {
@@ -87,30 +55,6 @@ class SetKeys extends React.Component {
8755 })
8856
8957 this.determineManagementSeed(props.contracts.value, addr)
90−
91− props.web3.matchWith({
92− Nothing: () => {},
93− Just: (w3) => {
94− const validWeb3 = w3.value
95−
96− const getTxMetadata = [
97− validWeb3.eth.getTransactionCount(addr),
98− validWeb3.eth.net.getId(),
99− validWeb3.eth.getGasPrice()
100− ];
101−
102− Promise.all(getTxMetadata).then(r => {
103− const txMetadata = {
104− nonce: r[0],
105− chainId: r[1],
106− gasPrice: fromWei(r[2], 'gwei'),
107− };
108−
109− this.setState({...txMetadata})
110−
111− })
112− }
113− });
11458 }
11559
11660 async determineManagementSeed(ctrcs, addr) {
@@ -154,126 +98,6 @@ class SetKeys extends React.Component {
15498 this.setState({ networkSeed })
15599 }
156100
157− handleCreateUnsignedTxn() {
158− const txn = this.createUnsignedTxn()
159− this.setState({ txn })
160− }
161−
162−
163− handleSetUserApproval(){
164− const {state} = this
165− this.setState({ userApproval: !state.userApproval })
166− }
167−
168−
169−
170− handleSetTxn(txn){
171− this.setState({ txn })
172− }
173−
174−
175−
176− handleSetStx(stx){
177− this.setState({
178− stx,
179− userApproval: false,
180− })
181− }
182−
183−
184−
185− handleSetNonce(nonce){
186− this.setState({ nonce })
187− this.handleClearStx()
188− }
189−
190−
191−
192− handleSetChainId(chainId){
193− this.setState({ chainId })
194− this.handleClearStx()
195− }
196−
197−
198−
199− handleSetGasPrice(gasPrice){
200− this.setState({ gasPrice })
201− this.handleClearStx()
202− }
203−
204−
205−
206− handleSetGasLimit(gasLimit){
207− this.setState({ gasLimit })
208− this.handleClearStx()
209− }
210−
211−
212−
213− handleClearStx() {
214− this.setState({
215− userApproval: false,
216− stx: Maybe.Nothing(),
217− })
218− }
219−
220−
221−
222−
223− handleClearTxn() {
224− this.setState({
225− userApproval: false,
226− txn: Maybe.Nothing(),
227− stx: Maybe.Nothing(),
228− })
229− }
230−
231−
232−
233− handleClearTransaction() {
234− this.setState({
235− userApproval: false,
236− txn: Maybe.Nothing(),
237− stx: Maybe.Nothing(),
238− })
239− }
240−
241− downloadKeyfile(networkSeed) {
242− const { pointCache } = this.props
243− const { pointCursor } = this.props
244−
245− const point = pointCursor.matchWith({
246− Just: (pt) => pt.value,
247− Nothing: () => {
248− throw BRIDGE_ERROR.MISSING_POINT
249− }
250− })
251−
252− const pointDetails =
253− point in pointCache
254− ? pointCache[point]
255− : (() => { throw BRIDGE_ERROR.MISSING_POINT })()
256−
257− const revision = parseInt(pointDetails.keyRevisionNumber)
258− const keyfile = genKey(networkSeed, point, revision)
259− let blob = new Blob([keyfile], {type:"text/plain;charset=utf-8"});
260− saveAs(blob, `${ob.patp(point).slice(1)}-${revision}.key`)
261− }
262−
263− handleSubmit(){
264− const { props, state } = this
265− sendSignedTransaction(props.web3.value, state.stx)
266− .then(sent => {
267− props.setNetworkSeedCache(this.state.networkSeed)
268− props.setTxnHashCursor(sent)
269− props.popRoute()
270− props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION, {promptKeyfile: true})
271− })
272− .catch(err => {
273− this.setState({ txError: err.map(val => val.merge()) })
274− })
275− }
276−
277101 createUnsignedTxn() {
278102 const { state, props } = this
279103
@@ -322,13 +146,6 @@ class SetKeys extends React.Component {
322146 state.networkSeed.length === 64
323147 && state.networkSeed.length === 64
324148
325− const canSign = Maybe.Just.hasInstance(state.txn)
326− const canApprove = Maybe.Just.hasInstance(state.stx)
327−
328− const canSend =
329− Maybe.Just.hasInstance(state.stx)
330− && state.userApproval === true
331−
332149 const pointDetails =
333150 state.point in props.pointCache
334151 ? props.pointCache[state.point]
@@ -376,45 +193,14 @@ class SetKeys extends React.Component {
376193 walletType={props.walletType}
377194 walletHdPath={props.walletHdPath}
378195 networkType={props.networkType}
196+ setTxnHashCursor={props.setTxnHashCursor}
197+ popRoute={props.popRoute}
198+ pushRoute={props.pushRoute}
379199 // Tx
380− txn={state.txn}
381− stx={state.stx}
382− // Tx details
383− nonce={state.nonce}
384− gasPrice={state.gasPrice}
385− chainId={state.chainId}
386− gasLimit={state.gasLimit}
387− showGasDetails={state.showGasDetails}
388− toggleGasDetails={this.toggleGasDetails}
389− // Checks
390− userApproval={state.userApproval}
391200 canGenerate={ canGenerate }
392− canSign={ canSign }
393− canApprove={ canApprove }
394− canSend={ canSend }
395− // Methods
396− createUnsignedTxn={this.handleCreateUnsignedTxn}
397− setUserApproval={this.handleSetUserApproval}
398− setTxn={this.handleSetTxn}
399− setStx={this.handleSetStx}
400− setNonce={this.handleSetNonce}
401− setChainId={this.handleSetChainId}
402− setGasPrice={this.handleSetGasPrice}
403− setGasLimit={this.handleSetGasLimit}
404− handleSubmit={this.handleSubmit} />
405−
406− {
407− Maybe.Nothing.hasInstance(state.txError)
408− ? ''
409− : <Warning className={'mt-8'}>
410− <H3 style={{marginTop: 0, paddingTop: 0}}>
411− {
412− 'There was an error sending your transaction.'
413− }
414− </H3>
415− { state.txError.value }
416− </Warning>
417− }
201+ createUnsignedTxn={this.createUnsignedTxn}
202+ networkSeed={ state.networkSeed }
203+ setNetworkSeedCache={ props.setNetworkSeedCache } />
418204
419205 </Col>
420206 </Row>
src/bridge/views/SetProxy.js+13−224
@@ -1,8 +1,8 @@
11import Maybe from 'folktale/maybe'
22import React from 'react'
33import * as azimuth from 'azimuth-js'
4−import { Row, Col, H1, H3, P, InnerLabel, ShowBlockie, Anchor } from '../components/Base'
5−import { AddressInput, Warning } from '../components/Base'
4+import { Row, Col, H1, P, InnerLabel, ShowBlockie, Anchor } from '../components/Base'
5+import { AddressInput } from '../components/Base'
66import * as ob from 'urbit-ob'
77
88import { PROXY_TYPE, renderProxyType } from '../lib/proxy'
@@ -12,17 +12,7 @@ import { NETWORK_NAMES } from '../lib/network'
1212
1313import StatelessTransaction from '../components/StatelessTransaction'
1414
15−import { ROUTE_NAMES } from '../lib/router'
16−
17−import {
18− sendSignedTransaction,
19− fromWei,
20− } from '../lib/txn'
21−
22−import {
23− isValidAddress,
24− addressFromSecp256k1Public,
25−} from '../lib/wallet'
15+import { isValidAddress } from '../lib/wallet'
2616
2717const SetManagementProxy = (props) =>
2818 <SetProxy
@@ -55,181 +45,20 @@ class SetProxy extends React.Component {
5545
5646 this.state = {
5747 proxyAddress: '',
58− txn: Maybe.Nothing(),
59− txError: Maybe.Nothing(),
6048 issuingPoint: issuingPoint,
61− showGasDetails: false,
62− userApproval: false,
63− nonce: '',
64− gasPrice: '5',
65− chainId: '',
66− gasLimit: '600000',
67− stx: Maybe.Nothing(),
6849 }
6950
51+ this.statelessRef = React.createRef();
7052 this.handleAddressInput = this.handleAddressInput.bind(this)
71− // Transaction
72− this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this)
73− this.handleSubmit = this.handleSubmit.bind(this)
74− this.handleSetUserApproval = this.handleSetUserApproval.bind(this)
75− this.handleSetTxn = this.handleSetTxn.bind(this)
76− this.handleSetStx = this.handleSetStx.bind(this)
77− this.handleSetNonce = this.handleSetNonce.bind(this)
78− this.handleSetChainId = this.handleSetChainId.bind(this)
79− this.handleSetGasPrice = this.handleSetGasPrice.bind(this)
80− this.handleSetGasLimit = this.handleSetGasLimit.bind(this)
81− this.toggleGasDetails = this.toggleGasDetails.bind(this)
82− }
83−
84− toggleGasDetails() {
85− this.setState({
86− showGasDetails: !this.state.showGasDetails
87− })
53+ this.createUnsignedTxn = this.createUnsignedTxn.bind(this)
8854 }
8955
90− componentDidMount() {
91− const { props } = this
92−
93− const addr = props.wallet.matchWith({
94− Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
95− Nothing: () => {
96− throw BRIDGE_ERROR.MISSING_WALLET
97− }
98− })
99−
100− props.web3.matchWith({
101− Nothing: () => {},
102− Just: (w3) => {
103− const validWeb3 = w3.value
104−
105− const getTxMetadata = [
106− validWeb3.eth.getTransactionCount(addr),
107− validWeb3.eth.net.getId(),
108− validWeb3.eth.getGasPrice()
109− ];
110−
111− Promise.all(getTxMetadata).then(r => {
112− const txMetadata = {
113− nonce: r[0],
114− chainId: r[1],
115− gasPrice: fromWei(r[2], 'gwei'),
116− };
117−
118− this.setState({...txMetadata})
119−
120− })
121− }
122− });
123−
124− }
125−
126−
127−
12856 handleAddressInput(proxyAddress) {
12957 this.setState({ proxyAddress })
130− this.handleClearTxn()
131− }
132−
133−
134− handleCreateUnsignedTxn() {
135− const txn = this.createUnsignedTxn()
136− this.setState({ txn })
137− }
138−
139−
140− handleSetUserApproval(){
141− const {state} = this
142− this.setState({ userApproval: !state.userApproval })
143− }
144−
145−
146−
147− handleSetTxn(txn){
148− this.setState({ txn })
149− }
150−
151−
152−
153− handleSetStx(stx){
154− this.setState({
155− stx,
156− userApproval: false,
157− })
158− }
159−
160−
16158
162− handleSetNonce(nonce){
163− this.setState({ nonce })
164− this.handleClearStx()
59+ this.statelessRef.current.clearTxn()
16560 }
16661
167−
168−
169− handleSetChainId(chainId){
170− this.setState({ chainId })
171− this.handleClearStx()
172− }
173−
174−
175−
176− handleSetGasPrice(gasPrice){
177− this.setState({ gasPrice })
178− this.handleClearStx()
179− }
180−
181−
182−
183− handleSetGasLimit(gasLimit){
184− this.setState({ gasLimit })
185− this.handleClearStx()
186− }
187−
188−
189−
190− handleClearStx() {
191− this.setState({
192− userApproval: false,
193− stx: Maybe.Nothing(),
194− })
195− }
196−
197−
198−
199− handleClearTxn() {
200− this.setState({
201− userApproval: false,
202− txn: Maybe.Nothing(),
203− stx: Maybe.Nothing(),
204− })
205− }
206−
207−
208−
209− handleClearTransaction() {
210− this.setState({
211− userApproval: false,
212− txn: Maybe.Nothing(),
213− stx: Maybe.Nothing(),
214− })
215− }
216−
217−
218−
219− handleSubmit(){
220− const { props, state } = this
221− sendSignedTransaction(props.web3.value, state.stx)
222− .then(sent => {
223− props.setTxnHashCursor(sent)
224− props.popRoute()
225− props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
226− })
227− .catch(err => {
228− this.setState({ txError: err.map(val => val.merge()) })
229− })
230− }
231−
232−
23362 createUnsignedTxn(proxyAddress) {
23463 const { state, props } = this
23564
@@ -270,19 +99,12 @@ class SetProxy extends React.Component {
27099 }
271100
272101 render() {
273−
274102 const { props, state } = this
275103
276104 const renderedProxyType = renderProxyType(props.proxyType)
277−
278105 const validAddress = isValidAddress(state.proxyAddress)
279−
280106 const canGenerate = validAddress === true
281107
282− const canSign = Maybe.Just.hasInstance(state.txn)
283− const canApprove = Maybe.Just.hasInstance(state.stx)
284− const canSend = Maybe.Just.hasInstance(state.stx) && state.userApproval === true
285−
286108 const esvisible =
287109 props.networkType === NETWORK_NAMES.ROPSTEN ||
288110 props.networkType === NETWORK_NAMES.MAINNET
@@ -339,46 +161,13 @@ class SetProxy extends React.Component {
339161 walletType={props.walletType}
340162 walletHdPath={props.walletHdPath}
341163 networkType={props.networkType}
342− // Tx
343− txn={state.txn}
344− stx={state.stx}
345− // Tx details
346− nonce={state.nonce}
347− gasPrice={state.gasPrice}
348− chainId={state.chainId}
349− gasLimit={state.gasLimit}
350− showGasDetails={state.showGasDetails}
351− toggleGasDetails={this.toggleGasDetails}
352− // Checks
353− userApproval={state.userApproval}
354− canGenerate={ canGenerate }
355− canSign={ canSign }
356− canApprove={ canApprove }
357− canSend={ canSend }
358− // Methods
359− createUnsignedTxn={this.handleCreateUnsignedTxn}
360− setUserApproval={this.handleSetUserApproval}
361− setTxn={this.handleSetTxn}
362− setStx={this.handleSetStx}
363− setNonce={this.handleSetNonce}
364− setChainId={this.handleSetChainId}
365− setGasPrice={this.handleSetGasPrice}
366− setGasLimit={this.handleSetGasLimit}
367− handleSubmit={this.handleSubmit} />
368−
369− {
370− Maybe.Nothing.hasInstance(state.txError)
371− ? ''
372− : <Warning className={'mt-8'}>
373− <H3 style={{marginTop: 0, paddingTop: 0}}>
374− {
375− 'There was an error sending your transaction.'
376− }
377− </H3>
378− { state.txError.value }
379− </Warning>
380− }
381−
164+ setTxnHashCursor={props.setTxnHashCursor}
165+ popRoute={props.popRoute}
166+ pushRoute={props.pushRoute}
167+ // Other
168+ ref={this.statelessRef}
169+ createUnsignedTxn={this.createUnsignedTxn}
170+ canGenerate={ canGenerate } />
382171 </Col>
383172 </Row>
384173 )
src/bridge/views/Transfer.js+12−222
@@ -4,22 +4,15 @@ import * as azimuth from 'azimuth-js'
44import * as ob from 'urbit-ob'
55
66import { Row, Col, H1, InnerLabel, ShowBlockie, P, Anchor } from '../components/Base'
7−import { AddressInput, Warning, H3 } from '../components/Base'
7+import { AddressInput } from '../components/Base'
88import StatelessTransaction from '../components/StatelessTransaction'
99
1010import { BRIDGE_ERROR } from '../lib/error'
1111import { NETWORK_NAMES } from '../lib/network'
12−import { ROUTE_NAMES } from '../lib/router'
1312
1413import {
15− sendSignedTransaction,
16− fromWei,
17− } from '../lib/txn'
18−
19− import {
20− isValidAddress,
21− addressFromSecp256k1Public
22− } from '../lib/wallet'
14+ isValidAddress
15+} from '../lib/wallet'
2316
2417class Transfer extends React.Component {
2518 constructor(props) {
@@ -33,191 +26,26 @@ class Transfer extends React.Component {
3326 })
3427
3528 this.state = {
36− txError: Maybe.Nothing(),
3729 receivingAddress: '',
3830 issuingPoint: issuingPoint,
39− userApproval: false,
40− nonce: '',
41− gasPrice: '5',
42− showGasDetails: false,
43− chainId: '',
44− gasLimit: '600000',
45− txn: Maybe.Nothing(),
46− stx: Maybe.Nothing(),
4731 }
48− this.handleAddressInput = this.handleAddressInput.bind(this)
49− // Transaction
50− this.handleCreateUnsignedTxn = this.handleCreateUnsignedTxn.bind(this)
51− this.handleSubmit = this.handleSubmit.bind(this)
52− this.handleSetUserApproval = this.handleSetUserApproval.bind(this)
53− this.handleSetTxn = this.handleSetTxn.bind(this)
54− this.handleSetStx = this.handleSetStx.bind(this)
55− this.handleSetNonce = this.handleSetNonce.bind(this)
56− this.handleSetChainId = this.handleSetChainId.bind(this)
57− this.handleSetGasPrice = this.handleSetGasPrice.bind(this)
58− this.handleSetGasLimit = this.handleSetGasLimit.bind(this)
59− this.toggleGasDetails = this.toggleGasDetails.bind(this)
60− }
61−
62− toggleGasDetails() {
63− this.setState({
64− showGasDetails: !this.state.showGasDetails
65− })
66− }
67−
68− componentDidMount() {
69− const { props } = this
70−
71− const addr = props.wallet.matchWith({
72− Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
73− Nothing: () => {
74− throw BRIDGE_ERROR.MISSING_WALLET
75− }
76− })
77−
78− props.web3.matchWith({
79− Nothing: () => {},
80− Just: (w3) => {
81− const validWeb3 = w3.value
82−
83− const getTxMetadata = [
84− validWeb3.eth.getTransactionCount(addr),
85− validWeb3.eth.net.getId(),
86− validWeb3.eth.getGasPrice()
87− ];
88−
89− Promise.all(getTxMetadata).then(r => {
90− const txMetadata = {
91− nonce: r[0],
92− chainId: r[1],
93− gasPrice: fromWei(r[2], 'gwei'),
94− };
95−
96− this.setState({...txMetadata})
97−
98− })
99− }
100− });
10132
33+ this.handleAddressInput = this.handleAddressInput.bind(this)
34+ this.createUnsignedTxn = this.createUnsignedTxn.bind(this)
35+ this.statelessRef = React.createRef();
10236 }
10337
104−
105−
10638 handleAddressInput(receivingAddress) {
10739 this.setState({ receivingAddress })
108− this.handleClearTxn()
40+ this.statelessRef.current.clearTxn()
10941 }
11042
111−
112−
11343 handleConfirmAvailability() {
11444 this.confirmPointAvailability().then(r => {
11545 this.setState({ isAvailable: r })
11646 })
11747 }
11848
119−
120−
121− handleCreateUnsignedTxn() {
122− const txn = this.createUnsignedTxn()
123− this.setState({ txn })
124− }
125−
126−
127− handleSetUserApproval(){
128− const {state} = this
129− this.setState({ userApproval: !state.userApproval })
130− }
131−
132−
133−
134− handleSetTxn(txn){
135− this.setState({ txn })
136− }
137−
138−
139−
140− handleSetStx(stx){
141− this.setState({
142− stx,
143− userApproval: false,
144− })
145− }
146−
147−
148−
149− handleSetNonce(nonce){
150− this.setState({ nonce })
151− this.handleClearStx()
152− }
153−
154−
155−
156− handleSetChainId(chainId){
157− this.setState({ chainId })
158− this.handleClearStx()
159− }
160−
161−
162−
163− handleSetGasPrice(gasPrice){
164− this.setState({ gasPrice })
165− this.handleClearStx()
166− }
167−
168−
169−
170− handleSetGasLimit(gasLimit){
171− this.setState({ gasLimit })
172− this.handleClearStx()
173− }
174−
175−
176−
177− handleClearStx() {
178− this.setState({
179− userApproval: false,
180− stx: Maybe.Nothing(),
181− })
182− }
183−
184−
185−
186− handleClearTxn() {
187− this.setState({
188− userApproval: false,
189− txn: Maybe.Nothing(),
190− stx: Maybe.Nothing(),
191− })
192− }
193−
194−
195−
196− handleClearTransaction() {
197− this.setState({
198− userApproval: false,
199− txn: Maybe.Nothing(),
200− stx: Maybe.Nothing(),
201− })
202− }
203−
204−
205−
206− handleSubmit(){
207− const { props, state } = this
208− sendSignedTransaction(props.web3.value, state.stx)
209− .then(sent => {
210− props.setTxnHashCursor(sent)
211− props.popRoute()
212− props.pushRoute(ROUTE_NAMES.SENT_TRANSACTION)
213− })
214− .catch(err => {
215− this.setState({ txError: err.map(val => val.merge()) })
216− })
217− }
218−
219−
220−
22149 createUnsignedTxn() {
22250 const { state, props } = this
22351
@@ -244,19 +72,12 @@ class Transfer extends React.Component {
24472 return Maybe.Just(txn)
24573 }
24674
247−
248−
24975 render() {
25076 const { props, state } = this
25177
25278 const validAddress = isValidAddress(state.receivingAddress)
253−
25479 const canGenerate = validAddress === true
25580
256− const canSign = Maybe.Just.hasInstance(state.txn)
257− const canApprove = Maybe.Just.hasInstance(state.stx)
258− const canSend = Maybe.Just.hasInstance(state.stx) && state.userApproval === true
259−
26081 const esvisible =
26182 props.networkType === NETWORK_NAMES.ROPSTEN ||
26283 props.networkType === NETWORK_NAMES.MAINNET
@@ -310,46 +131,15 @@ class Transfer extends React.Component {
310131 walletType={props.walletType}
311132 walletHdPath={props.walletHdPath}
312133 networkType={props.networkType}
313− // Tx
314− txn={state.txn}
315− stx={state.stx}
316− // Tx details
317− nonce={state.nonce}
318− gasPrice={state.gasPrice}
319− chainId={state.chainId}
320− gasLimit={state.gasLimit}
321− showGasDetails={state.showGasDetails}
322− toggleGasDetails={this.toggleGasDetails}
134+ setTxnHashCursor={props.setTxnHashCursor}
135+ popRoute={props.popRoute}
136+ pushRoute={props.pushRoute}
323137 // Checks
324138 userApproval={state.userApproval}
325139 canGenerate={ canGenerate }
326− canSign={ canSign }
327− canApprove={ canApprove }
328− canSend={ canSend }
329140 // Methods
330− createUnsignedTxn={this.handleCreateUnsignedTxn}
331− setUserApproval={this.handleSetUserApproval}
332− setTxn={this.handleSetTxn}
333− setStx={this.handleSetStx}
334− setNonce={this.handleSetNonce}
335− setChainId={this.handleSetChainId}
336− setGasPrice={this.handleSetGasPrice}
337− setGasLimit={this.handleSetGasLimit}
338− handleSubmit={this.handleSubmit} />
339−
340− {
341− Maybe.Nothing.hasInstance(state.txError)
342− ? ''
343− : <Warning className={'mt-8'}>
344− <H3 style={{marginTop: 0, paddingTop: 0}}>
345− {
346− 'There was an error sending your transaction.'
347− }
348− </H3>
349− { state.txError.value }
350− </Warning>
351− }
352−
141+ createUnsignedTxn={this.createUnsignedTxn}
142+ ref={this.statelessRef} />
353143 </Col>
354144 </Row>
355145 )
src/common/components/AppNavigation.js+5−5
@@ -23,17 +23,17 @@ class AppNavigation extends React.Component {
2323 let style = {
2424 position: "fixed",
2525 bottom: "10px",
26− right: "10px"
26+ right: "10px",
27+ "text-decoration": "underline",
28+ cursor: "pointer"
2729 }
2830
2931 return (
30− <a
31− href="javascript:void(0)"
32− type="button"
32+ <span
3333 style={style}
3434 onClick={this.navigate}>
3535 {buttonText}
36− </a>
36+ </span>
3737 )
3838 }
3939}