on 06b6de4 help sign in
bridge/src/lib/useEthereumTransaction.js
170 lines 4.1 kB history raw
1import { useCallback, useEffect, useState } from 'react';
2import { Just } from 'folktale/maybe';
4import { useNetwork } from 'store/network';
5import { useWallet } from 'store/wallet';
7import {
8 signTransaction,
9 sendSignedTransaction,
10 waitForTransactionConfirm,
11 hexify,
12} from './txn';
13import * as need from './need';
14import { toHex, toWei, fromWei } from 'web3-utils';
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(initialGasLimit = 0) {
28 const { wallet, walletType, walletHdPath } = useWallet();
29 const { web3, networkType } = useNetwork();
30 const _web3 = need.web3(web3);
31 const _wallet = need.wallet(wallet);
33 const [error, setError] = useState();
34 const [state, setState] = useState(STATE.NONE);
35 const [chainId, setChainId] = useState();
36 const [nonce, setNonce] = useState();
37 const [gasPrice, setGasPrice] = useState(20); // gwei
38 const [gasLimit] = useState(initialGasLimit);
39 const [unsignedTransaction, setUnsignedTransaction] = useState();
40 const [signedTransaction, setSignedTransaction] = useState();
42 const initializing = nonce === undefined || chainId === undefined;
43 const constructed = !!unsignedTransaction;
44 const signed = state === STATE.SIGNED;
45 const broadcasted = state === STATE.BROADCASTED;
46 const confirmed = state === STATE.CONFIRMED;
48 const inputsLocked = signed || broadcasted || confirmed;
50 const canSign = !initializing && constructed;
52 const construct = useCallback(txn => setUnsignedTransaction(txn), [
53 setUnsignedTransaction,
54 ]);
56 const generateAndSign = useCallback(async () => {
57 try {
58 // TODO: set varaibles
59 // txn.gas = toHex(gasLimit);
60 // txn.gasPrice = toHex(toWei(gasPrice, 'gwei'));
62 const txn = await signTransaction({
63 wallet, // wallet: _wallet,
64 walletType,
65 walletHdPath,
66 networkType,
67 txn: Just(unsignedTransaction),
68 setStx: () => {}, // TODO: remove
69 nonce,
70 chainId,
71 gasPrice,
72 gasLimit,
73 });
75 setSignedTransaction(txn);
76 setState(STATE.SIGNED);
77 } catch (error) {
78 setError(error);
79 }
80 }, [
81 chainId,
82 gasLimit,
83 gasPrice,
84 networkType,
85 nonce,
86 unsignedTransaction,
87 wallet,
88 walletHdPath,
89 walletType,
90 ]);
92 const waitForConfirmation = useCallback(
93 async txHash => {
94 try {
95 await waitForTransactionConfirm(_web3, txHash);
96 setState(STATE.CONFIRMED);
97 } catch (error) {
98 setError(error);
99 }
100 },
101 [_web3]
102 );
104 const broadcast = useCallback(async () => {
105 try {
106 const txHash = await sendSignedTransaction(
107 _web3,
108 Just(signedTransaction),
109 /* doubtNonceError */ false
110 );
112 setState(STATE.BROADCASTED);
113 waitForConfirmation(txHash);
114 } catch (error) {
115 setError(error);
116 }
117 }, [_web3, signedTransaction, waitForConfirmation]);
119 const reset = useCallback(() => {
120 setState(STATE.NONE);
121 setError(undefined);
122 setGasPrice(0);
123 setSignedTransaction(undefined);
124 }, [setState]);
126 useEffect(() => {
127 (async () => {
128 try {
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]);
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 bind: {
158 constructed,
159 canSign,
160 generateAndSign,
161 signed,
162 broadcast,
163 broadcasted,
164 confirmed,
165 reset,
166 error,
167 setGasPrice,
168 },
169 };