-
Notifications
You must be signed in to change notification settings - Fork 35
/
useMetamask.js
123 lines (108 loc) · 3.41 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
113
114
115
116
117
118
119
120
121
122
123
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';
case '11155111': return 'sepiola';
default: return `unknown`;
}
};
const useMetamask = () => {
const state = useContext(MetaStateContext);
if (!('window' in globalThis)) {
return {
metaState: { ...state, isAvailable: false },
};
}
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', (chainIdHex) => {
const chainId = parseInt(chainIdHex, 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 chainIdHex = await provider.request({
method: 'eth_chainId',
params: [],
});
const chainId = parseInt(chainIdHex, 16).toString();
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;