on a54b5ac help sign in
194 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, walletHdPath } = this.props
80 const { setSignedTransaction } = this.props
82 let { nonce, chainId, gasPrice, gasLimit } = signingArgs
83 nonce = this.toHex(nonce)
84 chainId = this.toHex(chainId)
85 gasPrice = this.toHex(this.toWei(gasPrice, 'gwei'))
86 gasLimit = this.toHex(gasLimit)
88 const wal = wallet.matchWith({
89 Just: (w) => w.value,
90 Nothing: () => {
91 throw BRIDGE_ERROR.MISSING_WALLET
92 }
93 })
95 const sec = wal.privateKey
97 const utx = txn.matchWith({
98 Just: (tx) =>
99 Object.assign(tx.value, { nonce, chainId, gasPrice, gasLimit }),
100 Nothing: () => {
101 throw BRIDGE_ERROR.MISSING_TXN
102 }
103 })
105 const stx = new Tx(utx)
107 if (walletType === WALLET_NAMES.LEDGER) {
108 await ledgerSignTransaction(stx, walletHdPath)
109 } else if (walletType === WALLET_NAMES.TREZOR) {
110 await trezorSignTransaction(stx, walletHdPath)
111 } else {
112 stx.sign(sec)
113 }
115 setSignedTransaction(stx)
116 }
118 render() {
120 const { state, props } = this
122 const signingArgs = this.state
123 const { nonce, gasPrice, gasLimit, chainId } = signingArgs
125 const signButton =
126 <Button
127 disabled={ props.disabled }
128 prop-size={'lg wide'}
129 prop-color={this.props['prop-color']}
130 onClick={ () => this.signTransaction(signingArgs) }
131 >
132 { 'Sign Transaction' }
133 </Button>
135 const dialogue = props.web3.matchWith({
136 Just: () => <div />,
137 Nothing: () =>
138 <div>
139 <Input
140 className='mono'
141 prop-size='md'
142 prop-format='innerLabel'
143 value={ state.nonce }
144 onChange={ v => this.handleNonceInput(v) }>
145 <InnerLabel>
146 { 'Nonce' }
147 </InnerLabel>
148 </Input>
150 <Input
151 className='mono mt-4 mb-8'
152 prop-size='md'
153 prop-format='innerLabel'
154 value={ state.chainId }
155 onChange={ v => this.handleChainIdInput(v) }>
156 <InnerLabel>
157 { 'Chain ID' }
158 </InnerLabel>
159 </Input>
161 </div>
162 })
164 return (
165 <div className={this.props.className}>
166 <Input
167 className='mono mt-4'
168 prop-size='md'
169 prop-format='innerLabel'
170 value={ state.gasPrice }
171 onChange={ v => this.handleGasPriceInput(v) }>
172 <InnerLabel>
173 { 'Gas Price (gwei)' }
174 </InnerLabel>
175 </Input>
177 <Input
178 className='mono mt-4'
179 prop-size='md'
180 prop-format='innerLabel'
181 value={ state.gasLimit }
182 onChange={ v => this.handleGasLimitInput(v) }>
183 <InnerLabel>
184 { 'Gas Limit' }
185 </InnerLabel>
186 </Input>
187 { dialogue }
188 { signButton }
189 </div>
190 )
191 }
194export default Signer