on 6e83c10 help sign in
bridge/src/lib/useEthereumTransaction.js
179 lines 4.3 kB history raw
1import { useCallback, useState } from 'react';
2import { fromWei } from 'web3-utils';
4import { useNetwork } from 'store/network';
5import { useWallet } from 'store/wallet';
7import {
8 signTransaction,
9 sendSignedTransaction,
10 waitForTransactionConfirm,
11} from './txn';
12import * as need from './need';
13import { GAS_LIMITS } from './constants';
14import useLifecycle from './useLifecycle';
16const STATE = {
17 NONE: 'NONE',
18 SIGNED: 'SIGNED',
19 BROADCASTED: 'BROADCASTED',
20 CONFIRMED: 'CONFIRMED',
21};
23/**
24 * manage the state around sending and confirming an ethereum transaction
25 * @param {number} initialGasLimit
26 */
27export default function useEthereumTransaction(
28 initialGasLimit = GAS_LIMITS.DEFAULT,
29 initialGasPrice = 20
30) {
31 const { wallet, walletType, walletHdPath } = useWallet();
32 const { web3, networkType } = useNetwork();
33 const _web3 = need.web3(web3);
34 const _wallet = need.wallet(wallet);
36 const [error, _setError] = useState();
37 const setError = useCallback(
38 error => {
39 _setError(error);
40 if (error) {
41 console.error(error);
42 }
43 },
44 [_setError]
45 );
46 const [state, setState] = useState(STATE.NONE);
47 const [chainId, setChainId] = useState();
48 const [nonce, setNonce] = useState();
49 const [gasPrice, setGasPrice] = useState(initialGasPrice); // gwei
50 const [gasLimit] = useState(initialGasLimit);
51 const [unsignedTransaction, setUnsignedTransaction] = useState();
52 const [signedTransaction, setSignedTransaction] = useState();
53 const [txHash, setTxHash] = useState();
55 const initializing = nonce === undefined || chainId === undefined;
56 const constructed = !!unsignedTransaction;
57 const signed = state === STATE.SIGNED;
58 const broadcasted = state === STATE.BROADCASTED;
59 const confirmed = state === STATE.CONFIRMED;
61 // disable the inputs when:
62 const inputsLocked = signed || broadcasted || confirmed;
64 // we can sign when:
65 const canSign = !initializing && constructed;
67 const construct = useCallback(txn => setUnsignedTransaction(txn), [
68 setUnsignedTransaction,
69 ]);
71 const generateAndSign = useCallback(async () => {
72 try {
73 setError(undefined);
75 const txn = await signTransaction({
76 wallet: _wallet,
77 walletType,
78 walletHdPath,
79 networkType,
80 txn: unsignedTransaction,
81 nonce,
82 chainId,
83 gasPrice: gasPrice.toFixed(0),
84 gasLimit,
85 });
87 setSignedTransaction(txn);
88 setState(STATE.SIGNED);
89 } catch (error) {
90 setError(error);
91 }
92 }, [
93 _wallet,
94 chainId,
95 gasLimit,
96 gasPrice,
97 networkType,
98 nonce,
99 setError,
100 unsignedTransaction,
101 walletHdPath,
102 walletType,
103 ]);
105 const broadcast = useCallback(async () => {
106 try {
107 setError(undefined);
108 const txHash = await sendSignedTransaction(
109 _web3,
110 signedTransaction,
111 /* doubtNonceError */ false
112 );
114 setState(STATE.BROADCASTED);
115 setTxHash(txHash);
117 await waitForTransactionConfirm(_web3, txHash);
119 setState(STATE.CONFIRMED);
120 } catch (error) {
121 setError(error);
122 }
123 }, [_web3, setError, signedTransaction]);
125 const reset = useCallback(() => {
126 setUnsignedTransaction(undefined);
127 setTxHash(undefined);
128 setSignedTransaction(undefined);
129 setGasPrice(initialGasPrice);
130 setState(STATE.NONE);
131 setError(undefined);
132 }, [initialGasPrice, setError]);
134 useLifecycle(() => {
135 (async () => {
136 try {
137 setError(undefined);
138 const [nonce, chainId, estimatedGasPrice] = await Promise.all([
139 _web3.eth.getTransactionCount(_wallet.address),
140 _web3.eth.net.getId(),
141 _web3.eth.getGasPrice(),
142 ]);
144 setNonce(nonce);
145 setChainId(chainId);
146 setGasPrice(parseInt(fromWei(estimatedGasPrice, 'gwei'), 10));
147 } catch (error) {
148 setError(error);
149 }
150 })();
151 });
153 const values = {
154 initializing,
155 construct,
156 constructed,
157 canSign,
158 generateAndSign,
159 signed,
160 broadcast,
161 broadcasted,
162 confirmed,
163 reset,
164 error,
165 inputsLocked,
166 //
167 txHash,
168 signedTransaction,
169 gasPrice,
170 setGasPrice,
171 nonce,
172 chainId,
173 };
175 return {
176 ...values,
177 bind: values,
178 };