migrate to ProviderEngine zero-client
This commit is contained in:
parent
cc935a1eba
commit
72a747165d
|
@ -1,7 +1,10 @@
|
||||||
|
const ZeroClientProvider = require('web3-provider-skeleton')
|
||||||
|
// const PortStream = require('./lib/port-stream.js')
|
||||||
const identitiesUrl = 'https://alpha.metamask.io/identities/'
|
const identitiesUrl = 'https://alpha.metamask.io/identities/'
|
||||||
const messagingChannelName = 'metamask'
|
|
||||||
|
|
||||||
var unsignedTxs = {}
|
// var unsignedTxs = {}
|
||||||
|
|
||||||
|
var zeroClient = ZeroClientProvider()
|
||||||
|
|
||||||
// setup badge click handler
|
// setup badge click handler
|
||||||
chrome.browserAction.onClicked.addListener(function(activeTab) {
|
chrome.browserAction.onClicked.addListener(function(activeTab) {
|
||||||
|
@ -10,118 +13,131 @@ chrome.browserAction.onClicked.addListener(function(activeTab) {
|
||||||
|
|
||||||
// setup messaging
|
// setup messaging
|
||||||
chrome.runtime.onConnect.addListener(connectRemote)
|
chrome.runtime.onConnect.addListener(connectRemote)
|
||||||
chrome.runtime.onConnectExternal.addListener(connectRemote)
|
// chrome.runtime.onConnectExternal.addListener(connectRemote)
|
||||||
function connectRemote(remote){
|
function connectRemote(remotePort){
|
||||||
remote.onMessage.addListener(handleMessage)
|
remotePort.onMessage.addListener(onRpcRequest.bind(null, remotePort))
|
||||||
exportUnsignedTxs(remote)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// load from storage
|
function onRpcRequest(remotePort, payload){
|
||||||
chrome.storage.sync.get(function(data){
|
zeroClient.sendAsync(payload, function onPayloadHandled(err, response){
|
||||||
for (var key in data) {
|
if (err) throw err
|
||||||
var serialized = data[key]
|
// console.log('MetaMaskPlugin - RPC complete:', payload, '->', response)
|
||||||
var tx = deserializeTx(serialized)
|
// if (typeof response !== 'object') {
|
||||||
var hash = simpleHash(serialized)
|
// if (!response) {
|
||||||
unsignedTxs[hash] = tx
|
// console.warn('-------------------------------')
|
||||||
}
|
// console.warn(payload, '->', response)
|
||||||
updateBadge()
|
// console.warn('-------------------------------')
|
||||||
})
|
// }
|
||||||
|
remotePort.postMessage(response)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// listen to storage changes
|
// // load from storage
|
||||||
chrome.storage.onChanged.addListener(function(changes, namespace) {
|
// chrome.storage.sync.get(function(data){
|
||||||
for (key in changes) {
|
// for (var key in data) {
|
||||||
var storageChange = changes[key]
|
// var serialized = data[key]
|
||||||
if (storageChange.oldValue && !storageChange.newValue) {
|
// var tx = deserializeTx(serialized)
|
||||||
// was removed
|
// var hash = simpleHash(serialized)
|
||||||
removeTransaction(storageChange.oldValue)
|
// unsignedTxs[hash] = tx
|
||||||
} else if (!storageChange.oldValue && storageChange.newValue) {
|
// }
|
||||||
// was added
|
// updateBadge()
|
||||||
addTransaction(deserializeTx(storageChange.newValue))
|
// })
|
||||||
}
|
|
||||||
}
|
// // listen to storage changes
|
||||||
})
|
// chrome.storage.onChanged.addListener(function(changes, namespace) {
|
||||||
|
// for (key in changes) {
|
||||||
|
// var storageChange = changes[key]
|
||||||
|
// if (storageChange.oldValue && !storageChange.newValue) {
|
||||||
|
// // was removed
|
||||||
|
// removeTransaction(storageChange.oldValue)
|
||||||
|
// } else if (!storageChange.oldValue && storageChange.newValue) {
|
||||||
|
// // was added
|
||||||
|
// addTransaction(deserializeTx(storageChange.newValue))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
// setup badge text
|
// setup badge text
|
||||||
updateBadge()
|
// updateBadge()
|
||||||
|
|
||||||
function handleMessage(msg){
|
// function updateBadge(){
|
||||||
console.log('got message!', msg.type)
|
// var label = ''
|
||||||
switch(msg.type){
|
// var count = Object.keys(unsignedTxs).length
|
||||||
|
// if (count) {
|
||||||
|
// label = String(count)
|
||||||
|
// }
|
||||||
|
// chrome.browserAction.setBadgeText({text: label})
|
||||||
|
// chrome.browserAction.setBadgeBackgroundColor({color: '#506F8B'})
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function handleMessage(msg){
|
||||||
|
// console.log('got message!', msg.type)
|
||||||
|
// switch(msg.type){
|
||||||
|
|
||||||
case 'addUnsignedTx':
|
// case 'addUnsignedTx':
|
||||||
addTransaction(msg.payload)
|
// addTransaction(msg.payload)
|
||||||
return
|
// return
|
||||||
|
|
||||||
case 'removeUnsignedTx':
|
// case 'removeUnsignedTx':
|
||||||
removeTransaction(msg.payload)
|
// removeTransaction(msg.payload)
|
||||||
return
|
// return
|
||||||
|
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
function addTransaction(tx){
|
// function addTransaction(tx){
|
||||||
var serialized = serializeTx(tx)
|
// var serialized = serializeTx(tx)
|
||||||
var hash = simpleHash(serialized)
|
// var hash = simpleHash(serialized)
|
||||||
unsignedTxs[hash] = tx
|
// unsignedTxs[hash] = tx
|
||||||
var data = {}
|
// var data = {}
|
||||||
data[hash] = serialized
|
// data[hash] = serialized
|
||||||
chrome.storage.sync.set(data)
|
// chrome.storage.sync.set(data)
|
||||||
// trigger ui changes
|
// // trigger ui changes
|
||||||
updateBadge()
|
// updateBadge()
|
||||||
}
|
// }
|
||||||
|
|
||||||
function removeTransaction(serialized){
|
// function removeTransaction(serialized){
|
||||||
var hash = simpleHash(serialized)
|
// var hash = simpleHash(serialized)
|
||||||
delete unsignedTxs[hash]
|
// delete unsignedTxs[hash]
|
||||||
var data = {}
|
// var data = {}
|
||||||
data[hash] = undefined
|
// data[hash] = undefined
|
||||||
chrome.storage.sync.set(data)
|
// chrome.storage.sync.set(data)
|
||||||
// trigger ui changes
|
// // trigger ui changes
|
||||||
updateBadge()
|
// updateBadge()
|
||||||
}
|
// }
|
||||||
|
|
||||||
function exportUnsignedTxs(remote){
|
// function exportUnsignedTxs(remote){
|
||||||
console.log('exporting txs!', unsignedTxs)
|
// console.log('exporting txs!', unsignedTxs)
|
||||||
var data = {
|
// var data = {
|
||||||
type: 'importUnsignedTxs',
|
// type: 'importUnsignedTxs',
|
||||||
payload: getValues(unsignedTxs),
|
// payload: getValues(unsignedTxs),
|
||||||
}
|
// }
|
||||||
remote.postMessage(data)
|
// remote.postMessage(data)
|
||||||
}
|
// }
|
||||||
|
|
||||||
function updateBadge(){
|
// function simpleHash(input) {
|
||||||
var label = ''
|
// var hash = 0, i, chr, len
|
||||||
var count = Object.keys(unsignedTxs).length
|
// if (input.length == 0) return hash
|
||||||
if (count) {
|
// for (i = 0, len = input.length; i < len; i++) {
|
||||||
label = String(count)
|
// chr = input.charCodeAt(i)
|
||||||
}
|
// hash = ((hash << 5) - hash) + chr
|
||||||
chrome.browserAction.setBadgeText({text: label})
|
// hash |= 0 // Convert to 32bit integer
|
||||||
chrome.browserAction.setBadgeBackgroundColor({color: '#506F8B'})
|
// }
|
||||||
}
|
// return hash
|
||||||
|
// }
|
||||||
|
|
||||||
function simpleHash(input) {
|
// function serializeTx(tx){
|
||||||
var hash = 0, i, chr, len
|
// return JSON.stringify(tx)
|
||||||
if (input.length == 0) return hash
|
// }
|
||||||
for (i = 0, len = input.length; i < len; i++) {
|
|
||||||
chr = input.charCodeAt(i)
|
|
||||||
hash = ((hash << 5) - hash) + chr
|
|
||||||
hash |= 0 // Convert to 32bit integer
|
|
||||||
}
|
|
||||||
return hash
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeTx(tx){
|
// function deserializeTx(tx){
|
||||||
return JSON.stringify(tx)
|
// return JSON.parse(tx)
|
||||||
}
|
// }
|
||||||
|
|
||||||
function deserializeTx(tx){
|
// function getValues(obj){
|
||||||
return JSON.parse(tx)
|
// var output = []
|
||||||
}
|
// for (var key in obj) {
|
||||||
|
// output.push(obj[key])
|
||||||
function getValues(obj){
|
// }
|
||||||
var output = []
|
// return output
|
||||||
for (var key in obj) {
|
// }
|
||||||
output.push(obj[key])
|
|
||||||
}
|
|
||||||
return output
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
const allowedMessageTarget = 'metamask'
|
const LocalMessageDuplexStream = require('./lib/local-message-stream.js')
|
||||||
const allowedMessageType = 'addUnsignedTx'
|
const PortStream = require('./lib/port-stream.js')
|
||||||
|
|
||||||
|
console.log('content script!')
|
||||||
|
|
||||||
// inject in-page script
|
// inject in-page script
|
||||||
var scriptTag = document.createElement('script')
|
var scriptTag = document.createElement('script')
|
||||||
|
@ -9,17 +10,14 @@ scriptTag.onload = function() { this.parentNode.removeChild(this) }
|
||||||
var container = document.head || document.documentElement
|
var container = document.head || document.documentElement
|
||||||
container.appendChild(scriptTag)
|
container.appendChild(scriptTag)
|
||||||
|
|
||||||
// setup connection with background
|
// setup communication to page and plugin
|
||||||
var metamaskPlugin = chrome.runtime.connect({name: 'metamask'})
|
var pageStream = new LocalMessageDuplexStream({
|
||||||
|
name: 'contentscript',
|
||||||
|
target: 'inpage',
|
||||||
|
})
|
||||||
|
var pluginPort = chrome.runtime.connect({name: 'metamask'})
|
||||||
|
var pluginStream = new PortStream(pluginPort)
|
||||||
|
|
||||||
// forward messages from inpage to background
|
// forward communication across
|
||||||
window.addEventListener('message', receiveMessage, false);
|
pageStream.pipe(pluginStream)
|
||||||
function receiveMessage(event){
|
pluginStream.pipe(pageStream)
|
||||||
var msg = event.data
|
|
||||||
// validate message type
|
|
||||||
if (typeof msg !== 'object') return
|
|
||||||
if (msg.to !== allowedMessageTarget) return
|
|
||||||
if (msg.type !== allowedMessageType) return
|
|
||||||
// forward message
|
|
||||||
metamaskPlugin.postMessage(msg)
|
|
||||||
}
|
|
|
@ -1,59 +1,18 @@
|
||||||
const web3 = require('web3')
|
const Web3 = require('web3')
|
||||||
const BlockAppsWeb3Provider = require('blockapps-web3')
|
const StreamProvider = require('./lib/stream-provider.js')
|
||||||
const Transaction = require('ethereumjs-tx')
|
const LocalMessageDuplexStream = require('./lib/local-message-stream.js')
|
||||||
require('object.entries').shim()
|
|
||||||
|
|
||||||
// const rpcUrl = 'https://rpc.metamask.io'
|
|
||||||
|
|
||||||
// var provider = new MetamaskProvider(forwardPayload, rpcUrl)
|
|
||||||
var provider = new BlockAppsWeb3Provider({
|
|
||||||
host: 'http://hacknet.blockapps.net',
|
|
||||||
// host: 'http://api.blockapps.net',
|
|
||||||
transaction_signer: {
|
|
||||||
// Can be any object that implements the following methods:
|
|
||||||
hasAddress: function(address, callback) {
|
|
||||||
console.log('metamask provider - asked for address ownership', address)
|
|
||||||
callback(null, true)
|
|
||||||
},
|
|
||||||
signTransaction: function(txParams, callback) {
|
|
||||||
txParams.gasLimit = txParams.gas
|
|
||||||
var tx = new Transaction(txParams)
|
|
||||||
tx.sign(new Buffer('0d0ba14043088cd629a978b49c8691deca5926f0271432bc0064e4745bac0a9f', 'hex'))
|
|
||||||
callback(null, '0x'+tx.serialize().toString('hex'))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
coinbase: '0x00000000000',
|
|
||||||
accounts: ['0x985095ef977ba75fb2bb79cd5c4b84c81392dff6'],
|
|
||||||
// host: function(){ debugger },
|
|
||||||
});
|
|
||||||
|
|
||||||
const documentOrigin = window.location.origin
|
|
||||||
const allowedMessageTarget = 'metamask'
|
|
||||||
const allowedMessageType = 'addUnsignedTx'
|
|
||||||
|
|
||||||
web3.setProvider(provider)
|
|
||||||
// disable setProvider
|
|
||||||
web3.setProvider = function(){}
|
|
||||||
|
|
||||||
// injecting web3
|
|
||||||
console.log('Metamask injected web3')
|
|
||||||
|
|
||||||
|
|
||||||
// log all the stuff!
|
// setup plugin communication
|
||||||
// provider.verbosity = 1
|
var pluginStream = new LocalMessageDuplexStream({
|
||||||
|
name: 'inpage',
|
||||||
// web3.currentProvider.vm.onStep = function(data, cb){
|
target: 'contentscript',
|
||||||
// console.log(data)
|
})
|
||||||
// cb()
|
var remoteProvider = new StreamProvider()
|
||||||
// }
|
remoteProvider.pipe(pluginStream).pipe(remoteProvider)
|
||||||
|
|
||||||
|
// create web3
|
||||||
|
var web3 = new Web3(remoteProvider)
|
||||||
window.web3 = web3
|
window.web3 = web3
|
||||||
|
web3.setProvider = function(){}
|
||||||
|
console.log('Metamask injected web3')
|
||||||
function forwardPayload(payload){
|
|
||||||
window.postMessage({
|
|
||||||
to: allowedMessageTarget,
|
|
||||||
type: allowedMessageType,
|
|
||||||
payload: payload,
|
|
||||||
}, documentOrigin)
|
|
||||||
}
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
const Duplex = require('readable-stream').Duplex
|
||||||
|
const inherits = require('util').inherits
|
||||||
|
|
||||||
|
module.exports = LocalMessageDuplexStream
|
||||||
|
|
||||||
|
|
||||||
|
inherits(LocalMessageDuplexStream, Duplex)
|
||||||
|
|
||||||
|
function LocalMessageDuplexStream(opts){
|
||||||
|
Duplex.call(this, {
|
||||||
|
objectMode: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// this._origin = opts.origin
|
||||||
|
this._name = opts.name
|
||||||
|
this._target = opts.target
|
||||||
|
|
||||||
|
// console.log('LocalMessageDuplexStream ('+this._name+') - initialized...')
|
||||||
|
window.addEventListener('message', this._onMessage.bind(this), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// private
|
||||||
|
|
||||||
|
LocalMessageDuplexStream.prototype._onMessage = function(event){
|
||||||
|
var msg = event.data
|
||||||
|
// console.log('LocalMessageDuplexStream ('+this._name+') - heard message...')
|
||||||
|
// validate message
|
||||||
|
if (event.origin !== location.origin) return //console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (event.origin !== location.origin) ')
|
||||||
|
if (typeof msg !== 'object') return //console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (typeof msg !== "object") ')
|
||||||
|
if (msg.target !== this._name) return //console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (msg.target !== this._name) ', msg.target, this._name)
|
||||||
|
if (!msg.data) return //console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (!msg.data) ')
|
||||||
|
// console.log('LocalMessageDuplexStream ('+this._name+') - accepted', msg.data)
|
||||||
|
// forward message
|
||||||
|
this.push(msg.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stream plumbing
|
||||||
|
|
||||||
|
LocalMessageDuplexStream.prototype._read = noop
|
||||||
|
|
||||||
|
LocalMessageDuplexStream.prototype._write = function(data, encoding, cb){
|
||||||
|
// console.log('LocalMessageDuplexStream ('+this._name+') - sending message...')
|
||||||
|
var message = {
|
||||||
|
target: this._target,
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
window.postMessage(message, location.origin)
|
||||||
|
cb()
|
||||||
|
}
|
||||||
|
|
||||||
|
// util
|
||||||
|
|
||||||
|
function noop(){}
|
|
@ -0,0 +1,36 @@
|
||||||
|
const Duplex = require('readable-stream').Duplex
|
||||||
|
const inherits = require('util').inherits
|
||||||
|
|
||||||
|
module.exports = PortDuplexStream
|
||||||
|
|
||||||
|
|
||||||
|
inherits(PortDuplexStream, Duplex)
|
||||||
|
|
||||||
|
function PortDuplexStream(port){
|
||||||
|
Duplex.call(this, {
|
||||||
|
objectMode: true,
|
||||||
|
})
|
||||||
|
this._port = port
|
||||||
|
port.onMessage.addListener(this._onMessage.bind(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
// private
|
||||||
|
|
||||||
|
PortDuplexStream.prototype._onMessage = function(msg){
|
||||||
|
// console.log('PortDuplexStream - saw message', msg)
|
||||||
|
this.push(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stream plumbing
|
||||||
|
|
||||||
|
PortDuplexStream.prototype._read = noop
|
||||||
|
|
||||||
|
PortDuplexStream.prototype._write = function(msg, encoding, cb){
|
||||||
|
// console.log('PortDuplexStream - sent message', msg)
|
||||||
|
this._port.postMessage(msg)
|
||||||
|
cb()
|
||||||
|
}
|
||||||
|
|
||||||
|
// util
|
||||||
|
|
||||||
|
function noop(){}
|
|
@ -0,0 +1,50 @@
|
||||||
|
const Duplex = require('readable-stream').Duplex
|
||||||
|
const inherits = require('util').inherits
|
||||||
|
|
||||||
|
module.exports = StreamProvider
|
||||||
|
|
||||||
|
|
||||||
|
inherits(StreamProvider, Duplex)
|
||||||
|
|
||||||
|
function StreamProvider(){
|
||||||
|
Duplex.call(this, {
|
||||||
|
objectMode: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
this._handlers = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// public
|
||||||
|
|
||||||
|
StreamProvider.prototype.send = function(payload){
|
||||||
|
throw new Error('StreamProvider - does not support synchronous RPC calls')
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamProvider.prototype.sendAsync = function(payload, callback){
|
||||||
|
// console.log('StreamProvider - sending payload', payload)
|
||||||
|
this._handlers[payload.id] = callback
|
||||||
|
this.push(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
// private
|
||||||
|
|
||||||
|
StreamProvider.prototype._onResponse = function(payload){
|
||||||
|
// console.log('StreamProvider - got response', payload)
|
||||||
|
var callback = this._handlers[payload.id]
|
||||||
|
if (!callback) throw new Error('StreamProvider - Unknown response id')
|
||||||
|
delete this._handlers[payload.id]
|
||||||
|
callback(null, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stream plumbing
|
||||||
|
|
||||||
|
StreamProvider.prototype._read = noop
|
||||||
|
|
||||||
|
StreamProvider.prototype._write = function(msg, encoding, cb){
|
||||||
|
this._onResponse(msg)
|
||||||
|
cb()
|
||||||
|
}
|
||||||
|
|
||||||
|
// util
|
||||||
|
|
||||||
|
function noop(){}
|
|
@ -8,7 +8,9 @@
|
||||||
"ethereumjs-tx": "^0.6.7",
|
"ethereumjs-tx": "^0.6.7",
|
||||||
"ethereumjs-util": "^1.3.5",
|
"ethereumjs-util": "^1.3.5",
|
||||||
"object.entries": "^1.0.2",
|
"object.entries": "^1.0.2",
|
||||||
"web3": "^0.9.2"
|
"readable-stream": "^2.0.5",
|
||||||
|
"web3": "^0.15.1",
|
||||||
|
"web3-provider-engine": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"grunt": "~0.4.1",
|
"grunt": "~0.4.1",
|
||||||
|
|
Loading…
Reference in New Issue