on master help sign in
checkpoint: initial stubbed implementation of useEthereumTransaction
commita13b9ebc86becb9e8db3ab3e38378f2288b7b6dc authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateMon 15 Jul 2019, 17:45 (7 years ago) parentaf19266
1 file changed+165
src/lib/useEthereumTransaction.js+165
src/lib/useEthereumTransaction.jsnew file+165
@@ -0,0 +1,165 @@
1+import { useCallback, useEffect, useState } from 'react';
2+import { Just } from 'folktale/maybe';
3+
4+import { useNetwork } from 'store/network';
5+import { useWallet } from 'store/wallet';
6+
7+import {
8+ signTransaction,
9+ sendSignedTransaction,
10+ waitForTransactionConfirm,
11+ hexify,
12+} from './txn';
13+import * as need from './need';
14+import { toHex, toWei, fromWei } from 'web3-utils';
15+
16+const STATE = {
17+ NONE: 'NONE',
18+ GENERATED: 'GENERATED',
19+ SIGNED: 'SIGNED',
20+ BROADCASTED: 'BROADCASTED',
21+ CONFIRMED: 'CONFIRMED',
22+};
23+
24+/**
25+ * manage the state around sending and confirming an ethereum transaction
26+ * @param {Maybe<EthereumTx>} unsignedTx
27+ * @param {number} initialGasLimit
28+ */
29+export default function useEthereumTransaction(
30+ unsignedTx,
31+ initialGasLimit = 0
32+) {
33+ const { wallet, walletType, walletHdPath } = useWallet();
34+ const { web3, networkType } = useNetwork();
35+ const _web3 = need.web3(web3);
36+ const _wallet = need.wallet(wallet);
37+
38+ const [error, setError] = useState();
39+ const [state, setState] = useState(STATE.NONE);
40+ const [chainId, setChainId] = useState();
41+ const [nonce, setNonce] = useState();
42+ const [gasPrice, setGasPrice] = useState(20); // gwei
43+ const [gasLimit] = useState(initialGasLimit);
44+ const [unsignedTransaction, setUnsignedTransaction] = useState();
45+ const [signedTransaction, setSignedTransaction] = useState();
46+
47+ const initializing = nonce === undefined || chainId === undefined;
48+ const constructed = Just.hasInstance(unsignedTx);
49+ const generated = state === STATE.GENERATED;
50+ const signed = state === STATE.SIGNED;
51+ const broadcasted = state === STATE.BROADCASTED;
52+ const confirmed = state === STATE.CONFIRMED;
53+
54+ const generate = useCallback(() => {
55+ const txn = unsignedTx.value;
56+ try {
57+ txn.gas = toHex(gasLimit);
58+ txn.gasPrice = toHex(toWei(gasPrice, 'gwei'));
59+
60+ setUnsignedTransaction(txn);
61+ setState(STATE.GENERATED);
62+ } catch (error) {
63+ setError(error);
64+ }
65+ }, [gasLimit, gasPrice, unsignedTx.value]);
66+
67+ const sign = useCallback(async () => {
68+ try {
69+ // TODO: sign the transaction
70+ const txn = await signTransaction(
71+ _wallet,
72+ walletType,
73+ walletHdPath.getOrElse(''),
74+ networkType,
75+ chainId,
76+ unsignedTransaction
77+ );
78+ const stx = hexify(txn.serialize());
79+
80+ setSignedTransaction(stx);
81+ setState(STATE.SIGNED);
82+ } catch (error) {
83+ setError(error);
84+ }
85+ }, [
86+ _wallet,
87+ chainId,
88+ networkType,
89+ unsignedTransaction,
90+ walletHdPath,
91+ walletType,
92+ ]);
93+
94+ const waitForConfirmation = useCallback(
95+ async txHash => {
96+ try {
97+ await waitForTransactionConfirm(_web3, txHash);
98+ setState(STATE.CONFIRMED);
99+ } catch (error) {
100+ setError(error);
101+ }
102+ },
103+ [_web3]
104+ );
105+
106+ const broadcast = useCallback(async () => {
107+ try {
108+ const txHash = await sendSignedTransaction(_web3, signedTransaction);
109+
110+ setState(STATE.BROADCASTED);
111+ waitForConfirmation(txHash);
112+ } catch (error) {
113+ setError(error);
114+ }
115+ }, [_web3, signedTransaction, waitForConfirmation]);
116+
117+ const reset = useCallback(() => {
118+ setState(STATE.NONE);
119+ setError(undefined);
120+ setGasPrice(0);
121+ setSignedTransaction(undefined);
122+ }, [setState]);
123+
124+ useEffect(() => {
125+ (async () => {
126+ try {
127+ const [nonce, chainId, estimatedGasPrice] = await Promise.all([
128+ _web3.eth.getTransactionCount(_wallet.address),
129+ _web3.eth.net.getId(),
130+ _web3.eth.getGasPrice(),
131+ ]);
132+
133+ setNonce(nonce);
134+ setChainId(chainId);
135+ setGasPrice(fromWei(estimatedGasPrice, 'gwei'));
136+ } catch (error) {
137+ setError(error);
138+ }
139+ })();
140+ }, [_wallet.address, _web3.eth]);
141+
142+ return {
143+ initializing,
144+ constructed,
145+ generate,
146+ generated,
147+ sign,
148+ signed,
149+ broadcast,
150+ broadcasted,
151+ confirmed,
152+ reset,
153+ error,
154+ bind: {
155+ error,
156+ initializing,
157+ constructed,
158+ generated,
159+ signed,
160+ broadcasted,
161+ confirmed,
162+ setGasPrice,
163+ },
164+ };
165+}