on 9b396e2 help sign in
bridge/src/components/StatelessTransaction.js
244 lines 5.8 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 // TODO: Investigate
19 // setState doesn't seem to work in SetProxy/handleSubmit;
20 // - TypeError: Cannot read property 'updater' of undefined
21 // so just modifying the DOM manually here. (https://imgur.com/a/i0Qsyq1)
23 const handleRangeChange = (e) => {
24 setGasPrice(e.target.value);
25 }
27 const sendTxn = (e) => {
28 e.target.setAttribute("disabled", true);
29 let spinner = e.target.querySelectorAll('.btn-spinner')[0];
30 spinner.classList.remove('hide');
31 handleSubmit()
32 }
34 const generateButtonColor =
35 Nothing.hasInstance(txn)
36 ? 'blue'
37 : 'green'
39 const signerButtonColor =
40 Nothing.hasInstance(stx)
41 ? 'blue'
42 : 'green'
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>
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 })
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>
74 </div>
75 <div className="text-sm">
76 <span>Max transaction fee: </span>
77 <span className="text-700">{(gasPrice * gasLimit) / 1000000000} eth</span>
78 </div>
79 </div>
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 />
91 <div className="flex space-between text-sm mb-8">
92 <div>Cheap</div>
93 <div>Fast</div>
94 </div>
95 </React.Fragment>
96 )
98 const toggleGasDetailsDialogue = (
99 <a href="javascript:void(0)" onClick={toggleGasDetails}>Gas Details</a>
100 )
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>
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>
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>
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>
153 const onlineParamsDialogue = web3.matchWith({
154 Just: _ => <div />,
155 Nothing: _ =>
156 <React.Fragment>
157 { nonceDialogue }
158 { chainDialogue }
159 </React.Fragment>
160 })
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>
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 })
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>
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>
211 const sendDialogue = web3.matchWith({
212 Nothing: _ => '',
213 Just: _ =>
214 <React.Fragment>
215 { confirmButton }
216 { sendTxnButton }
217 </React.Fragment>
218 })
220 return (
221 <React.Fragment>
222 { generateTxnButton }
223 { unsignedTxnDisplay }
225 { gasPriceRangeDialogue }
226 { toggleGasDetailsDialogue }
228 { showGasDetails &&
229 <div>
230 { gasPriceDialogue }
231 { gasLimitDialogue }
232 </div>
233 }
234 { onlineParamsDialogue }
236 { signTxnButton }
238 { signedTxnDisplay }
239 { sendDialogue }
240 </React.Fragment>
241 )
244export default StatelessTransaction