diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8fbc310ac..2b70dacf7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,16 @@
## Current Master
+## 2.0.0 2016-05-23
+
+- UI Overhaul per Vlad Todirut's designs.
+- Replaced identicons with jazzicons.
+- Fixed glitchy transitions.
+- Added support for capitalization-based address checksums.
+- Send value is no longer limited by javascript number precision, and is always in ETH.
+- Added ability to generate new accounts.
+- Added ability to locally nickname accounts.
+
## 1.8.4 2016-05-13
- Point rpc servers to https endpoints.
diff --git a/app/fonts/Transat Black/transat_black-webfont.eot b/app/fonts/Transat Black/transat_black-webfont.eot
new file mode 100755
index 000000000..268ba943d
Binary files /dev/null and b/app/fonts/Transat Black/transat_black-webfont.eot differ
diff --git a/app/fonts/Transat Black/transat_black-webfont.svg b/app/fonts/Transat Black/transat_black-webfont.svg
new file mode 100755
index 000000000..b8762f7d6
--- /dev/null
+++ b/app/fonts/Transat Black/transat_black-webfont.svg
@@ -0,0 +1,2592 @@
+
+
+
\ No newline at end of file
diff --git a/app/fonts/Transat Black/transat_black-webfont.ttf b/app/fonts/Transat Black/transat_black-webfont.ttf
new file mode 100755
index 000000000..d501f77da
Binary files /dev/null and b/app/fonts/Transat Black/transat_black-webfont.ttf differ
diff --git a/app/fonts/Transat Black/transat_black-webfont.woff b/app/fonts/Transat Black/transat_black-webfont.woff
new file mode 100755
index 000000000..ea5d95b40
Binary files /dev/null and b/app/fonts/Transat Black/transat_black-webfont.woff differ
diff --git a/app/fonts/Transat Black/transat_black-webfont.woff2 b/app/fonts/Transat Black/transat_black-webfont.woff2
new file mode 100755
index 000000000..64113a718
Binary files /dev/null and b/app/fonts/Transat Black/transat_black-webfont.woff2 differ
diff --git a/app/fonts/Transat Light/transat_light-webfont.eot b/app/fonts/Transat Light/transat_light-webfont.eot
new file mode 100755
index 000000000..1660cdad9
Binary files /dev/null and b/app/fonts/Transat Light/transat_light-webfont.eot differ
diff --git a/app/fonts/Transat Light/transat_light-webfont.svg b/app/fonts/Transat Light/transat_light-webfont.svg
new file mode 100755
index 000000000..82327f942
--- /dev/null
+++ b/app/fonts/Transat Light/transat_light-webfont.svg
@@ -0,0 +1,2399 @@
+
+
+
\ No newline at end of file
diff --git a/app/fonts/Transat Light/transat_light-webfont.ttf b/app/fonts/Transat Light/transat_light-webfont.ttf
new file mode 100755
index 000000000..dda8bb83f
Binary files /dev/null and b/app/fonts/Transat Light/transat_light-webfont.ttf differ
diff --git a/app/fonts/Transat Light/transat_light-webfont.woff b/app/fonts/Transat Light/transat_light-webfont.woff
new file mode 100755
index 000000000..2e898fefc
Binary files /dev/null and b/app/fonts/Transat Light/transat_light-webfont.woff differ
diff --git a/app/fonts/Transat Light/transat_light-webfont.woff2 b/app/fonts/Transat Light/transat_light-webfont.woff2
new file mode 100755
index 000000000..b2dfed9ad
Binary files /dev/null and b/app/fonts/Transat Light/transat_light-webfont.woff2 differ
diff --git a/app/fonts/Transat Medium/transat_medium-webfont.eot b/app/fonts/Transat Medium/transat_medium-webfont.eot
new file mode 100755
index 000000000..03a1b8339
Binary files /dev/null and b/app/fonts/Transat Medium/transat_medium-webfont.eot differ
diff --git a/app/fonts/Transat Medium/transat_medium-webfont.svg b/app/fonts/Transat Medium/transat_medium-webfont.svg
new file mode 100755
index 000000000..073fe602f
--- /dev/null
+++ b/app/fonts/Transat Medium/transat_medium-webfont.svg
@@ -0,0 +1,2813 @@
+
+
+
\ No newline at end of file
diff --git a/app/fonts/Transat Medium/transat_medium-webfont.ttf b/app/fonts/Transat Medium/transat_medium-webfont.ttf
new file mode 100755
index 000000000..361df5c16
Binary files /dev/null and b/app/fonts/Transat Medium/transat_medium-webfont.ttf differ
diff --git a/app/fonts/Transat Medium/transat_medium-webfont.woff b/app/fonts/Transat Medium/transat_medium-webfont.woff
new file mode 100755
index 000000000..fd3616d48
Binary files /dev/null and b/app/fonts/Transat Medium/transat_medium-webfont.woff differ
diff --git a/app/fonts/Transat Medium/transat_medium-webfont.woff2 b/app/fonts/Transat Medium/transat_medium-webfont.woff2
new file mode 100755
index 000000000..d6c99d7fb
Binary files /dev/null and b/app/fonts/Transat Medium/transat_medium-webfont.woff2 differ
diff --git a/app/fonts/Transat Standard/transat_standard-webfont.eot b/app/fonts/Transat Standard/transat_standard-webfont.eot
new file mode 100755
index 000000000..8bbc5a3e1
Binary files /dev/null and b/app/fonts/Transat Standard/transat_standard-webfont.eot differ
diff --git a/app/fonts/Transat Standard/transat_standard-webfont.svg b/app/fonts/Transat Standard/transat_standard-webfont.svg
new file mode 100755
index 000000000..72d184d1a
--- /dev/null
+++ b/app/fonts/Transat Standard/transat_standard-webfont.svg
@@ -0,0 +1,2827 @@
+
+
+
\ No newline at end of file
diff --git a/app/fonts/Transat Standard/transat_standard-webfont.ttf b/app/fonts/Transat Standard/transat_standard-webfont.ttf
new file mode 100755
index 000000000..ccea33a5f
Binary files /dev/null and b/app/fonts/Transat Standard/transat_standard-webfont.ttf differ
diff --git a/app/fonts/Transat Standard/transat_standard-webfont.woff b/app/fonts/Transat Standard/transat_standard-webfont.woff
new file mode 100755
index 000000000..8e3abeaa5
Binary files /dev/null and b/app/fonts/Transat Standard/transat_standard-webfont.woff differ
diff --git a/app/fonts/Transat Standard/transat_standard-webfont.woff2 b/app/fonts/Transat Standard/transat_standard-webfont.woff2
new file mode 100755
index 000000000..3d62b0ffd
Binary files /dev/null and b/app/fonts/Transat Standard/transat_standard-webfont.woff2 differ
diff --git a/app/manifest.json b/app/manifest.json
index d9697627f..56f0ce62e 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"short_name": "Metamask",
- "version": "1.8.4",
+ "version": "2.0.0",
"manifest_version": 2,
"description": "__MSG_appDescription__",
"icons": {
diff --git a/app/scripts/background.js b/app/scripts/background.js
index a52eab2d3..8c6adff04 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -1,11 +1,12 @@
const Dnode = require('dnode')
-const ObjectMultiplex = require('./lib/obj-multiplex')
const eos = require('end-of-stream')
const combineStreams = require('pumpify')
const extend = require('xtend')
const EthStore = require('eth-store')
-const PortStream = require('./lib/port-stream.js')
const MetaMaskProvider = require('web3-provider-engine/zero.js')
+const handleRequestsFromStream = require('web3-stream-provider/handler')
+const ObjectMultiplex = require('./lib/obj-multiplex')
+const PortStream = require('./lib/port-stream.js')
const IdentityStore = require('./lib/idStore')
const createTxNotification = require('./lib/notifications.js').createTxNotification
const createMsgNotification = require('./lib/notifications.js').createMsgNotification
@@ -132,25 +133,6 @@ function storeSetFromObj(store, obj){
}
-
-// handle rpc requests
-function onRpcRequest(remoteStream, payload){
- // console.log('MetaMaskPlugin - incoming payload:', payload)
- provider.sendAsync(payload, function onPayloadHandled(err, response){
- // provider engine errors are included in response objects
- if (!payload.isMetamaskInternal) {
- console.log('MetaMaskPlugin - RPC complete:', payload, '->', response)
- if (response.error) console.error('Error in RPC response:\n'+response.error.message)
- }
- try {
- remoteStream.write(response)
- } catch (err) {
- console.error(err)
- }
- })
-}
-
-
//
// remote features
//
@@ -161,7 +143,15 @@ function setupPublicConfig(stream){
}
function setupProviderConnection(stream){
- stream.on('data', onRpcRequest.bind(null, stream))
+ handleRequestsFromStream(stream, provider, logger)
+
+ function logger(err, request, response){
+ if (err) return console.error(err.stack)
+ if (!request.isMetamaskInternal) {
+ console.log('MetaMaskPlugin - RPC complete:', request, '->', response)
+ if (response.error) console.error('Error in RPC response:\n'+response.error.message)
+ }
+ }
}
function setupControllerConnection(stream){
@@ -182,6 +172,8 @@ function setupControllerConnection(stream){
setLocked: idStore.setLocked.bind(idStore),
clearSeedWordCache: idStore.clearSeedWordCache.bind(idStore),
exportAccount: idStore.exportAccount.bind(idStore),
+ revealAccount: idStore.revealAccount.bind(idStore),
+ saveAccountLabel: idStore.saveAccountLabel.bind(idStore),
})
stream.pipe(dnode).pipe(stream)
dnode.on('remote', function(remote){
diff --git a/app/scripts/config.js b/app/scripts/config.js
new file mode 100644
index 000000000..f26e6778d
--- /dev/null
+++ b/app/scripts/config.js
@@ -0,0 +1,12 @@
+const MAINET_RPC_URL = 'https://mainnet.infura.io/'
+const TESTNET_RPC_URL = 'https://morden.infura.io/'
+const DEFAULT_RPC_URL = TESTNET_RPC_URL
+
+module.exports = {
+ network: {
+ default: DEFAULT_RPC_URL,
+ mainnet: MAINET_RPC_URL,
+ testnet: TESTNET_RPC_URL,
+ },
+}
+
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index 1b7b98ec9..43ae5bc98 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -25,14 +25,14 @@ pluginStream.on('error', console.error.bind(console))
// forward communication plugin->inpage
pageStream.pipe(pluginStream).pipe(pageStream)
-// connect contentscript->inpage control stream
+// connect contentscript->inpage reload stream
var mx = ObjectMultiplex()
mx.on('error', console.error.bind(console))
mx.pipe(pageStream)
-var controlStream = mx.createStream('control')
-controlStream.on('error', console.error.bind(console))
+var reloadStream = mx.createStream('reload')
+reloadStream.on('error', console.error.bind(console))
// if we lose connection with the plugin, trigger tab refresh
pluginStream.on('close', function(){
- controlStream.write({ method: 'reset' })
+ reloadStream.write({ method: 'reset' })
})
\ No newline at end of file
diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js
index 33e2c9358..b8532747e 100644
--- a/app/scripts/inpage.js
+++ b/app/scripts/inpage.js
@@ -1,18 +1,12 @@
cleanContextForImports()
-const createPayload = require('web3-provider-engine/util/create-payload')
-const StreamProvider = require('./lib/stream-provider.js')
-const LocalMessageDuplexStream = require('./lib/local-message-stream.js')
-const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
-const RemoteStore = require('./lib/remote-store.js').RemoteStore
const Web3 = require('web3')
-const once = require('once')
+const LocalMessageDuplexStream = require('./lib/local-message-stream.js')
+const setupDappAutoReload = require('./lib/auto-reload.js')
+const MetamaskInpageProvider = require('./lib/inpage-provider.js')
restoreContextAfterImports()
-// rename on window
+// remove from window
delete window.Web3
-window.MetamaskWeb3 = Web3
-
-const DEFAULT_RPC_URL = 'https://rpc.metamask.io/'
//
@@ -20,148 +14,40 @@ const DEFAULT_RPC_URL = 'https://rpc.metamask.io/'
//
// setup background connection
-var pluginStream = new LocalMessageDuplexStream({
+var metamaskStream = new LocalMessageDuplexStream({
name: 'inpage',
target: 'contentscript',
})
-var mx = setupMultiplex(pluginStream)
-// connect to provider
-var remoteProvider = new StreamProvider()
-remoteProvider.pipe(mx.createStream('provider')).pipe(remoteProvider)
-remoteProvider.on('error', console.error.bind(console))
-
-// subscribe to metamask public config
-var initState = JSON.parse(localStorage['MetaMask-Config'] || '{}')
-var publicConfigStore = new RemoteStore(initState)
-var storeStream = publicConfigStore.createStream()
-storeStream.pipe(mx.createStream('publicConfig')).pipe(storeStream)
-publicConfigStore.subscribe(function(state){
- localStorage['MetaMask-Config'] = JSON.stringify(state)
-})
+// compose the inpage provider
+var inpageProvider = new MetamaskInpageProvider(metamaskStream)
//
// setup web3
//
-var web3 = new Web3(remoteProvider)
+var web3 = new Web3(inpageProvider)
web3.setProvider = function(){
console.log('MetaMask - overrode web3.setProvider')
}
console.log('MetaMask - injected web3')
//
-// automatic dapp reset
+// export global web3 with auto dapp reload
//
-// export web3 as a global, checking for usage
-var pageIsUsingWeb3 = false
-var resetWasRequested = false
-window.web3 = ensnare(web3, once(function(){
- // if web3 usage happened after a reset request, trigger reset late
- if (resetWasRequested) return triggerReset()
- // mark web3 as used
- pageIsUsingWeb3 = true
- // reset web3 reference
- window.web3 = web3
-}))
-
-// listen for reset requests
-mx.createStream('control').once('data', function(){
- resetWasRequested = true
- // ignore if web3 was not used
- if (!pageIsUsingWeb3) return
- // reload after short timeout
- triggerReset()
-})
-
-function triggerReset(){
- setTimeout(function(){
- window.location.reload()
- }, 500)
-}
-
-//
-// handle synchronous requests
-//
-
-global.publicConfigStore = publicConfigStore
+var reloadStream = inpageProvider.multiStream.createStream('reload')
+setupDappAutoReload(web3, reloadStream)
// set web3 defaultAcount
-publicConfigStore.subscribe(function(state){
+inpageProvider.publicConfigStore.subscribe(function(state){
web3.eth.defaultAccount = state.selectedAddress
})
-// setup sync http provider
-var providerConfig = publicConfigStore.get('provider') || {}
-var providerUrl = providerConfig.rpcTarget ? providerConfig.rpcTarget : DEFAULT_RPC_URL
-var syncProvider = new Web3.providers.HttpProvider(providerUrl)
-publicConfigStore.subscribe(function(state){
- if (!state.provider) return
- if (!state.provider.rpcTarget || state.provider.rpcTarget === providerUrl) return
- providerUrl = state.provider.rpcTarget
- syncProvider = new Web3.providers.HttpProvider(providerUrl)
-})
-
-// handle sync methods
-remoteProvider.send = function(payload){
- var result = null
- switch (payload.method) {
-
- case 'eth_accounts':
- // read from localStorage
- var selectedAddress = publicConfigStore.get('selectedAddress')
- result = selectedAddress ? [selectedAddress] : []
- break
-
- case 'eth_coinbase':
- // read from localStorage
- var selectedAddress = publicConfigStore.get('selectedAddress')
- result = selectedAddress || '0x0000000000000000000000000000000000000000'
- break
-
- // fallback to normal rpc
- default:
- return syncProvider.send(payload)
-
- }
-
- // return the result
- return {
- id: payload.id,
- jsonrpc: payload.jsonrpc,
- result: result,
- }
-}
-
-
//
// util
//
-// creates a proxy object that calls cb everytime the obj's properties/fns are accessed
-function ensnare(obj, cb){
- var proxy = {}
- Object.keys(obj).forEach(function(key){
- var val = obj[key]
- switch (typeof val) {
- case 'function':
- proxy[key] = function(){
- cb()
- val.apply(obj, arguments)
- }
- return
- default:
- Object.defineProperty(proxy, key, {
- get: function(){ cb(); return obj[key] },
- set: function(val){ cb(); return obj[key] = val },
- })
- return
- }
- })
- return proxy
-}
-
// need to make sure we aren't affected by overlapping namespaces
// and that we dont affect the app with our namespace
// mostly a fix for web3's BigNumber if AMD's "define" is defined...
diff --git a/app/scripts/lib/auto-reload.js b/app/scripts/lib/auto-reload.js
new file mode 100644
index 000000000..95a744b2c
--- /dev/null
+++ b/app/scripts/lib/auto-reload.js
@@ -0,0 +1,37 @@
+const once = require('once')
+const ensnare = require('./ensnare.js')
+
+module.exports = setupDappAutoReload
+
+
+function setupDappAutoReload(web3, controlStream){
+
+ // export web3 as a global, checking for usage
+ var pageIsUsingWeb3 = false
+ var resetWasRequested = false
+ global.web3 = ensnare(web3, once(function(){
+ // if web3 usage happened after a reset request, trigger reset late
+ if (resetWasRequested) return triggerReset()
+ // mark web3 as used
+ pageIsUsingWeb3 = true
+ // reset web3 reference
+ global.web3 = web3
+ }))
+
+ // listen for reset requests from metamask
+ controlStream.once('data', function(){
+ resetWasRequested = true
+ // ignore if web3 was not used
+ if (!pageIsUsingWeb3) return
+ // reload after short timeout
+ triggerReset()
+ })
+
+ // reload the page
+ function triggerReset(){
+ setTimeout(function(){
+ global.location.reload()
+ }, 500)
+ }
+
+}
\ No newline at end of file
diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js
index 3c9326db9..f5e1cf38d 100644
--- a/app/scripts/lib/config-manager.js
+++ b/app/scripts/lib/config-manager.js
@@ -1,11 +1,12 @@
const Migrator = require('pojo-migrator')
const extend = require('xtend')
+const MetamaskConfig = require('../config.js')
+const migrations = require('./migrations')
const STORAGE_KEY = 'metamask-config'
-const TESTNET_RPC = 'https://morden.infura.io'
-const MAINNET_RPC = 'https://mainnet.infura.io/'
+const TESTNET_RPC = MetamaskConfig.network.testnet
+const MAINNET_RPC = MetamaskConfig.network.mainnet
-const migrations = require('./migrations')
/* The config-manager is a convenience object
* wrapping a pojo-migrator.
@@ -229,6 +230,26 @@ ConfigManager.prototype.updateTx = function(tx) {
this._saveTxList(transactions)
}
+// wallet nickname methods
+
+ConfigManager.prototype.getWalletNicknames = function() {
+ var data = this.getData()
+ let nicknames = ('walletNicknames' in data) ? data.walletNicknames : {}
+ return nicknames
+}
+
+ConfigManager.prototype.nicknameForWallet = function(account) {
+ let nicknames = this.getWalletNicknames()
+ return nicknames[account]
+}
+
+ConfigManager.prototype.setNicknameForWallet = function(account, nickname) {
+ let nicknames = this.getWalletNicknames()
+ nicknames[account] = nickname
+ var data = this.getData()
+ data.walletNicknames = nicknames
+ this.setData(data)
+}
// observable
diff --git a/app/scripts/lib/ensnare.js b/app/scripts/lib/ensnare.js
new file mode 100644
index 000000000..b70330a5a
--- /dev/null
+++ b/app/scripts/lib/ensnare.js
@@ -0,0 +1,24 @@
+module.exports = ensnare
+
+// creates a proxy object that calls cb everytime the obj's properties/fns are accessed
+function ensnare(obj, cb){
+ var proxy = {}
+ Object.keys(obj).forEach(function(key){
+ var val = obj[key]
+ switch (typeof val) {
+ case 'function':
+ proxy[key] = function(){
+ cb()
+ val.apply(obj, arguments)
+ }
+ return
+ default:
+ Object.defineProperty(proxy, key, {
+ get: function(){ cb(); return obj[key] },
+ set: function(val){ cb(); return obj[key] = val },
+ })
+ return
+ }
+ })
+ return proxy
+}
diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js
index b8d825d8b..9d2552e8b 100644
--- a/app/scripts/lib/idStore.js
+++ b/app/scripts/lib/idStore.js
@@ -105,14 +105,29 @@ IdentityStore.prototype.getSelectedAddress = function(){
return configManager.getSelectedAccount()
}
-IdentityStore.prototype.setSelectedAddress = function(address){
+IdentityStore.prototype.setSelectedAddress = function(address, cb){
if (!address) {
var addresses = this._getAddresses()
address = addresses[0]
}
configManager.setSelectedAccount(address)
+ if (cb) return cb(null, address)
+}
+
+IdentityStore.prototype.revealAccount = function(cb) {
+ let addresses = this._getAddresses()
+ const derivedKey = this._idmgmt.derivedKey
+ const keyStore = this._keyStore
+
+ keyStore.setDefaultHdDerivationPath(this.hdPathString)
+ keyStore.generateNewAddress(derivedKey, 1)
+ configManager.setWallet(keyStore.serialize())
+
+ addresses = this._getAddresses()
+ this._loadIdentities()
this._didUpdate()
+ cb(null)
}
IdentityStore.prototype.getNetwork = function(tries) {
@@ -310,9 +325,10 @@ IdentityStore.prototype._loadIdentities = function(){
// // add to ethStore
this._ethStore.addAccount(address)
// add to identities
+ const defaultLabel = 'Wallet ' + (i+1)
+ const nickname = configManager.nicknameForWallet(address)
var identity = {
- name: 'Wallet ' + (i+1),
- img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd',
+ name: nickname || defaultLabel,
address: address,
mayBeFauceting: this._mayBeFauceting(i),
}
@@ -321,6 +337,13 @@ IdentityStore.prototype._loadIdentities = function(){
this._didUpdate()
}
+IdentityStore.prototype.saveAccountLabel = function(account, label, cb) {
+ configManager.setNicknameForWallet(account, label)
+ this._loadIdentities()
+ cb(null, label)
+ this._didUpdate()
+}
+
// mayBeFauceting
// If on testnet, index 0 may be fauceting.
// The UI will have to check the balance to know.
diff --git a/app/scripts/lib/inpage-provider.js b/app/scripts/lib/inpage-provider.js
new file mode 100644
index 000000000..70b0d80dd
--- /dev/null
+++ b/app/scripts/lib/inpage-provider.js
@@ -0,0 +1,123 @@
+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
+
+ 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
+}
\ No newline at end of file
diff --git a/app/scripts/lib/stream-provider.js b/app/scripts/lib/stream-provider.js
deleted file mode 100644
index 505e45d1f..000000000
--- a/app/scripts/lib/stream-provider.js
+++ /dev/null
@@ -1,72 +0,0 @@
-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._payloads = {}
-}
-
-// public
-
-StreamProvider.prototype.send = function(payload){
- throw new Error('StreamProvider - does not support synchronous RPC calls. called: "'+payload.method+'"')
-}
-
-StreamProvider.prototype.sendAsync = function(payload, callback){
- // console.log('StreamProvider - sending payload', payload)
- var id = payload.id
- if (Array.isArray(payload)) {
- id = 'batch'+payload[0].id
- }
- this._payloads[id] = [payload, callback]
- // console.log('payload for plugin:', payload)
- this.push(payload)
-}
-
-StreamProvider.prototype.isConnected = function(){
- return true
-}
-
-// private
-
-StreamProvider.prototype._onResponse = function(response){
- // console.log('StreamProvider - got response', payload)
- var id = response.id
- if (Array.isArray(response)) {
- id = 'batch'+response[0].id
- }
- var data = this._payloads[id]
- if (!data) throw new Error('StreamProvider - Unknown response id')
- delete this._payloads[id]
- var payload = data[0]
- var callback = data[1]
-
- // logging
- var res = Array.isArray(response) ? response : [response]
- // ;(Array.isArray(payload) ? payload : [payload]).forEach(function(payload, index){
- // console.log('plugin response:', payload.id, payload.method, payload.params, '->', res[index].result)
- // })
-
- callback(null, response)
-}
-
-// stream plumbing
-
-StreamProvider.prototype._read = noop
-
-StreamProvider.prototype._write = function(msg, encoding, cb){
- this._onResponse(msg)
- cb()
-}
-
-// util
-
-function noop(){}
\ No newline at end of file
diff --git a/app/scripts/popup.js b/app/scripts/popup.js
index e9ca7cd71..4fa6e1127 100644
--- a/app/scripts/popup.js
+++ b/app/scripts/popup.js
@@ -7,7 +7,7 @@ const MetaMaskUi = require('../../ui')
const MetaMaskUiCss = require('../../ui/css')
const injectCss = require('inject-css')
const PortStream = require('./lib/port-stream.js')
-const StreamProvider = require('./lib/stream-provider.js')
+const StreamProvider = require('web3-stream-provider')
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
// setup app
diff --git a/gulpfile.js b/gulpfile.js
index c4e9630ea..2322be608 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -30,6 +30,10 @@ gulp.task('copy:images', copyTask({
source: './app/images/',
destination: './dist/images',
}))
+gulp.task('copy:fonts', copyTask({
+ source: './app/fonts/',
+ destination: './dist/fonts',
+}))
gulp.task('copy:reload', copyTask({
source: './app/scripts/',
destination: './dist/scripts',
@@ -40,7 +44,7 @@ gulp.task('copy:root', copyTask({
destination: './dist',
pattern: '/*',
}))
-gulp.task('copy', gulp.parallel('copy:locales','copy:images','copy:reload','copy:root'))
+gulp.task('copy', gulp.parallel('copy:locales','copy:images','copy:fonts','copy:reload','copy:root'))
gulp.task('copy:watch', function(){
gulp.watch(['./app/{_locales,images}/', './app/scripts/chromereload.js', './app/*.{html,json}'], gulp.series('copy'))
})
diff --git a/package.json b/package.json
index 3bb2dd3a1..c5ec98b11 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,8 @@
},
"dependencies": {
"async": "^1.5.2",
+ "babel-preset-es2015": "^6.9.0",
+ "babel-register": "^6.9.0",
"browserify-derequire": "^0.9.4",
"clone": "^1.0.2",
"copy-to-clipboard": "^2.0.0",
@@ -36,26 +38,32 @@
"hat": "0.0.3",
"identicon.js": "^1.2.1",
"inject-css": "^0.1.1",
+ "jazzicon": "^1.1.3",
+ "menu-droppo": "^1.1.0",
"metamask-logo": "^1.1.5",
+ "mississippi": "^1.2.0",
"multiplex": "^6.7.0",
"once": "^1.3.3",
"pojo-migrator": "^2.1.0",
"polyfill-crypto.getrandomvalues": "^1.0.0",
"pumpify": "^1.3.4",
- "react": "^0.14.3",
- "react-addons-css-transition-group": "^0.14.7",
- "react-dom": "^0.14.3",
+ "react": "^15.0.2",
+ "react-addons-css-transition-group": "^15.0.2",
+ "react-dom": "^15.0.2",
"react-hyperscript": "^2.2.2",
- "react-redux": "^4.0.3",
+ "react-redux": "^4.4.5",
"readable-stream": "^2.1.2",
"redux": "^3.0.5",
"redux-logger": "^2.3.1",
"redux-thunk": "^1.0.2",
+ "sandwich-expando": "^1.0.5",
"textarea-caret": "^3.0.1",
"three.js": "^0.73.2",
"through2": "^2.0.1",
+ "vreme": "^3.0.2",
"web3": "ethereum/web3.js#0.16.0",
- "web3-provider-engine": "^7.6.3",
+ "web3-provider-engine": "^7.6.5",
+ "web3-stream-provider": "^2.0.1",
"xtend": "^4.0.1"
},
"devDependencies": {
diff --git a/svg-notifications.md b/svg-notifications.md
index bbb74da79..fd3b63f7a 100644
--- a/svg-notifications.md
+++ b/svg-notifications.md
@@ -12,6 +12,9 @@ Heres some utilities for preparing the data uri:
build a template using pure svg:
+generate uri
+'data:image/svg+xml;charset=utf-8,'+encodeURIComponent(svgSrc)
+