diff --git a/lib/abi.js b/lib/abi.js
index 3df0fe684b0670631dd34c0a5d9f46bbc1576425..2cff503d3840d6fe599fac86d3cfac600acc8e34 100644
--- a/lib/abi.js
+++ b/lib/abi.js
@@ -17,9 +17,19 @@
 /** @file abi.js
  * @authors:
  *   Marek Kotewicz <marek@ethdev.com>
+ *   Gav Wood <g@ethdev.com>
  * @date 2014
  */
 
+// TODO: make these be actually accurate instead of falling back onto JS's doubles.
+var hexToDec = function (hex) {
+    return parseInt(hex, 16).toString();
+};
+
+var decToHex = function (dec) {
+    return parseInt(dec).toString(16);
+};
+
 var findIndex = function (array, callback) {
     var end = false;
     var i = 0;
@@ -35,8 +45,8 @@ var findMethodIndex = function (json, methodName) {
     });
 };
 
-var padLeft = function (number, n) {
-    return (new Array(n * 2 - number.toString().length + 1)).join("0") + number;
+var padLeft = function (string, chars) {
+    return Array(chars - string.length + 1).join("0") + string;
 };
 
 var setupInputTypes = function () {
@@ -48,27 +58,34 @@ var setupInputTypes = function () {
             }
 
             var padding = parseInt(type.slice(expected.length)) / 8;
-            return padLeft(value, padding);
+            if (typeof value === "number")
+                value = value.toString(16);
+            else if (value.indexOf('0x') === 0)
+                value = value.substr(2);
+            else
+                value = (+value).toString(16);
+            return padLeft(value, padding * 2);
         };
     };
 
     var namedType = function (name, padding, formatter) {
         return function (type, value) {
             if (type !== name) {
-                return false; 
+                return false;
             }
 
-            return padLeft(formatter ? value : formatter(value), padding);
+            return padLeft(formatter ? formatter(value) : value, padding * 2);
         };
     };
 
     var formatBool = function (value) {
-        return value ? '1' : '0';
+        return value ? '0x1' : '0x0';
     };
 
     return [
         prefixedType('uint'),
         prefixedType('int'),
+        prefixedType('hash'),
         namedType('address', 20),
         namedType('bool', 1, formatBool),
     ];
