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
|
const pipe = require('pump')
const ProviderEngine = require('web3-provider-engine')
const FilterSubprovider = require('web3-provider-engine/subproviders/filters')
const StreamSubprovider = require('web3-provider-engine/subproviders/stream')
const LocalStorageStore = require('obs-store')
const ObjectMultiplex = require('./obj-multiplex')
const createRandomId = require('./random-id')
module.exports = MetamaskInpageProvider
function MetamaskInpageProvider (connectionStream) {
const self = this
// setup connectionStream multiplexing
var multiStream = self.multiStream = ObjectMultiplex()
pipe(
connectionStream,
multiStream,
connectionStream,
(err) => logStreamDisconnectWarning('MetaMask', err)
)
// subscribe to metamask public config (one-way)
self.publicConfigStore = new LocalStorageStore({ storageKey: 'MetaMask-Config' })
pipe(
multiStream.createStream('publicConfig'),
self.publicConfigStore,
(err) => logStreamDisconnectWarning('MetaMask PublicConfigStore', err)
)
// connect to async provider
const engine = new ProviderEngine()
const filterSubprovider = new FilterSubprovider()
engine.addProvider(filterSubprovider)
const streamSubprovider = new StreamSubprovider()
engine.addProvider(streamSubprovider)
pipe(
streamSubprovider,
multiStream.createStream('provider'),
streamSubprovider,
(err) => logStreamDisconnectWarning('MetaMask RpcProvider', err)
)
// start polling
engine.start()
self.idMap = {}
// handle sendAsync requests via asyncProvider
self.sendAsync = function (payload, cb) {
// rewrite request ids
var request = eachJsonMessage(payload, (message) => {
var newId = createRandomId()
self.idMap[newId] = message.id
message.id = newId
return message
})
// forward to asyncProvider
engine.sendAsync(request, function (err, res) {
if (err) return cb(err)
// transform messages to original ids
eachJsonMessage(res, (message) => {
var oldId = self.idMap[message.id]
delete self.idMap[message.id]
message.id = oldId
return message
})
cb(null, res)
})
}
}
MetamaskInpageProvider.prototype.send = function (payload) {
const self = this
let selectedAddress
let result = null
switch (payload.method) {
case 'eth_accounts':
// read from localStorage
selectedAddress = self.publicConfigStore.getState().selectedAddress
result = selectedAddress ? [selectedAddress] : []
break
case 'eth_coinbase':
// read from localStorage
selectedAddress = self.publicConfigStore.getState().selectedAddress
result = selectedAddress
break
case 'eth_uninstallFilter':
self.sendAsync(payload, noop)
result = true
break
case 'net_version':
const networkVersion = self.publicConfigStore.getState().networkVersion
result = networkVersion
break
// throw not-supported Error
default:
var link = 'https://github.com/MetaMask/faq/blob/master/DEVELOPERS.md#dizzy-all-async---think-of-metamask-as-a-light-client'
var message = `The MetaMask Web3 object does not support synchronous methods like ${payload.method} without a callback parameter. See ${link} for details.`
throw new Error(message)
}
// 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
}
MetamaskInpageProvider.prototype.isMetaMask = true
// util
function eachJsonMessage (payload, transformFn) {
if (Array.isArray(payload)) {
return payload.map(transformFn)
} else {
return transformFn(payload)
}
}
function logStreamDisconnectWarning (remoteLabel, err) {
let warningMsg = `MetamaskInpageProvider - lost connection to ${remoteLabel}`
if (err) warningMsg += '\n' + err.stack
console.warn(warningMsg)
}
function noop () {}
|