You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.7 KiB
134 lines
3.7 KiB
const pipe = require('pump')
|
|
const StreamProvider = require('web3-stream-provider')
|
|
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 asyncProvider = self.asyncProvider = new StreamProvider()
|
|
pipe(
|
|
asyncProvider,
|
|
multiStream.createStream('provider'),
|
|
asyncProvider,
|
|
(err) => logStreamDisconnectWarning('MetaMask RpcProvider', err)
|
|
)
|
|
|
|
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
|
|
asyncProvider.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':
|
|
let 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 () {}
|
|
|