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
|
const HttpProvider = require('web3/lib/web3/httpprovider')
const Streams = require('mississippi')
const ObjectMultiplex = require('./obj-multiplex')
const StreamProvider = require('./stream-provider.js')
const RemoteStore = require('./remote-store.js').RemoteStore
const MetamaskConfig = require('../config.js')
module.exports = MetamaskInpageProvider
function MetamaskInpageProvider(connectionStream){
const self = this
// setup connectionStream multiplexing
var multiStream = ObjectMultiplex()
Streams.pipe(connectionStream, multiStream, connectionStream, function(err){
console.warn('MetamaskInpageProvider - lost connection to MetaMask')
if (err) throw err
})
self.multiStream = multiStream
// subscribe to metamask public config
var publicConfigStore = remoteStoreWithLocalStorageCache('MetaMask-Config')
var storeStream = publicConfigStore.createStream()
Streams.pipe(storeStream, multiStream.createStream('publicConfig'), storeStream, function(err){
console.warn('MetamaskInpageProvider - lost connection to MetaMask publicConfig')
if (err) throw err
})
self.publicConfigStore = publicConfigStore
// connect to sync provider
self.syncProvider = createSyncProvider(publicConfigStore.get('provider'))
// subscribe to publicConfig to update the syncProvider on change
publicConfigStore.subscribe(function(state){
self.syncProvider = createSyncProvider(state.provider)
})
// connect to async provider
var asyncProvider = new StreamProvider()
Streams.pipe(asyncProvider, multiStream.createStream('provider'), asyncProvider, function(err){
console.warn('MetamaskInpageProvider - lost connection to MetaMask provider')
if (err) throw err
})
asyncProvider.on('error', console.error.bind(console))
self.asyncProvider = asyncProvider
// overwrite own sendAsync method
self.sendAsync = asyncProvider.sendAsync.bind(asyncProvider)
}
MetamaskInpageProvider.prototype.send = function(payload){
const self = this
var result = null
switch (payload.method) {
case 'eth_accounts':
// read from localStorage
var selectedAddress = self.publicConfigStore.get('selectedAddress')
result = selectedAddress ? [selectedAddress] : []
break
case 'eth_coinbase':
// read from localStorage
var selectedAddress = self.publicConfigStore.get('selectedAddress')
result = selectedAddress || '0x0000000000000000000000000000000000000000'
break
// fallback to normal rpc
default:
return self.syncProvider.send(payload)
}
// return the result
return {
id: payload.id,
jsonrpc: payload.jsonrpc,
result: result,
}
}
MetamaskInpageProvider.prototype.sendAsync = function(){
throw new Error('MetamaskInpageProvider - sendAsync not overwritten')
}
MetamaskInpageProvider.prototype.isConnected = function(){
return true
}
// util
function createSyncProvider(providerConfig){
providerConfig = providerConfig || {}
var syncProviderUrl = undefined
if (providerConfig.rpcTarget) {
syncProviderUrl = providerConfig.rpcTarget
} else {
switch(providerConfig.type) {
case 'testnet':
syncProviderUrl = MetamaskConfig.network.testnet
break
case 'mainnet':
syncProviderUrl = MetamaskConfig.network.mainnet
break
default:
syncProviderUrl = MetamaskConfig.network.default
}
}
return new HttpProvider(syncProviderUrl)
}
function remoteStoreWithLocalStorageCache(storageKey){
// read local cache
var initState = JSON.parse(localStorage[storageKey] || '{}')
var store = new RemoteStore(initState)
// cache the latest state locally
store.subscribe(function(state){
localStorage[storageKey] = JSON.stringify(state)
})
return store
}
|