on 1fddeb3 help sign in
bridge/src/components/StatelessTransaction.js
240 lines 5.7 kB history raw
1import { Nothing } from 'folktale/maybe'
2import React from 'react'
4import { Code, H3 } from './Base'
5import { Button } from './Base'
6import { CheckboxButton, Input, InnerLabel } from './Base'
8import { renderSignedTx, signTransaction } from '../lib/txn'
10const 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
18 // setState doesn't seem to work in SetProxy/handleSubmit, so just
19 // modifying the DOM manually here. (https://imgur.com/a/i0Qsyq1)
21 const handleRangeChange = (e) => {
22 setGasPrice(e.target.value);
23 }
25 const sendTxn = (e) => {
26 e.target.setAttribute("disabled", true);
27 let spinner = e.target.querySelectorAll('.btn-spinner')[0];
28 spinner.classList.remove('hide');
29 handleSubmit()
30 }
32 const generateButtonColor =
33 Nothing.hasInstance(txn)
34 ? 'blue'
35 : 'green'
37 const signerButtonColor =
38 Nothing.hasInstance(stx)
39 ? 'blue'
40 : 'green'
42 const generateTxnButton =
43 <Button
44 className={ 'mt-8' }
45 disabled={ !canGenerate }
46 prop-color={ generateButtonColor }
47 prop-size={ 'lg wide' }
48 onClick={ createUnsignedTxn }
49 >
50 { 'Generate Transaction' }
51 </Button>
53 const unsignedTxnDisplay = txn.matchWith({
54 Nothing: _ => '',
55 Just: tx =>
56 <React.Fragment>
57 <H3 className={ 'mt-8' }>
58 { 'Unsigned Transaction' }
59 </H3>
60 <Code>
61 { JSON.stringify(tx.value, null, 2) }
62 </Code>
63 </React.Fragment>
64 })
66 const gasPriceRangeDialogue = (
67 <React.Fragment>
68 <div className="mt-8">Gas Price: <span className="ml-4 text-700 text-sm">{gasPrice} gwei</span></div>
70 <input
71 className="mt-4"
72 type="range"
73 min="2"
74 max="20"
75 list="gweiVals"
76 value={gasPrice}
77 onChange={handleRangeChange}
78 />
80 <div className="flex space-between text-sm mb-8">
81 <div>Cheap</div>
82 <div>Fast</div>
83 </div>
84 </React.Fragment>
85 )
87 const toggleGasDetailsDialogue = (
88 <a href="javascript:void(0)" onClick={toggleGasDetails}>Gas Details</a>
89 )
91 const gasPriceDialogue =
92 <Input
93 className={ 'mono mt-4' }
94 prop-size={ 'md' }
95 prop-format={ 'innerLabel' }
96 value={ gasPrice }
97 onChange={ setGasPrice }
98 >
99 <InnerLabel>
100 { 'Gas Price (gwei)' }
101 </InnerLabel>
102 </Input>
104 const gasLimitDialogue =
105 <Input
106 className={ 'mono mt-4' }
107 prop-size={ 'md' }
108 prop-format={ 'innerLabel' }
109 value={ gasLimit }
110 onChange={ setGasLimit }>
111 <InnerLabel>
112 { 'Gas Limit' }
113 </InnerLabel>
114 </Input>
116 const maxTxnPriceInEth = (
117 <div className="mt-8">
118 Max transaction price: <span className="text-700">{(gasPrice * gasLimit) / 1000000000} eth</span>
119 </div>
120 )
122 const nonceDialogue =
123 <Input
124 className={ 'mono mt-4' }
125 prop-size={ 'md' }
126 prop-format={ 'innerLabel' }
127 value={ nonce }
128 onChange={ setNonce }
129 >
130 <InnerLabel>
131 { 'Nonce' }
132 </InnerLabel>
133 </Input>
135 const chainDialogue =
136 <Input
137 className={ 'mono mt-4 mb-8' }
138 prop-size={ 'md' }
139 prop-format={ 'innerLabel' }
140 value={ chainId }
141 onChange={ setChainId }
142 >
143 <InnerLabel>
144 { 'Chain ID' }
145 </InnerLabel>
146 </Input>
148 const onlineParamsDialogue = web3.matchWith({
149 Just: _ => <div />,
150 Nothing: _ =>
151 <React.Fragment>
152 { nonceDialogue }
153 { chainDialogue }
154 </React.Fragment>
155 })
157 const signTxnButton =
158 <Button
159 disabled={ !canSign }
160 className={ 'mt-8' }
161 prop-size={ 'lg wide' }
162 prop-color={ signerButtonColor }
163 onClick={ () => signTransaction(props) }
164 >
165 { 'Sign Transaction' }
166 </Button>
168 const signedTxnDisplay = stx.matchWith({
169 Nothing: _ => '',
170 Just: tx =>
171 <React.Fragment>
172 <H3 className={ 'mt-8' }>
173 { 'Signed Transaction' }
174 </H3>
175 <Code>
176 { JSON.stringify(renderSignedTx(tx.value), null, 2) }
177 </Code>
178 </React.Fragment>
179 })
181 const confirmButton =
182 <CheckboxButton
183 className={ 'mt-8' }
184 disabled={ !canApprove }
185 onClick={ setUserApproval }
186 state={ userApproval }
187 >
188 <div>
189 { `I approve this transaction and wish to send.` }
190 </div>
191 </CheckboxButton>
193 const sendTxnButton =
194 <Button
195 prop-size={ 'xl wide' }
196 className={ 'mt-8' }
197 disabled={ !canSend }
198 onClick={ sendTxn }
199 >
200 <span className="relative">
201 <span className="btn-spinner hide"></span>
202 { 'Send Transaction' }
203 </span>
204 </Button>
206 const sendDialogue = web3.matchWith({
207 Nothing: _ => '',
208 Just: _ =>
209 <React.Fragment>
210 { confirmButton }
211 { sendTxnButton }
212 </React.Fragment>
213 })
215 return (
216 <React.Fragment>
217 { generateTxnButton }
218 { unsignedTxnDisplay }
220 { gasPriceRangeDialogue }
221 { toggleGasDetailsDialogue }
223 { showGasDetails &&
224 <div>
225 { gasPriceDialogue }
226 { gasLimitDialogue }
227 { maxTxnPriceInEth }
228 </div>
229 }
230 { onlineParamsDialogue }
232 { signTxnButton }
234 { signedTxnDisplay }
235 { sendDialogue }
236 </React.Fragment>
237 )
240export default StatelessTransaction