From b4bd70c402e75f933e694e9f9df14912df468e69 Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
Date: Mon, 22 Sep 2014 14:54:27 +0200
Subject: Re-wrote ethereum.js

---
 mist/assets/debugger/debugger.qml |   8 +-
 mist/assets/ext/filter.js         |   8 +-
 mist/assets/ext/html_messaging.js | 350 ++++++++++++++++++++++-
 mist/assets/ext/pre.js            |  38 ---
 mist/assets/qml/wallet.qml        |  12 +-
 mist/assets/qml/webapp.qml        | 570 ++++++++++++++++++++------------------
 mist/debugger.go                  |   2 +-
 mist/ui_lib.go                    |  44 ++-
 8 files changed, 698 insertions(+), 334 deletions(-)

(limited to 'mist')

diff --git a/mist/assets/debugger/debugger.qml b/mist/assets/debugger/debugger.qml
index 2309a443b..8d54b5b5d 100644
--- a/mist/assets/debugger/debugger.qml
+++ b/mist/assets/debugger/debugger.qml
@@ -221,7 +221,7 @@ ApplicationWindow {
                             }
                             height: parent.height
                             width: 300
-                            TableViewColumn{ role: "value" ; title: "Temp" ; width: 200 }
+                            TableViewColumn{ role: "value" ; title: "Local VM stack" ; width: stackTableView.width - 2 }
                             model: stackModel
                         }
 
@@ -233,7 +233,7 @@ ApplicationWindow {
                             height: parent.height
                             width: parent.width - stackTableView.width
                             TableViewColumn{ id:mnumColmn ; role: "num" ; title: "#" ; width: 50 }
-                            TableViewColumn{ role: "value" ; title: "Memory" ; width: 750 }
+                            TableViewColumn{ role: "value" ; title: "Memory" ; width: 650 }
                             model: memModel
                         }
                     }
@@ -248,8 +248,8 @@ ApplicationWindow {
                             }
                             height: parent.height
                             width: parent.width
-                            TableViewColumn{ id: key ; role: "key" ; title: "#" ; width: storageTableView.width / 2}
-                            TableViewColumn{ role: "value" ; title: "Storage" ; width:  storageTableView.width / 2}
+                            TableViewColumn{ id: key ; role: "key" ; title: "#" ; width: storageTableView.width / 2 - 1}
+                            TableViewColumn{ role: "value" ; title: "Storage" ; width:  storageTableView.width / 2 - 1}
                             model: storageModel
                         }
                     }
