diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e6bc5299..9d89c2438 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,11 +2,37 @@
## Current Master
+- Fix bug where pending transactions from Test net (or other networks) show up In Main net.
+- Add fiat conversion values to more views.
+- On fresh install, open a new tab with the MetaMask Introduction video. Does not open on update.
+- Block negative values from transactions.
+- Fixed a memory leak.
+- MetaMask logo now renders as super lightweight SVG, improving compatibility and performance.
+- Now showing loading indication during vault unlocking, to clarify behavior for users who are experience slow unlocks.
+- Now only initially creates one wallet when restoring a vault, to reduce some users' confusion.
+
+## 2.10.2 2016-09-02
+
+- Fix bug where notification popup would not display.
+
+## 2.10.1 2016-09-02
+
+- Fix bug where provider menu did not allow switching to custom network from a custom network.
+- Sending a transaction from within MetaMask no longer triggers a popup.
+- The ability to build without livereload features (such as for production) can be enabled with the gulp --disableLiveReload flag.
+- Fix Ethereum JSON RPC Filters bug.
+
+## 2.10.0 2016-08-29
+
+- Changed transaction approval from notifications system to popup system.
+- Add a back button to locked screen to allow restoring vault from seed words when password is forgotten.
+- Forms now retain their values even when closing the popup and reopening it.
+- Fixed a spelling error in provider menu.
+
## 2.9.2 2016-08-24
- Fixed shortcut bug from preventing installation.
-
## 2.9.1 2016-08-24
- Added static image as fallback for when WebGL isn't supported.
@@ -27,7 +53,7 @@
## 2.8.0 2016-08-15
- Integrate ShapeShift
-- Add a for for Coinbase to specify amount to buy
+- Add a form for Coinbase to specify amount to buy
- Fix various typos.
- Make dapp-metamask connection more reliable
- Remove Ethereum Classic from provider menu.
diff --git a/README.md b/README.md
index 4c348b56c..afdda4d97 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,12 @@
# MetaMask Plugin [![Build Status](https://circleci.com/gh/MetaMask/metamask-plugin.svg?style=shield&circle-token=a1ddcf3cd38e29267f254c9c59d556d513e3a1fd)](https://circleci.com/gh/MetaMask/metamask-plugin)
+## Developing Compatible Dapps
+
+If you're a web dapp developer, we've got two types of guides for you:
+
+- If you've never built a Dapp before, we've got a gentle introduction on [Developing Dapps with Truffle and MetaMask](https://blog.metamask.io/developing-for-metamask-with-truffle/).
+- If you have a Dapp, and you want to ensure compatibility, [here is our guide on building MetaMask-compatible Dapps](https://github.com/MetaMask/faq/blob/master/DEVELOPERS.md)
+
## Building locally
- Install [Node.js](https://nodejs.org/en/) version 6.3.1 or later.
diff --git a/app/manifest.json b/app/manifest.json
index e5e08c4b6..0fee3f051 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,8 +1,9 @@
{
"name": "MetaMask",
"short_name": "Metamask",
- "version": "2.9.2",
+ "version": "2.10.2",
"manifest_version": 2,
+ "author": "https://metamask.io",
"description": "Ethereum Browser Extension",
"commands": {
"_execute_browser_action": {
@@ -28,7 +29,8 @@
"scripts": [
"scripts/chromereload.js",
"scripts/background.js"
- ]
+ ],
+ "persistent": true
},
"browser_action": {
"default_icon": {
diff --git a/app/notification.html b/app/notification.html
new file mode 100644
index 000000000..cc485da7f
--- /dev/null
+++ b/app/notification.html
@@ -0,0 +1,16 @@
+
+
+
+
+ MetaMask Notification
+
+
+
+
+
+
+
diff --git a/app/scripts/background.js b/app/scripts/background.js
index e04309e74..58228a41a 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -3,9 +3,7 @@ const extend = require('xtend')
const Dnode = require('dnode')
const eos = require('end-of-stream')
const PortStream = require('./lib/port-stream.js')
-const createUnlockRequestNotification = require('./lib/notifications.js').createUnlockRequestNotification
-const createTxNotification = require('./lib/notifications.js').createTxNotification
-const createMsgNotification = require('./lib/notifications.js').createMsgNotification
+const notification = require('./lib/notifications.js')
const messageManager = require('./lib/message-manager')
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
const MetamaskController = require('./metamask-controller')
@@ -26,50 +24,32 @@ const controller = new MetamaskController({
const idStore = controller.idStore
function unlockAccountMessage () {
- createUnlockRequestNotification({
- title: 'Account Unlock Request',
- })
+ notification.show()
}
function showUnconfirmedMessage (msgParams, msgId) {
- var controllerState = controller.getState()
-
- createMsgNotification({
- imageifyIdenticons: false,
- txData: {
- msgParams: msgParams,
- time: (new Date()).getTime(),
- },
- identities: controllerState.identities,
- accounts: controllerState.accounts,
- onConfirm: idStore.approveMessage.bind(idStore, msgId, noop),
- onCancel: idStore.cancelMessage.bind(idStore, msgId),
- })
+ notification.show()
}
function showUnconfirmedTx (txParams, txData, onTxDoneCb) {
- var controllerState = controller.getState()
-
- createTxNotification({
- imageifyIdenticons: false,
- txData: {
- txParams: txParams,
- time: (new Date()).getTime(),
- },
- identities: controllerState.identities,
- accounts: controllerState.accounts,
- onConfirm: idStore.approveTransaction.bind(idStore, txData.id, noop),
- onCancel: idStore.cancelTransaction.bind(idStore, txData.id),
- })
+ notification.show()
}
+// On first install, open a window to MetaMask website to how-it-works.
+
+extension.runtime.onInstalled.addListener(function (details) {
+ if (details.reason === 'install') {
+ extension.tabs.create({url: 'https://metamask.io/#how-it-works'})
+ }
+})
+
//
// connect to other contexts
//
extension.runtime.onConnect.addListener(connectRemote)
function connectRemote (remotePort) {
- var isMetaMaskInternalProcess = (remotePort.name === 'popup')
+ var isMetaMaskInternalProcess = remotePort.name === 'popup' || remotePort.name === 'notification'
var portStream = new PortStream(remotePort)
if (isMetaMaskInternalProcess) {
// communication with popup
@@ -109,7 +89,7 @@ function setupControllerConnection (stream) {
dnode.on('remote', (remote) => {
// push updates to popup
controller.ethStore.on('update', controller.sendUpdate.bind(controller))
- controller.remote = remote
+ controller.listeners.push(remote)
idStore.on('update', controller.sendUpdate.bind(controller))
// teardown on disconnect
@@ -188,5 +168,3 @@ function getOldStyleData () {
function setData (data) {
window.localStorage[STORAGE_KEY] = JSON.stringify(data)
}
-
-function noop () {}
diff --git a/app/scripts/chromereload.js b/app/scripts/chromereload.js
index 88333ba8a..f0bae403c 100644
--- a/app/scripts/chromereload.js
+++ b/app/scripts/chromereload.js
@@ -324,13 +324,13 @@ window.LiveReloadOptions = { host: 'localhost' };
this.pluginIdentifiers = {}
this.console = this.window.console && this.window.console.log && this.window.console.error ? this.window.location.href.match(/LR-verbose/) ? this.window.console : {
log: function () {},
- error: this.window.console.error.bind(this.window.console),
+ error: console.error,
} : {
log: function () {},
error: function () {},
}
if (!(this.WebSocket = this.window.WebSocket || this.window.MozWebSocket)) {
- this.console.error('LiveReload disabled because the browser does not seem to support web sockets')
+ console.error('LiveReload disabled because the browser does not seem to support web sockets')
return
}
if ('LiveReloadOptions' in window) {
@@ -344,7 +344,7 @@ window.LiveReloadOptions = { host: 'localhost' };
} else {
this.options = Options.extract(this.window.document)
if (!this.options) {
- this.console.error('LiveReload disabled because it could not find its own