on d6291a2 help sign in
193 lines 4.9 kB history raw
1import Tx from 'ethereumjs-tx'
2import React from 'react'
3import Web3 from 'web3'
4import { Button } from '../Base'
5import { Input, InnerLabel } from '../Base'
7import { ledgerSignTransaction } from '../../lib/ledger'
8import { trezorSignTransaction } from '../../lib/trezor'
9import { WALLET_NAMES, addressFromSecp256k1Public } from '../../lib/wallet'
10import { BRIDGE_ERROR } from '../../lib/error'
12class Signer extends React.Component {
13 constructor(props) {
14 super(props)
16 this.state = {
17 nonce: '',
18 gasPrice: '5',
19 chainId: '',
20 gasLimit: '600000'
21 }
23 const dummy = new Web3()
24 this.toHex = dummy.utils.toHex
25 this.toWei = dummy.utils.toWei
26 this.fromWei = dummy.utils.fromWei
28 this.handleNonceInput = this.handleNonceInput.bind(this)
29 this.handleChainIdInput = this.handleChainIdInput.bind(this)
30 this.handleGasPriceInput = this.handleGasPriceInput.bind(this)
31 this.handleGasLimitInput = this.handleGasLimitInput.bind(this)
32 this.signTransaction = this.signTransaction.bind(this)
33 }
35 componentDidMount() {
36 const { web3, wallet } = this.props
38 const addr = wallet.matchWith({
39 Just: (wal) => addressFromSecp256k1Public(wal.value.publicKey),
40 Nothing: () => {
41 throw BRIDGE_ERROR.MISSING_WALLET
42 }
43 })
45 web3.map(w3 =>
46 this.getTxnInfo(w3, addr)
47 .then(txInfo => this.setState(txInfo))
48 )
49 }
51 getTxnInfo = async (web3, addr) => {
52 let nonce = await web3.eth.getTransactionCount(addr)
53 let chainId = await web3.eth.net.getId()
54 let gasPrice = await web3.eth.getGasPrice()
55 return {
56 nonce: nonce,
57 chainId: chainId,
58 gasPrice: this.fromWei(gasPrice, 'gwei')
59 }
60 }
62 handleNonceInput(nonce) {
63 this.setState({ nonce })
64 }
66 handleChainIdInput(chainId) {
67 this.setState({ chainId })
68 }
70 handleGasPriceInput(gasPrice) {
71 this.setState({ gasPrice })
72 }
74 handleGasLimitInput(gasLimit) {
75 this.setState({ gasLimit })
76 }
78 async signTransaction(signingArgs) {
79 const { wallet, walletType, txn, setSignedTransaction } = this.props
81 let { nonce, chainId, gasPrice, gasLimit } = signingArgs
82 nonce = this.toHex(nonce)
83 chainId = this.toHex(chainId)
84 gasPrice = this.toHex(this.toWei(gasPrice, 'gwei'))
85 gasLimit = this.toHex(gasLimit)
87 const wal = wallet.matchWith({
88 Just: (w) => w.value,
89 Nothing: () => {
90 throw BRIDGE_ERROR.MISSING_WALLET
91 }
92 })
94 const sec = wal.privateKey
96 const utx = txn.matchWith({
97 Just: (tx) =>
98 Object.assign(tx.value, { nonce, chainId, gasPrice, gasLimit }),
99 Nothing: () => {
100 throw BRIDGE_ERROR.MISSING_TXN
101 }
102 })
104 const stx = new Tx(utx)
106 if (walletType === WALLET_NAMES.LEDGER) {
107 await ledgerSignTransaction(stx)
108 } else if (walletType === WALLET_NAMES.TREZOR) {
109 await trezorSignTransaction(stx)
110 } else {
111 stx.sign(sec)
112 }
114 setSignedTransaction(stx)
115 }
117 render() {
119 const { state, props } = this
121 const signingArgs = this.state
122 const { nonce, gasPrice, gasLimit, chainId } = signingArgs
124 const signButton =
125 <Button
126 disabled={ props.disabled }
127 prop-size={'lg wide'}
128 prop-color={this.props['prop-color']}
129 onClick={ () => this.signTransaction(signingArgs) }
130 >
131 { 'Sign Transaction' }
132 </Button>
134 const dialogue = props.web3.matchWith({
135 Just: () => <div />,
136 Nothing: () =>
137 <div>
138 <Input
139 className='mono'
140 prop-size='md'
141 prop-format='innerLabel'
142 value={ state.nonce }
143 onChange={ v => this.handleNonceInput(v) }>
144 <InnerLabel>
145 { 'Nonce' }
146 </InnerLabel>
147 </Input>
149 <Input
150 className='mono mt-4 mb-8'
151 prop-size='md'
152 prop-format='innerLabel'
153 value={ state.chainId }
154 onChange={ v => this.handleChainIdInput(v) }>
155 <InnerLabel>
156 { 'Chain ID' }
157 </InnerLabel>
158 </Input>
160 </div>
161 })
163 return (
164 <div className={this.props.className}>
165 <Input
166 className='mono mt-4'
167 prop-size='md'
168 prop-format='innerLabel'
169 value={ state.gasPrice }
170 onChange={ v => this.handleGasPriceInput(v) }>
171 <InnerLabel>
172 { 'Gas Price (gwei)' }
173 </InnerLabel>
174 </Input>
176 <Input
177 className='mono mt-4'
178 prop-size='md'
179 prop-format='innerLabel'
180 value={ state.gasLimit }
181 onChange={ v => this.handleGasLimitInput(v) }>
182 <InnerLabel>
183 { 'Gas Limit' }
184 </InnerLabel>
185 </Input>
186 { dialogue }
187 { signButton }
188 </div>
189 )
190 }
193export default Signer