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