@@ -79,21 +96,18 @@ var inputTypes = setupInputTypes();
 var toAbiInput = function (json, methodName, params) {
     var bytes = "";
     var index = findMethodIndex(json, methodName);
-    
+
     if (index === -1) {
         return;
     }
 
-    // it needs to be checked in WebThreeStubServer 
-    // something wrong might be with this additional zero
-    bytes = bytes + index + 'x' + '0';
+    bytes = "0x" + padLeft(index.toString(16), 2);
     var method = json[index];
-    
+
     for (var i = 0; i < method.inputs.length; i++) {
         var found = false;
         for (var j = 0; j < inputTypes.length && !found; j++) {
-            var val = parseInt(params[i]).toString(16);
-            found = inputTypes[j](method.inputs[i].type, val);
+            found = inputTypes[j](method.inputs[i].type, params[i]);
         }
         if (!found) {
             console.error('unsupported json type: ' + method.inputs[i].type);
@@ -110,7 +124,7 @@ var setupOutputTypes = function () {
             if (type.indexOf(expected) !== 0) {
                 return -1;
             }
-            
+
             var padding = parseInt(type.slice(expected.length)) / 8;
             return padding * 2;
         };
@@ -118,12 +132,16 @@ var setupOutputTypes = function () {
 
     var namedType = function (name, padding) {
         return function (type) {
-            return name === type ? padding * 2: -1;
+            return name === type ? padding * 2 : -1;
         };
     };
 
     var formatInt = function (value) {
-        return parseInt(value, 16);
+        return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);
+    };
+
+    var formatHash = function (value) {
+        return "0x" + value;
     };
 
     var formatBool = function (value) {
@@ -133,6 +151,7 @@ var setupOutputTypes = function () {
     return [
     { padding: prefixedType('uint'), format: formatInt },
     { padding: prefixedType('int'), format: formatInt },
+    { padding: prefixedType('hash'), format: formatHash },
     { padding: namedType('address', 20) },
     { padding: namedType('bool', 1), format: formatBool }
     ];
@@ -146,7 +165,7 @@ var fromAbiOutput = function (json, methodName, output) {
     if (index === -1) {
         return;
     }
-    
+
     output = output.slice(2);
 
     var result = [];
@@ -163,7 +182,7 @@ var fromAbiOutput = function (json, methodName, output) {
         }
         var res = output.slice(0, padding);
         var formatter = outputTypes[j - 1].format;
-        result.push(formatter ? formatter(res): res);
+        result.push(formatter ? formatter(res) : ("0x" + res));
         output = output.slice(padding);
     }
 
@@ -197,4 +216,3 @@ module.exports = {
     inputParser: inputParser,
     outputParser: outputParser
 };
-
diff --git a/lib/autoprovider.js b/lib/autoprovider.js
index 735f56349d0dcd7e121a4818145cb844a075bd1e..bfbc3ab6e1ef3d983f0f7c12c400d0ddb4d67a4e 100644
--- a/lib/autoprovider.js
+++ b/lib/autoprovider.js
@@ -26,10 +26,13 @@
  * if not tries to connect over websockets
  * if it fails, it uses HttpRpcProvider
  */
-if (process.env.NODE_ENV !== 'build') {
+
+// TODO: work out which of the following two lines it is supposed to be...
+//if (process.env.NODE_ENV !== 'build') {
+if ("build" !== 'build') {/*
     var WebSocket = require('ws'); // jshint ignore:line
     var web3 = require('./main.js'); // jshint ignore:line
-}
+*/}
 
 var AutoProvider = function (userOptions) {
     if (web3.haveProvider()) {
diff --git a/lib/contract.js b/lib/contract.js
index 10ceaf8694cbb81515fa92f3b6f6e5ed1df21e4d..17b077484bae50237848aa5754de35eef07a7c34 100644
--- a/lib/contract.js
+++ b/lib/contract.js
@@ -20,9 +20,11 @@
  * @date 2014
  */
 
-if (process.env.NODE_ENV !== 'build') {
+// TODO: work out which of the following two lines it is supposed to be...
+//if (process.env.NODE_ENV !== 'build') {
+if ("build" !== 'build') {/*
     var web3 = require('./web3'); // jshint ignore:line
-}
+*/}
 var abi = require('./abi');
 
 var contract = function (address, desc) {
@@ -56,7 +58,7 @@ var contract = function (address, desc) {
             };
         };
     });
-         
+
     return contract;
 };
 
diff --git a/lib/httprpc.js b/lib/httprpc.js
index 8141a6bae9fc0a35c241511f35effdc8ea178a63..ee6b5c30705f3391a91b64f1450f4a9b50fb71dc 100644
--- a/lib/httprpc.js
+++ b/lib/httprpc.js
@@ -21,9 +21,11 @@
  * @date 2014
  */
 
-if (process.env.NODE_ENV !== "build") {
+// TODO: work out which of the following two lines it is supposed to be...
+//if (process.env.NODE_ENV !== 'build') {
+if ("build" !== "build") {/*
     var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
-}
+*/}
 
 var HttpRpcProvider = function (host) {
     this.handlers = [];
diff --git a/lib/main.js b/lib/main.js
index 697cbdbc388c60f0f70e627471d65cf3a88bc556..59c60cfa816cec77ba05d75ce32cd2f9ea342491 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -19,6 +19,7 @@
  *   Jeffrey Wilcke <jeff@ethdev.com>
  *   Marek Kotewicz <marek@ethdev.com>
  *   Marian Oancea <marian@ethdev.com>
+ *   Gav Wood <g@ethdev.com>
  * @date 2014
  */
 
@@ -61,17 +62,23 @@ function flattenPromise (obj) {
     return Promise.resolve(obj);
 }
 
+var web3Methods = function () {
+    return [
+    { name: 'sha3', call: 'web3_sha3' }
+    ];
+};
+
 var ethMethods = function () {
     var blockCall = function (args) {
         return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber";
     };
 
     var transactionCall = function (args) {
-        return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber';   
+        return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber';
     };
 
     var uncleCall = function (args) {
-        return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber';       
+        return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber';
     };
 
     var methods = [
@@ -205,19 +212,20 @@ var setupProperties = function (obj, properties) {
     });
 };
 
+// TODO: import from a dependency, don't duplicate.
+var hexToDec = function (hex) {
+    return parseInt(hex, 16).toString();
+};
+
+var decToHex = function (dec) {
+    return parseInt(dec).toString(16);
+};
+
+
 var web3 = {
     _callbacks: {},
     _events: {},
     providers: {},
-    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
@@ -237,10 +245,6 @@ var web3 = {
         return str;
     },
 
-    toDecimal: function (val) {
-        return parseInt(val, 16);
-    },
-
     fromAscii: function(str, pad) {
         pad = pad === undefined ? 32 : pad;
         var hex = this.toHex(str);
@@ -249,6 +253,33 @@ var web3 = {
         return "0x" + hex;
     },
 
+    toDecimal: function (val) {
+        return hexToDec(val.substring(2));
+    },
+
+    fromDecimal: function (val) {
+        return "0x" + decToHex(val);
+    },
+
+    toEth: function(str) {
+        var val = typeof str === "string" ? str.indexOf('0x') == 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
+        var unit = 0;
+        var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];
+        while (val > 3000 && unit < units.length - 1)
+        {
+            val /= 1000;
+            unit++;
+        }
+        var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);
+        while (true) {
+            var o = s;
+            s = s.replace(/(\d)(\d\d\d[\.\,])/, function($0, $1, $2) { return $1 + ',' + $2; });
+            if (o == s)
+                break;
+        }
+        return s + ' ' + units[unit];
+    },
+
     eth: {
         prototype: Object(), // jshint ignore:line
         watch: function (params) {
@@ -294,6 +325,7 @@ var web3 = {
     }
 };
 
+setupMethods(web3, web3Methods());
 setupMethods(web3.eth, ethMethods());
 setupProperties(web3.eth, ethProperties());
 setupMethods(web3.db, dbMethods());
@@ -460,4 +492,3 @@ function messageHandler(data) {
 }
 
 module.exports = web3;
-
diff --git a/lib/websocket.js b/lib/websocket.js
index 0c75630624b676a022d00d5bbd4a90e20634e1bf..24a0725313fb4811e4ebcb00938bcc6025aabf33 100644
--- a/lib/websocket.js
+++ b/lib/websocket.js
@@ -22,9 +22,11 @@
  * @date 2014
  */
 
-if (process.env.NODE_ENV !== "build") {
+// TODO: work out which of the following two lines it is supposed to be...
+//if (process.env.NODE_ENV !== 'build') {
+if ("build" !== "build") {/*
     var WebSocket = require('ws'); // jshint ignore:line
-}
+*/}
 
 var WebSocketProvider = function(host) {
     // onmessage handlers