diff --git a/mist/assets/ext/filter.js b/mist/assets/ext/filter.js
index bc6a93144..c23706249 100644
--- a/mist/assets/ext/filter.js
+++ b/mist/assets/ext/filter.js
@@ -31,11 +31,11 @@ Filter.prototype.changed = function(callback) {
     this.callbacks.push(callback);
 
 	var self = this;
-	message.connect(function(messages, id) {
+	messages.connect(function(messages, id) {
 		if(id ==  self.id) {
-            for(var i = 0; i < self.callbacks.length; i++) {
-                self.callbacks[i].call(self, messages);
-            }
+			for(var i = 0; i < self.callbacks.length; i++) {
+				self.callbacks[i].call(self, messages);
+			}
 		}
 	});
 };
diff --git a/mist/assets/ext/html_messaging.js b/mist/assets/ext/html_messaging.js
index cf6d72cfa..3c67c77ea 100644
--- a/mist/assets/ext/html_messaging.js
+++ b/mist/assets/ext/html_messaging.js
@@ -12,15 +12,46 @@
 
 	window.eth = {
 		_callbacks: {},
-		_onCallbacks: {},
+		_events: {},
 		prototype: Object(),
 
-		coinbase: function() {
-			return new Promise(function(resolve, reject) {
-				postData({call: "getCoinBase"}, function(coinbase) {
-					resolve(coinbase);
-				});
-			});
+		toHex: function(str) {
+			var hex = "";
+			for(var i = 0; i < str.length; i++) {
+				var n = str.charCodeAt(i).toString(16);
+				hex += n.length < 2 ? '0' + n : n;
+			}
+
+			return hex;
+		},
+
+		toAscii: function(hex) {
+			// Find termination
+			var str = "";
+			var i = 0, l = hex.length;
+			for(; i < l; i+=2) {
+				var code = hex.charCodeAt(i)
+				if(code == 0) {
+					break;
+				}
+
+				str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
+			}
+
+			return str;
+		},
+
+		fromAscii: function(str, pad) {
+			if(pad === undefined) {
+				pad = 32
+			}
+
+			var hex = this.toHex(str);
+
+			while(hex.length < pad*2)
+				hex += "00";
+
+			return hex
 		},
 
 		block: function(numberOrHash) {
@@ -107,17 +138,316 @@
 			});
 		},
 
-		key: function() {
+		balanceAt: function(address) {
+			var promises = [];
+
+			if(isPromise(address)) {
+				promises.push(address.then(function(_address) { address = _address; }));
+			}
+
+			return Q.all(promises).then(function() {
+				return new Promise(function(resolve, reject) {
+					postData({call: "getBalanceAt", args: [address]}, function(balance) {
+						resolve(balance);
+					});
+				});
+			});
+		},
+
+		countAt: function(address) {
+			var promises = [];
+
+			if(isPromise(address)) {
+				promises.push(address.then(function(_address) { address = _address; }));
+			}
+
+			return Q.all(promises).then(function() {
+				return new Promise(function(resolve, reject) {
+					postData({call: "getCountAt", args: [address]}, function(count) {
+						resolve(count);
+					});
+				});
+			});
+		},
+
+		codeAt: function(address) {
+			var promises = [];
+
+			if(isPromise(address)) {
+				promises.push(address.then(function(_address) { address = _address; }));
+			}
+
+			return Q.all(promises).then(function() {
+				return new Promise(function(resolve, reject) {
+					postData({call: "getCodeAt", args: [address]}, function(code) {
+						resolve(code);
+					});
+				});
+			});
+		},
+
+		storageAt: function(address, storageAddress) {
+			var promises = [];
+
+			if(isPromise(address)) {
+				promises.push(address.then(function(_address) { address = _address; }));
+			}
+
+			if(isPromise(storageAddress)) {
+				promises.push(storageAddress.then(function(_sa) { storageAddress = _sa; }));
+			}
+
+			return Q.all(promises).then(function() {
+				return new Promise(function(resolve, reject) {
+					postData({call: "getStorageAt", args: [address, storageAddress]}, function(entry) {
+						resolve(entry);
+					});
+				});
+			});
+		},
+
+		stateAt: function(address, storageAddress) {
+			return this.storageAt(address, storageAddress);
+		},
+
+		call: function(params) {
+			if(params === undefined) {
+				params = {};
+			}
+
+			if(params.endowment !== undefined)
+				params.value = params.endowment;
+			if(params.code !== undefined)
+				params.data = params.code;
+
+
+			var promises = []
+			if(isPromise(params.to)) {
+				promises.push(params.to.then(function(_to) { params.to = _to; }));
+			}
+			if(isPromise(params.from)) {
+				promises.push(params.from.then(function(_from) { params.from = _from; }));
+			}
+
+			if(isPromise(params.data)) {
+				promises.push(params.data.then(function(_code) { params.data = _code; }));
+			} else {
+				if(typeof params.data === "object") {
+					data = "";
+					for(var i = 0; i < params.data.length; i++) {
+						data += params.data[i]
+					}
+				} else {
+					data = params.data;
+				}
+			}
+
+			// Make sure everything is string
+			var fields = ["value", "gas", "gasPrice"];
+			for(var i = 0; i < fields.length; i++) {
+				if(params[fields[i]] === undefined) {
+					params[fields[i]] = "";
+				}
+				params[fields[i]] = params[fields[i]].toString();
+			}
+
+			// Load promises then call the last "transact".
+			return Q.all(promises).then(function() {
+				return new Promise(function(resolve, reject) {
+					postData({call: "call", args: params}, function(data) {
+						if(data[1])
+							reject(data[0]);
+						else
+							resolve(data[0]);
+					});
+				});
+			})
+		},
+
+		watch: function(params) {
+			return new Filter(params);
+		},
+
+		secretToAddress: function(key) {
+			var promises = [];
+			if(isPromise(key)) {
+				promises.push(key.then(function(_key) { key = _key; }));
+			}
+
+			return Q.all(promises).then(function() {
+				return new Promise(function(resolve, reject) {
+					postData({call: "getSecretToAddress", args: [key]}, function(address) {
+						resolve(address);
+					});
+				});
+			});
+		},
+
+		on: function(event, cb) {
+			if(eth._events[event] === undefined) {
+				eth._events[event] = [];
+			}
+
+			eth._events[event].push(cb);
+
+			return this
+		},
+
+		off: function(event, cb) {
+			if(eth._events[event] !== undefined) {
+				var callbacks = eth._events[event];
+				for(var i = 0; i < callbacks.length; i++) {
+					if(callbacks[i] === cb) {
+						delete callbacks[i];
+					}
+				}
+			}
+
+			return this
+		},
+
+		trigger: function(event, data) {
+			var callbacks = eth._events[event];
+			if(callbacks !== undefined) {
+				for(var i = 0; i < callbacks.length; i++) {
+					// Figure out whether the returned data was an array
+					// array means multiple return arguments (multiple params)
+					if(data instanceof Array) {
+						callbacks[i].apply(this, data);
+					} else {
+						callbacks[i].call(this, data);
+					}
+				}
+			}
+		},
+	};
+
+	// Eth object properties
+	Object.defineProperty(eth, "key", {
+		get: function() {
 			return new Promise(function(resolve, reject) {
 				postData({call: "getKey"}, function(k) {
 					resolve(k);
 				});
 			});
+		},
+	});
+
+	Object.defineProperty(eth, "gasPrice", {
+		get: function() {
+			return "1000000000000"
 		}
+	});
+
+	Object.defineProperty(eth, "coinbase", {
+		get: function() {
+			return new Promise(function(resolve, reject) {
+				postData({call: "getCoinBase"}, function(coinbase) {
+					resolve(coinbase);
+				});
+			});
+		},
+	});
+
+	Object.defineProperty(eth, "listening", {
+		get: function() {
+			return new Promise(function(resolve, reject) {
+				postData({call: "getIsListening"}, function(listening) {
+					resolve(listening);
+				});
+			});
+		},
+	});
+
+
+	Object.defineProperty(eth, "mining", {
+		get: function() {
+			return new Promise(function(resolve, reject) {
+				postData({call: "getIsMining"}, function(mining) {
+					resolve(mining);
+				});
+			});
+		},
+	});
+
+	Object.defineProperty(eth, "peerCount", {
+		get: function() {
+			return new Promise(function(resolve, reject) {
+				postData({call: "getPeerCount"}, function(peerCount) {
+					resolve(peerCount);
+				});
+			});
+		},
+	});
+
+	var filters = [];
+	var Filter = function(options) {
+		filters.push(this);
+
+		this.callbacks = [];
+		this.options = options;
+
+		var call;
+		if(options === "chain") {
+			call = "newFilterString"
+		} else if(typeof options === "object") {
+			call = "newFilter"
+		}
+
+		var self = this; // Cheaper than binding
+		this.promise = new Promise(function(resolve, reject) {
+			postData({call: call, args: [options]}, function(id) {
+				self.id = id;
+
+				resolve(id);
+			});
+		});
+	};
+
+	Filter.prototype.changed = function(callback) {
+		var self = this;
+		this.promise.then(function(id) {
+			self.callbacks.push(callback);
+		});
 	};
 
+	Filter.prototype.trigger = function(messages, id) {
+		if(id == this.id) {
+			for(var i = 0; i < this.callbacks.length; i++) {
+				this.callbacks[i].call(this, messages);
+			}
+		}
+	};
+
+	Filter.prototype.uninstall = function() {
+		this.promise.then(function(id) {
+			postData({call: "uninstallFilter", args:[id]});
+		});
+	};
+
+	Filter.prototype.messages = function() {
+		var self=this;
+		return Q.all([this.promise]).then(function() {
+			var id = self.id
+			return new Promise(function(resolve, reject) {
+				postData({call: "getMessages", args: [id]}, function(messages) {
+					resolve(messages);
+				});
+			});
+		});
+	};
+
+	// Register to the messages callback. "messages" will be emitted when new messages
+	// from the client have been created.
+	eth.on("messages", function(messages, id) {
+		for(var i = 0; i < filters.length; i++) {
+			filters[i].trigger(messages, id);
+		}
+	});
+
+	var g_seed = 1;
 	function postData(data, cb) {
-		data._seed = Math.floor(Math.random() * 1000000)
+		data._seed = g_seed;
 		if(cb) {
 			eth._callbacks[data._seed] = cb;
 		}
@@ -126,6 +456,8 @@
 			data.args = [];
 		}
 
+		g_seed++;
+
 		navigator.qt.postMessage(JSON.stringify(data));
 	}
 
diff --git a/mist/assets/ext/pre.js b/mist/assets/ext/pre.js
index 528149f6b..f298fe9a1 100644
--- a/mist/assets/ext/pre.js
+++ b/mist/assets/ext/pre.js
@@ -1,41 +1,3 @@
-// Helper function for generating pseudo callbacks and sending data to the QML part of the application
-function postData(data, cb) {
-	data._seed = Math.floor(Math.random() * 1000000)
-	if(cb) {
-		eth._callbacks[data._seed] = cb;
-	}
-
-	if(data.args === undefined) {
-		data.args = [];
-	}
-
-	navigator.qt.postMessage(JSON.stringify(data));
-}
-
-navigator.qt.onmessage = function(ev) {
-	var data = JSON.parse(ev.data)
-
-	if(data._event !== undefined) {
-		eth.trigger(data._event, data.data);
-	} else {
-		if(data._seed) {
-			var cb = eth._callbacks[data._seed];
-			if(cb) {
-				// Figure out whether the returned data was an array
-				// array means multiple return arguments (multiple params)
-				if(data.data instanceof Array) {
-					cb.apply(this, data.data)
-				} else {
-					cb.call(this, data.data)
-				}
-
-				// Remove the "trigger" callback
-				delete eth._callbacks[ev._seed];
-			}
-		}
-	}
-}
-
 if(typeof(Promise) === "undefined") {
 	window.Promise = Q.Promise;
 }
diff --git a/mist/assets/qml/wallet.qml b/mist/assets/qml/wallet.qml
index 5b402a214..c4379cd47 100644
--- a/mist/assets/qml/wallet.qml
+++ b/mist/assets/qml/wallet.qml
@@ -14,20 +14,22 @@ ApplicationWindow {
 
     property alias miningButtonText: miningButton.text
     property var ethx : Eth.ethx
+    property var web
 
-    width: 900
-    height: 600
+    width: 1024
+    height: 750
     minimumHeight: 300
 
     title: "Mist"
 
     // This signal is used by the filter API. The filter API connects using this signal handler from
     // the different QML files and plugins.
-    signal message(var callback, int seed);
+    signal messages(var messages, int id);
     function invokeFilterCallback(data, receiverSeed) {
         //var messages = JSON.parse(data)
         // Signal handler
-        message(data, receiverSeed);
+        messages(data, receiverSeed);
+	root.web.messages(data, receiverSeed);
     }
 
     TextField {
@@ -44,7 +46,7 @@ ApplicationWindow {
     // Takes care of loading all default plugins
     Component.onCompleted: {
         addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
-        addPlugin("./webapp.qml", {noAdd: true, close: false, section: "ethereum", active: true});
+        root.web = addPlugin("./webapp.qml", {noAdd: true, close: false, section: "ethereum", active: true});
 
         addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
         addPlugin("./views/chain.qml", {noAdd: true, close: false, section: "legacy"});
diff --git a/mist/assets/qml/webapp.qml b/mist/assets/qml/webapp.qml
index 186718ab5..8801b6b47 100644
--- a/mist/assets/qml/webapp.qml
+++ b/mist/assets/qml/webapp.qml
@@ -10,265 +10,279 @@ import Ethereum 1.0
 import "../ext/qml_messaging.js" as Messaging
 
 //ApplicationWindow {
-Rectangle {
-	id: window
-	property var title: "Browser"
-	property var iconSource: "../browser.png"
-	property var menuItem
+	Rectangle {
+		id: window
+		property var title: "Browser"
+		property var iconSource: "../browser.png"
+		property var menuItem
 
-	property alias url: webview.url
-	property alias webView: webview
+		property alias url: webview.url
+		property alias webView: webview
 
-	Component.onCompleted: {
-		webview.url = "http://etherian.io"
-	}
+		Component.onCompleted: {
+			webview.url = "http://etherian.io"
+		}
 
-	Item {
-		objectName: "root"
-		id: root
-		anchors.fill: parent
-		state: "inspectorShown"
-
-		RowLayout {
-			id: navBar
-			height: 40
-			anchors {
-				left: parent.left
-				right: parent.right
-				leftMargin: 7
-			}
+		signal messages(var messages, int id);
+		onMessages: {
+			// Bit of a cheat to get proper JSON
+			var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
+			webview.postEvent("messages", [m, id]);
+		}
 
-			Button {
-				id: back
-				onClicked: {
-					webview.goBack()
-				}
-				style: ButtonStyle {
-					background: Image {
-						source: "../back.png"
-						width: 30
-						height: 30
-					}
-				}
-			}
+		Item {
+			objectName: "root"
+			id: root
+			anchors.fill: parent
+			state: "inspectorShown"
 
-			TextField {
+			RowLayout {
+				id: navBar
+				height: 40
 				anchors {
-					left: back.right
-					right: toggleInspector.left
-					leftMargin: 5
-					rightMargin: 5
+					left: parent.left
+					right: parent.right
+					leftMargin: 7
 				}
-				text: "http://etherian.io"
-				id: uriNav
-				y: parent.height / 2 - this.height / 2
 
-				Keys.onReturnPressed: {
-					webview.url = this.text;
+				Button {
+					id: back
+					onClicked: {
+						webview.goBack()
+					}
+					style: ButtonStyle {
+						background: Image {
+							source: "../back.png"
+							width: 30
+							height: 30
+						}
+					}
 				}
-			}
 
-			Button {
-				id: toggleInspector
-				anchors {
-					right: parent.right
+				TextField {
+					anchors {
+						left: back.right
+						right: toggleInspector.left
+						leftMargin: 5
+						rightMargin: 5
+					}
+					text: "http://etherian.io"
+					id: uriNav
+					y: parent.height / 2 - this.height / 2
+
+					Keys.onReturnPressed: {
+						webview.url = this.text;
+					}
 				}
-				iconSource: "../bug.png"
-				onClicked: {
-					if(inspector.visible == true){
-						inspector.visible = false
-					}else{
-						inspector.visible = true
-						inspector.url = webview.experimental.remoteInspectorUrl
+
+				Button {
+					id: toggleInspector
+					anchors {
+						right: parent.right
+					}
+					iconSource: "../bug.png"
+					onClicked: {
+						if(inspector.visible == true){
+							inspector.visible = false
+						}else{
+							inspector.visible = true
+							inspector.url = webview.experimental.remoteInspectorUrl
+						}
 					}
 				}
 			}
-		}
 
 
-		WebView {
-			objectName: "webView"
-			id: webview
-			anchors {
-				left: parent.left
-				right: parent.right
-				bottom: parent.bottom
-				top: navBar.bottom
-			}
+			WebView {
+				objectName: "webView"
+				id: webview
+				anchors {
+					left: parent.left
+					right: parent.right
+					bottom: parent.bottom
+					top: navBar.bottom
+				}
 
-			property var cleanPath: false
-			onNavigationRequested: {
-				if(!this.cleanPath) {
-					var uri = request.url.toString();
-					if(!/.*\:\/\/.*/.test(uri)) {
-						uri = "http://" + uri;
+				property var cleanPath: false
+				onNavigationRequested: {
+					if(!this.cleanPath) {
+						var uri = request.url.toString();
+						if(!/.*\:\/\/.*/.test(uri)) {
+							uri = "http://" + uri;
+						}
+
+						var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/
+
+						if(reg.test(uri)) {
+							uri.replace(reg, function(match, pre, domain, path) {
+								uri = pre;
+
+								var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4));
+								var ip = [];
+								for(var i = 0, l = lookup.length; i < l; i++) {
+									ip.push(lookup.charCodeAt(i))
+								}
+
+								if(ip.length != 0) {
+									uri += lookup;
+								} else {
+									uri += domain;
+								}
+
+								uri += path;
+							});
+						}
+
+						this.cleanPath = true;
+
+						webview.url = uri;
+					} else {
+						// Prevent inf loop.
+						this.cleanPath = false;
 					}
+				}
 
-					var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/
-
-					if(reg.test(uri)) {
-						uri.replace(reg, function(match, pre, domain, path) {
-							uri = pre;
-
-							var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4));
-							var ip = [];
-							for(var i = 0, l = lookup.length; i < l; i++) {
-								ip.push(lookup.charCodeAt(i))
-							}
-
-							if(ip.length != 0) {
-								uri += lookup;
-							} else {
-								uri += domain;
-							}
+				function sendMessage(data) {
+					webview.experimental.postMessage(JSON.stringify(data))
+				}
 
-							uri += path;
-						});
+				onTitleChanged: {
+					var data = Messaging.HandleMessage(title);
+					if(data) {
+						sendMessage(data)
 					}
-
-					this.cleanPath = true;
-
-					webview.url = uri;
-				} else {
-					// Prevent inf loop.
-					this.cleanPath = false;
 				}
-			}
 
-			function sendMessage(data) {
-				//this.experimental.evaluateJavaScript("window.____returnData="+JSON.stringify(data));
-				webview.experimental.postMessage(JSON.stringify(data))
-			}
-
-			onTitleChanged: {
-				var data = Messaging.HandleMessage(title);
-				if(data) {
-					sendMessage(data)
-				}
-			}
+				experimental.preferences.javascriptEnabled: true
+				experimental.preferences.navigatorQtObjectEnabled: true
+				experimental.preferences.developerExtrasEnabled: true
+				experimental.userScripts: ["../ext/q.js", "../ext/pre.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"]
+				experimental.onMessageReceived: {
+					console.log("[onMessageReceived]: ", message.data)
+					// TODO move to messaging.js
+					var data = JSON.parse(message.data)
+
+					try {
+						switch(data.call) {
+							case "compile":
+							postData(data._seed, eth.compile(data.args[0]))
+							break
 
-			experimental.preferences.javascriptEnabled: true
-			experimental.preferences.navigatorQtObjectEnabled: true
-			experimental.preferences.developerExtrasEnabled: true
-			experimental.userScripts: ["../ext/q.js", "../ext/pre.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"]
-			experimental.onMessageReceived: {
-				console.log("[onMessageReceived]: ", message.data)
-				// TODO move to messaging.js
-				var data = JSON.parse(message.data)
+							case "getCoinBase":
+							postData(data._seed, eth.coinBase())
 
-				try {
-					switch(data.call) {
-						case "compile":
-						postData(data._seed, eth.compile(data.args[0]))
-						break
+							break
 
-						case "getCoinBase":
-						postData(data._seed, eth.coinBase())
+							case "getIsListening":
+							postData(data._seed, eth.isListening())
 
-						break
+							break
 
-						case "getIsListening":
-						postData(data._seed, eth.isListening())
+							case "getIsMining":
+							postData(data._seed, eth.isMining())
 
-						break
+							break
 
-						case "getIsMining":
-						postData(data._seed, eth.isMining())
+							case "getPeerCount":
+							postData(data._seed, eth.peerCount())
 
-						break
+							break
 
-						case "getPeerCount":
-						postData(data._seed, eth.peerCount())
+							case "getCountAt":
+							require(1)
+							postData(data._seed, eth.txCountAt(data.args[0]))
 
-						break
+							break
 
-						case "getTxCountAt":
-						require(1)
-						postData(data._seed, eth.txCountAt(data.args[0]))
+							case "getCodeAt":
+							require(1)
+							var code = eth.codeAt(data.args[0])
+							postData(data._seed, code);
 
-						break
+							break
 
-						case "getBlockByNumber":
-						var block = eth.blockByNumber(data.args[0])
-						postData(data._seed, block)
+							case "getBlockByNumber":
+							var block = eth.blockByNumber(data.args[0])
+							postData(data._seed, block)
 
-						break
+							break
 
-						case "getBlockByHash":
-						var block = eth.blockByHash(data.args[0])
-						postData(data._seed, block)
+							case "getBlockByHash":
+							var block = eth.blockByHash(data.args[0])
+							postData(data._seed, block)
 
-						break
+							break
 
-						case "transact":
-						require(5)
+							case "transact":
+							require(5)
 
-						var tx = eth.transact(data.args)
-						console.log("transactx", tx)
-						postData(data._seed, tx)
+							var tx = eth.transact(data.args)
+							postData(data._seed, tx)
 
-						break
+							break
 
-						case "getStorage":
-						require(2);
+							case "getStorageAt":
+							require(2);
 
-						var stateObject = eth.stateObject(data.args[0])
-						var storage = stateObject.storageAt(data.args[1])
-						postData(data._seed, storage)
+							var storage = eth.storageAt(data.args[0], data.args[1]);
+							postData(data._seed, storage)
 
-						break
+							break
 
-						case "getEachStorage":
-						require(1);
-						var storage = JSON.parse(eth.eachStorage(data.args[0]))
-						postData(data._seed, storage)
+							case "call":
+							require(1);
+							var ret = eth.call(data.args)
+							postData(data._seed, ret)
 
-						break
+							break
 
-						case "getTransactionsFor":
-						require(1);
-						var txs = eth.transactionsFor(data.args[0], true)
-						postData(data._seed, txs)
+							case "getEachStorage":
+							require(1);
+							var storage = JSON.parse(eth.eachStorage(data.args[0]))
+							postData(data._seed, storage)
 
-						break
+							break
 
-						case "getBalance":
-						require(1);
+							case "getTransactionsFor":
+							require(1);
+							var txs = eth.transactionsFor(data.args[0], true)
+							postData(data._seed, txs)
 
-						postData(data._seed, eth.stateObject(data.args[0]).value());
+							break
 
-						break
+							case "getBalanceAt":
+							require(1);
 
-						case "getKey":
-						var key = eth.key().privateKey;
+							postData(data._seed, eth.balanceAt(data.args[0]));
 
-						postData(data._seed, key)
-						break
+							break
 
-						/*
-						case "watch":
-							require(1)
-							eth.watch(data.args[0], data.args[1]);
+							case "getKey":
+							var key = eth.key().privateKey;
 
+							postData(data._seed, key)
 							break
-						*/
-					       case "watch":
-					       		require(2)
+
+							case "watch":
+							require(2)
 							eth.watch(data.args[0], data.args[1])
 
-						case "disconnect":
-						require(1)
-						postData(data._seed, null)
+							case "disconnect":
+							require(1)
+							postData(data._seed, null)
+
+							break;
 
-						break;
+							case "getSecretToAddress":
+							require(1)
 
-						case "getSecretToAddress":
-						require(1)
-						postData(data._seed, eth.secretToAddress(data.args[0]))
+							var addr = eth.secretToAddress(data.args[0])
+							console.log("getsecret", addr)
+							postData(data._seed, addr)
 
-						break;
+							break;
 
-						case "messages":
+							case "messages":
 							require(1);
 
 							var messages = JSON.parse(eth.getMessages(data.args[0]))
@@ -276,94 +290,120 @@ Rectangle {
 
 							break
 
-						case "mutan":
+							case "mutan":
 							require(1)
 
 							var code = eth.compileMutan(data.args[0])
 							postData(data._seed, "0x"+code)
 
 							break;
-					}
-				} catch(e) {
-					console.log(data.call + ": " + e)
 
-					postData(data._seed, null);
+							case "newFilterString":
+							require(1)
+							var id = eth.newFilterString(data.args[0])
+							postData(data._seed, id);
+							break;
+							case "newFilter":
+							require(1)
+							var id = eth.newFilter(data.args[0])
+
+							postData(data._seed, id);
+							break;
+
+							case "getMessages":
+							require(1);
+
+							var messages = eth.messages(data.args[0]);
+							var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
+							postData(data._seed, m);
+
+							break;
+
+							case "deleteFilter":
+							require(1);
+							eth.uninstallFilter(data.args[0])
+							break;
+						}
+					} catch(e) {
+						console.log(data.call + ": " + e)
+
+						postData(data._seed, null);
+					}
 				}
-			}
 
-			function post(seed, data) {
-				console.log("data", data)
-				postData(data._seed, data)
-			}
 
-			function require(args, num) {
-				if(args.length < num) {
-					throw("required argument count of "+num+" got "+args.length);
+				function post(seed, data) {
+					postData(data._seed, data)
 				}
-			}
-			function postData(seed, data) {
-				webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed}))
-			}
-			function postEvent(event, data) {
-				webview.experimental.postMessage(JSON.stringify({data: data, _event: event}))
-			}
 
-			function onWatchedCb(data, id) {
-				var messages = JSON.parse(data)
-				postEvent("watched:"+id, messages)
-			}
+				function require(args, num) {
+					if(args.length < num) {
+						throw("required argument count of "+num+" got "+args.length);
+					}
+				}
+				function postData(seed, data) {
+					webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed}))
+				}
+				function postEvent(event, data) {
+					webview.experimental.postMessage(JSON.stringify({data: data, _event: event}))
+				}
 
-			function onNewBlockCb(block) {
-				postEvent("block:new", block)
-			}
-			function onObjectChangeCb(stateObject) {
-				postEvent("object:"+stateObject.address(), stateObject)
-			}
-			function onStorageChangeCb(storageObject) {
-				var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
-				postEvent(ev, [storageObject.address, storageObject.value])
+				function onWatchedCb(data, id) {
+					var messages = JSON.parse(data)
+					postEvent("watched:"+id, messages)
+				}
+
+				function onNewBlockCb(block) {
+					postEvent("block:new", block)
+				}
+				function onObjectChangeCb(stateObject) {
+					postEvent("object:"+stateObject.address(), stateObject)
+				}
+				function onStorageChangeCb(storageObject) {
+					var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
+					postEvent(ev, [storageObject.address, storageObject.value])
+				}
 			}
-		}
 
 
-		Rectangle {
-			id: sizeGrip
-			color: "gray"
-			visible: false
-			height: 10
-			anchors {
-				left: root.left
-				right: root.right
-			}
-			y: Math.round(root.height * 2 / 3)
-
-			MouseArea {
-				anchors.fill: parent
-				drag.target: sizeGrip
-				drag.minimumY: 0
-				drag.maximumY: root.height
-				drag.axis: Drag.YAxis
+			Rectangle {
+				id: sizeGrip
+				color: "gray"
+				visible: false
+				height: 10
+				anchors {
+					left: root.left
+					right: root.right
+				}
+				y: Math.round(root.height * 2 / 3)
+
+				MouseArea {
+					anchors.fill: parent
+					drag.target: sizeGrip
+					drag.minimumY: 0
+					drag.maximumY: root.height
+					drag.axis: Drag.YAxis
+				}
 			}
-		}
 
-		WebView {
-			id: inspector
-			visible: false
-			anchors {
-				left: root.left
-				right: root.right
-				top: sizeGrip.bottom
-				bottom: root.bottom
+			WebView {
+				id: inspector
+				visible: false
+				anchors {
+					left: root.left
+					right: root.right
+					top: sizeGrip.bottom
+					bottom: root.bottom
+				}
 			}
-		}
 
-		states: [
-			State {
-				name: "inspectorShown"
-				PropertyChanges {
-					target: inspector
+			states: [
+				State {
+					name: "inspectorShown"
+					PropertyChanges {
+						target: inspector
+					}
 				}
-			}
-		]
+			]
+		}
 	}
-}
diff --git a/mist/debugger.go b/mist/debugger.go
index 8f3fc6751..9d1de8c42 100644
--- a/mist/debugger.go
+++ b/mist/debugger.go
@@ -276,7 +276,7 @@ func (d *Debugger) halting(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *et
 	d.win.Root().Call("clearStorage")
 
 	addr := 0
-	for i := 0; i+32 <= mem.Len(); i += 16 {
+	for i := 0; i+16 <= mem.Len(); i += 16 {
 		dat := mem.Data()[i : i+16]
 		var str string
 
diff --git a/mist/ui_lib.go b/mist/ui_lib.go
index 334442f9f..a913af7db 100644
--- a/mist/ui_lib.go
+++ b/mist/ui_lib.go
@@ -37,7 +37,6 @@ type UiLib struct {
 	jsEngine *javascript.JSRE
 
 	filterCallbacks map[int][]int
-	//filters         map[int]*ethpipe.JSFilter
 }
 
 func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
@@ -201,7 +200,7 @@ func (self *UiLib) UninstallFilter(id int) {
 	self.eth.UninstallFilter(id)
 }
 
-func (self *UiLib) Transact(object map[string]interface{}) (*ethpipe.JSReceipt, error) {
+func mapToTxParams(object map[string]interface{}) map[string]string {
 	// Default values
 	if object["from"] == nil {
 		object["from"] = ""
@@ -223,6 +222,8 @@ func (self *UiLib) Transact(object map[string]interface{}) (*ethpipe.JSReceipt,
 	var data []string
 	if list, ok := object["data"].(*qml.List); ok {
 		list.Convert(&data)
+	} else if str, ok := object["data"].(string); ok {
+		data = []string{str}
 	}
 
 	for _, str := range data {
@@ -238,14 +239,29 @@ func (self *UiLib) Transact(object map[string]interface{}) (*ethpipe.JSReceipt,
 
 		dataStr += str
 	}
+	object["data"] = dataStr
+	fmt.Println(object)
+
+	conv := make(map[string]string)
+	for key, value := range object {
+		if v, ok := value.(string); ok {
+			conv[key] = v
+		}
+	}
+
+	return conv
+}
+
+func (self *UiLib) Transact(params map[string]interface{}) (*ethpipe.JSReceipt, error) {
+	object := mapToTxParams(params)
 
 	return self.JSPipe.Transact(
-		object["from"].(string),
-		object["to"].(string),
-		object["value"].(string),
-		object["gas"].(string),
-		object["gasPrice"].(string),
-		dataStr,
+		object["from"],
+		object["to"],
+		object["value"],
+		object["gas"],
+		object["gasPrice"],
+		object["data"],
 	)
 }
 
@@ -257,3 +273,15 @@ func (self *UiLib) Compile(code string) (string, error) {
 
 	return ethutil.Bytes2Hex(bcode), err
 }
+
+func (self *UiLib) Call(params map[string]interface{}) (string, error) {
+	object := mapToTxParams(params)
+
+	return self.JSPipe.Execute(
+		object["to"],
+		object["value"],
+		object["gas"],
+		object["gasPrice"],
+		object["data"],
+	)
+}
-- 
cgit v1.2.3