forked from clbrge/svelte-web3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
web3-store.js
185 lines (158 loc) · 5.25 KB
/
web3-store.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import chains from './chains.js'
import { derived, writable } from 'svelte/store'
const getGlobalObject = () => {
if (typeof globalThis !== 'undefined') { return globalThis }
if (typeof self !== 'undefined') { return self }
if (typeof window !== 'undefined') { return window }
if (typeof global !== 'undefined') { return global }
throw new Error('cannot find the global object')
}
export let Web3 = {}
export const loadWeb3 = () => {
if (Web3.version) return
try {
Web3 = getGlobalObject().Web3 || {}
} catch (err) {
console.error('no globalThis.Web3 object')
}
}
const getWindowEthereum = () => {
try {
if (getGlobalObject().ethereum) return getGlobalObject().ethereum
} catch (err) {
console.error('no globalThis.ethereum object')
}
}
export const createStore = () => {
const { subscribe, update, set } = writable({
connected: false,
accounts: []
})
const init = () => {
loadWeb3()
if (!Web3.version) throw new Error('Cannot find Web3')
if (getWindowEthereum()) getWindowEthereum().autoRefreshOnNetworkChange = false
}
const setProvider = async (provider, callback) => {
init()
const instance = new Web3(provider)
const chainId = await instance.eth.getChainId()
// no account with ganache
const accounts = /127/.test(provider) ? [] : await instance.eth.getAccounts()
if (callback) {
instance._provider.removeListener('accountsChanged', () => setProvider(provider, true))
instance._provider.removeListener('chainChanged', () => setProvider(provider, true))
} else {
if (instance._provider && instance._provider.on) {
instance._provider.on('accountsChanged', () => setProvider(provider, true))
instance._provider.on('chainChanged', () => setProvider(provider, true))
}
}
update(() => ({
provider,
providerType: 'String',
connected: true,
chainId,
accounts,
instance
}))
}
const setBrowserProvider = async () => {
init()
if (!getWindowEthereum()) throw new Error('Please authorize browser extension (Metamask or similar)')
const res = await getWindowEthereum().request({ method: 'eth_requestAccounts' })
getWindowEthereum().on('accountsChanged', setBrowserProvider)
getWindowEthereum().on('chainChanged', setBrowserProvider)
const instance = new Web3(getWindowEthereum())
const chainId = await instance.eth.getChainId()
update(() => ({
provider: getWindowEthereum(),
providerType: 'Browser',
connected: true,
chainId,
accounts: res,
instance
}))
}
const close = async (provider) => {
if(provider && provider.disconnect) {
await provider.disconnect()
}
update(() => ({
connected: false,
accounts: []
}))
}
return {
setBrowserProvider,
setProvider,
close,
subscribe
}
}
const allStores = {}
const noData = { rpc: [], faucets: [], nativeCurrency: {} }
const getData = id => {
if (!id || !Web3.utils) return noData
if (Web3.utils.isHexStrict(id)) id = Web3.utils.hexToNumber(id)
for (const data of chains) {
if (data.chainId === id) return data
}
return noData
}
export const makeChainStore = name => {
const ethStore = allStores[name] = createStore()
allStores[name].connected = derived(ethStore, $ethStore => $ethStore.connected)
allStores[name].chainId = derived(ethStore, $ethStore => $ethStore.chainId)
allStores[name].providerType = derived(ethStore, $ethStore => $ethStore.providerType)
allStores[name].selectedAccount = derived(
ethStore,
$ethStore => {
if ($ethStore.connected) return $ethStore.accounts.length ? $ethStore.accounts[0] : null
return null
}
)
allStores[name].walletType = derived(ethStore, $ethStore => {
if (!$ethStore.provider) return null
if (typeof $ethStore.provider === 'string') return $ethStore.provider
if ($ethStore.provider.isMetaMask) return 'MetaMask (or compatible)'
if ($ethStore.provider.isNiftyWallet) return 'Nifty'
if ($ethStore.provider.isTrust) return 'Trust'
return 'Unknown'
})
allStores[name].web3 = derived(
ethStore,
$ethStore => {
if (!$ethStore.instance) return { utils: Web3.utils, version: Web3.version }
return $ethStore.instance
}
)
allStores[name].chainData = derived(
ethStore,
$ethStore => $ethStore.chainId ? getData($ethStore.chainId) : {}
)
return allStores[name]
}
export const getChainStore = name => {
if (!allStores[name]) throw new Error(`chain store ${name} does not exist`)
return allStores[name]
}
export const makeContractStore = (abi, address, defaults = {}) => derived(
[web3, connected],
([$web3, $connected]) => {
if ($connected && $web3.eth) {
return new $web3.eth.Contract(abi, address, defaults)
}
return null
}
)
loadWeb3()
export const defaultChainStore = makeChainStore('default')
export const connected = allStores.default.connected
export const chainId = allStores.default.chainId
export const providerType = allStores.default.providerType
export const selectedAccount = allStores.default.selectedAccount
export const walletType = allStores.default.walletType
export const web3 = allStores.default.web3
export const chainData = allStores.default.chainData
export const ethStore = defaultChainStore