aboutsummaryrefslogblamecommitdiffstats
path: root/app/scripts/lib/inpage-provider.js
blob: e387be895c6b3c278baf7a6181c9afbd554882a7 (plain) (tree)
1
2
3
4
5
6
7
8
9


                                                          
                                                      




                                                            
                                                    

                   
                                        
                                     
                                                                                







                                                                             
                                                                                                   







                                                                                     
                                                




                                                          
                                                                                                   








                                                                                 
                                                            
                   
                     





                               
                                                                     




                                                       
                                                                     
















                                                                              
                                                          


                                                                       
                                                            




             
                                              
                                       
                     



                                              
                                  









                                                        








                                                                                                                                                                                   

 
                                                        



                                                              
                                    



                                                    
 
const HttpProvider = require('web3/lib/web3/httpprovider')
const Streams = require('mississippi')
const ObjectMultiplex = require('./obj-multiplex')
const StreamProvider = require('web3-stream-provider')
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
  let selectedAddress

  var result = null
  switch (payload.method) {

    case 'eth_accounts':
      // read from localStorage
      selectedAddress = self.publicConfigStore.get('selectedAddress')
      result = selectedAddress ? [selectedAddress] : []
      break

    case 'eth_coinbase':
      // read from localStorage
      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 || {}
  let syncProviderUrl

  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
    }
  }

  const provider = new HttpProvider(syncProviderUrl)
  // Stubbing out the send method to throw on sync methods:
  provider.send = function() {
    var message = 'The MetaMask Web3 object does not support synchronous methods. See https://github.com/MetaMask/faq#all-async---think-of-metamask-as-a-light-client for details.'
    throw new Error(message)
  }

  return provider
}

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
}