on bdf30a8 help sign in
bridge/src/components/StatelessTransaction.js
242 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-12 flex space-between align-baseline">
69 <div>
70 <span>Gas Price:</span>
71 <span className="ml-4 text-700 text-sm">{gasPrice} gwei</span>
72 </div>
73 <div className="text-sm">
74 <span>Max transaction fee: </span>
75 <span className="text-700">{(gasPrice * gasLimit) / 1000000000} eth</span>
76 </div>
77 </div>
79 <input
80 className="mt-4"
81 type="range"
82 min="2"
83 max="20"
84 list="gweiVals"
85 value={gasPrice}
86 onChange={handleRangeChange}
87 />
89 <div className="flex space-between text-sm mb-8">
90 <div>Cheap</div>
91 <div>Fast</div>
92 </div>
93 </React.Fragment>
94 )
96 const toggleGasDetailsDialogue = (
97 <a href="javascript:void(0)" onClick={toggleGasDetails}>Gas Details</a>
98 )
100 const gasPriceDialogue =
101 <Input
102 className={ 'mono mt-4' }
103 prop-size={ 'md' }
104 prop-format={ 'innerLabel' }
105 value={ gasPrice }
106 onChange={ setGasPrice }
107 >
108 <InnerLabel>
109 { 'Gas Price (gwei)' }
110 </InnerLabel>
111 </Input>
113 const gasLimitDialogue =
114 <Input
115 className={ 'mono mt-4' }
116 prop-size={ 'md' }
117 prop-format={ 'innerLabel' }
118 value={ gasLimit }
119 onChange={ setGasLimit }>
120 <InnerLabel>
121 { 'Gas Limit' }
122 </InnerLabel>
123 </Input>
125 const nonceDialogue =
126 <Input
127 className={ 'mono mt-4' }
128 prop-size={ 'md' }
129 prop-format={ 'innerLabel' }
130 value={ nonce }
131 onChange={ setNonce }
132 >
133 <InnerLabel>
134 { 'Nonce' }
135 </InnerLabel>
136 </Input>
138 const chainDialogue =
139 <Input
140 className={ 'mono mt-4 mb-8' }
141 prop-size={ 'md' }
142 prop-format={ 'innerLabel' }
143 value={ chainId }
144 onChange={ setChainId }
145 >
146 <InnerLabel>
147 { 'Chain ID' }
148 </InnerLabel>
149 </Input>
151 const onlineParamsDialogue = web3.matchWith({
152 Just: _ => <div />,
153 Nothing: _ =>
154 <React.Fragment>
155 { nonceDialogue }
156 { chainDialogue }
157 </React.Fragment>
158 })
160 const signTxnButton =
161 <Button
162 disabled={ !canSign }
163 className={ 'mt-8' }
164 prop-size={ 'lg wide' }
165 prop-color={ signerButtonColor }
166 onClick={ () => signTransaction(props) }
167 >
168 { 'Sign Transaction' }
169 </Button>
171 const signedTxnDisplay = stx.matchWith({
172 Nothing: _ => '',
173 Just: tx =>
174 <React.Fragment>
175 <H3 className={ 'mt-8' }>
176 { 'Signed Transaction' }
177 </H3>
178 <Code>
179 { JSON.stringify(renderSignedTx(tx.value), null, 2) }
180 </Code>
181 </React.Fragment>
182 })
184 const confirmButton =
185 <CheckboxButton
186 className={ 'mt-8' }
187 disabled={ !canApprove }
188 onClick={ setUserApproval }
189 state={ userApproval }
190 >
191 <div>
192 { `I approve this transaction and wish to send.` }
193 </div>
194 </CheckboxButton>
196 const sendTxnButton =
197 <Button
198 prop-size={ 'xl wide' }
199 className={ 'mt-8' }
200 disabled={ !canSend }
201 onClick={ sendTxn }
202 >
203 <span className="relative">
204 <span className="btn-spinner hide"></span>
205 { 'Send Transaction' }
206 </span>
207 </Button>
209 const sendDialogue = web3.matchWith({
210 Nothing: _ => '',
211 Just: _ =>
212 <React.Fragment>
213 { confirmButton }
214 { sendTxnButton }
215 </React.Fragment>
216 })
218 return (
219 <React.Fragment>
220 { generateTxnButton }
221 { unsignedTxnDisplay }
223 { gasPriceRangeDialogue }
224 { toggleGasDetailsDialogue }
226 { showGasDetails &&
227 <div>
228 { gasPriceDialogue }
229 { gasLimitDialogue }
230 </div>
231 }
232 { onlineParamsDialogue }
234 { signTxnButton }
236 { signedTxnDisplay }
237 { sendDialogue }
238 </React.Fragment>
239 )
242export default StatelessTransaction