-
Notifications
You must be signed in to change notification settings - Fork 35
/
useMetamask.js
112 lines (99 loc) · 3.19 KB
/
useMetamask.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { useContext, useEffect, useState, useRef } from "react";
import { MetaStateContext, MetaDispatchContext } from "./store";
const chains = (chainId) => {
if (!!Number(chainId) && chainId.length > 9) {
return "local";
}
switch (chainId) {
case "1" : return "mainnet";
case "3" : return "ropsten";
case "4" : return "rinkeby";
case "5" : return "goerli";
case "42": return "kovan";
default : return `unknown`;
}
};
const useMetamask = () => {
const state = useContext(MetaStateContext);
const dispatch = useContext(MetaDispatchContext);
const _isMounted = useRef(true);
const _isConnectCalled = useRef(false);
const [ provider ] = useState(window.ethereum);
useEffect(() => {
return () => {
_isMounted.current = false;
}
}, []);
const connect = async (Web3Interface, settings = {}) => {
if (!provider) throw Error("Metamask is not available.");
if (!Web3Interface)
throw Error("Web3 Provider is required. You can use either ethers.js or web3.js.");
if (!_isMounted.current) throw Error("Component is not mounted.");
if (_isConnectCalled.current) throw Error("Connect method already called.");
_isConnectCalled.current = true;
const _web3 = new Web3Interface(
...(Object.keys(settings).length
? [provider, settings]
: [provider])
);
dispatch({ type: "SET_WEB3", payload: _web3 });
await getAccounts({ requestPermission: true });
await getChain();
window.ethereum.on("accountsChanged", (accounts) => {
if (!accounts.length) dispatch({ type: "SET_CONNECTED", payload: false });
dispatch({ type: "SET_ACCOUNT", payload: accounts });
});
window.ethereum.on("chainChanged", (chainId) => {
const _chainId = parseInt(chainId, 16).toString();
const _chainInfo = { id: _chainId, name: chains(_chainId) };
dispatch({ type: "SET_CHAIN", payload: _chainInfo });
});
_isConnectCalled.current = false;
};
const getAccounts = async ({ requestPermission } = { requestPermission: false }) => {
if (!provider) {
console.warn("Metamask is not available.");
return;
}
try {
const accounts = await provider.request({
method: requestPermission ? "eth_requestAccounts" : "eth_accounts",
params: []
});
if (accounts.length) {
dispatch({ type: "SET_CONNECTED", payload: true });
dispatch({ type: "SET_ACCOUNT", payload: accounts });
}
return accounts;
} catch (error) {
throw Error(error);
}
}
const getChain = async () => {
if (!provider) {
console.warn("Metamask is not available.");
return;
}
try {
const chainId = await provider.request({
method: "net_version",
params: []
});
const _chainInfo = { id: chainId, name: chains(chainId) };
dispatch({
type: "SET_CHAIN",
payload: _chainInfo
});
return _chainInfo;
} catch (error) {
throw Error(error);
}
}
return {
connect,
getAccounts,
getChain,
metaState: { ...state, isAvailable: !!provider },
};
}
export default useMetamask;