فهرست منبع

updated ethereum.js

obscuren 11 سال پیش
والد
کامیت
e42517754a

+ 5 - 0
cmd/ethtest/.bowerrc

@@ -0,0 +1,5 @@
+{
+  "directory": "example/js/",
+  "cwd": "./",
+  "analytics": false
+}

+ 12 - 0
cmd/ethtest/.editorconfig

@@ -0,0 +1,12 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false

+ 18 - 0
cmd/ethtest/.gitignore

@@ -0,0 +1,18 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+#   git config --global core.excludesfile ~/.gitignore_global
+
+*.swp
+/tmp
+*/**/*un~
+*un~
+.DS_Store
+*/**/.DS_Store
+ethereum/ethereum
+ethereal/ethereal
+example/js
+node_modules
+bower_components
+npm-debug.log

+ 50 - 0
cmd/ethtest/.jshintrc

@@ -0,0 +1,50 @@
+{
+    "predef": [
+        "console",
+        "require",
+        "equal",
+        "test",
+        "testBoth",
+        "testWithDefault",
+        "raises",
+        "deepEqual",
+        "start",
+        "stop",
+        "ok",
+        "strictEqual",
+        "module",
+        "expect",
+        "reject",
+        "impl"
+    ],
+
+    "esnext": true,
+    "proto": true,
+    "node" : true,
+    "browser" : true,
+    "browserify" : true,
+
+    "boss" : true,
+    "curly": false,
+    "debug": true,
+    "devel": true,
+    "eqeqeq": true,
+    "evil": true,
+    "forin": false,
+    "immed": false,
+    "laxbreak": false,
+    "newcap": true,
+    "noarg": true,
+    "noempty": false,
+    "nonew": false,
+    "nomen": false,
+    "onevar": false,
+    "plusplus": false,
+    "regexp": false,
+    "undef": true,
+    "sub": true,
+    "strict": false,
+    "white": false,
+    "shadow": true,
+    "eqnull": true
+}

+ 9 - 0
cmd/ethtest/.npmignore

@@ -0,0 +1,9 @@
+example/js
+node_modules
+test
+.gitignore
+.editorconfig
+.travis.yml
+.npmignore
+component.json
+testling.html

+ 11 - 0
cmd/ethtest/.travis.yml

@@ -0,0 +1,11 @@
+language: node_js
+node_js:
+  - "0.11"
+  - "0.10"
+before_script:
+  - npm install
+  - npm install jshint
+script:
+   - "jshint *.js lib"
+after_script:
+  - npm run-script gulp

+ 14 - 0
cmd/ethtest/LICENSE

@@ -0,0 +1,14 @@
+This file is part of ethereum.js.
+
+ethereum.js is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+ethereum.js is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with ethereum.js.  If not, see <http://www.gnu.org/licenses/>.

+ 79 - 0
cmd/ethtest/README.md

@@ -0,0 +1,79 @@
+# Ethereum JavaScript API
+
+This is the Ethereum compatible JavaScript API using `Promise`s
+which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js
+
+[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url]
+
+<!-- [![browser support](https://ci.testling.com/ethereum/ethereum.js.png)](https://ci.testling.com/ethereum/ethereum.js) -->
+
+## Installation
+
+### Node.js
+
+    npm install ethereum.js
+
+### For browser
+Bower
+
+	bower install ethereum.js
+
+Component
+
+	component install ethereum/ethereum.js
+
+* Include `ethereum.min.js` in your html file.
+* Include [es6-promise](https://github.com/jakearchibald/es6-promise) or another ES6-Shim if your browser doesn't support ECMAScript 6.
+
+## Usage
+Require the library:
+
+	var web3 = require('web3');
+
+Set a provider (QtProvider, WebSocketProvider, HttpRpcProvider)
+
+	var web3.setProvider(new web3.providers.WebSocketProvider('ws://localhost:40404/eth'));
+
+There you go, now you can use it:
+
+```
+web3.eth.coinbase.then(function(result){
+  console.log(result);
+  return web3.eth.balanceAt(result);
+}).then(function(balance){
+  console.log(web3.toDecimal(balance));
+}).catch(function(err){
+  console.log(err);
+});
+```
+
+
+For another example see `example/index.html`.
+
+## Building
+
+* `gulp build`
+
+
+### Testing
+
+**Please note this repo is in it's early stage.**
+
+If you'd like to run a WebSocket ethereum node check out
+[go-ethereum](https://github.com/ethereum/go-ethereum).
+
+To install ethereum and spawn a node:
+
+```
+go get github.com/ethereum/go-ethereum/ethereum
+ethereum -ws -loglevel=4
+```
+
+[npm-image]: https://badge.fury.io/js/ethereum.js.png
+[npm-url]: https://npmjs.org/package/ethereum.js
+[travis-image]: https://travis-ci.org/ethereum/ethereum.js.svg
+[travis-url]: https://travis-ci.org/ethereum/ethereum.js
+[dep-image]: https://david-dm.org/ethereum/ethereum.js.svg
+[dep-url]: https://david-dm.org/ethereum/ethereum.js
+[dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg
+[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies

+ 51 - 0
cmd/ethtest/bower.json

@@ -0,0 +1,51 @@
+{
+  "name": "ethereum.js",
+  "namespace": "ethereum",
+  "version": "0.0.3",
+  "description": "Ethereum Compatible JavaScript API",
+  "main": ["./dist/ethereum.js", "./dist/ethereum.min.js"],
+  "dependencies": {
+    "es6-promise": "#master"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/ethereum/ethereum.js.git"
+  },
+  "homepage": "https://github.com/ethereum/ethereum.js",
+  "bugs": {
+    "url": "https://github.com/ethereum/ethereum.js/issues"
+  },
+  "keywords": [
+    "ethereum",
+    "javascript",
+    "API"
+  ],
+  "authors": [
+    {
+      "name": "Marek Kotewicz",
+      "email": "marek@ethdev.com",
+      "homepage": "https://github.com/debris"
+    },
+    {
+      "name": "Marian Oancea",
+      "email": "marian@ethdev.com",
+      "homepage": "https://github.com/cubedro"
+    }
+  ],
+  "license": "LGPL-3.0",
+  "ignore": [
+    "example",
+    "lib",
+    "node_modules",
+    "package.json",
+    ".bowerrc",
+    ".editorconfig",
+    ".gitignore",
+    ".jshintrc",
+    ".npmignore",
+    ".travis.yml",
+    "gulpfile.js",
+    "index.js",
+    "**/*.txt"
+  ]
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
cmd/ethtest/dist/ethereum.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 19 - 0
cmd/ethtest/dist/ethereum.js.map


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
cmd/ethtest/dist/ethereum.min.js


+ 75 - 0
cmd/ethtest/example/contract.html

@@ -0,0 +1,75 @@
+<!doctype>
+<html>
+
+<head>
+<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
+<script type="text/javascript" src="../dist/ethereum.js"></script>
+<script type="text/javascript">
+
+    var web3 = require('web3');
+    web3.setProvider(new web3.providers.AutoProvider());
+
+    // solidity source code
+    var source = "" + 
+    "contract test {\n" +
+    "   function multiply(uint a) returns(uint d) {\n" +
+    "       return a * 7;\n" +
+    "   }\n" +
+    "}\n";
+
+    // contract description, this will be autogenerated somehow
+    var desc =  [{
+        "name": "multiply",
+        "inputs": [
+        {
+            "name": "a",
+            "type": "uint256"
+        }
+        ],
+        "outputs": [
+        {
+            "name": "d",
+            "type": "uint256"
+        }
+        ]
+    }];
+
+    var contract;
+
+    function createExampleContract() {
+        // hide create button
+        document.getElementById('create').style.visibility = 'hidden'; 
+        document.getElementById('source').innerText = source;
+
+        // create contract
+        web3.eth.transact({code: web3.eth.solidity(source)}).then(function (address) {
+            contract = web3.contract(address, desc);
+            document.getElementById('call').style.visibility = 'visible';
+        });
+    }
+
+    function callExampleContract() {
+        // this should be generated by ethereum
+        var param = document.getElementById('value').value;
+
+        // call the contract
+        contract.multiply(param).call().then(function(res) {
+            document.getElementById('result').innerText = res[0];
+        });
+    }
+
+</script>
+</head>
+<body>
+    <h1>contract</h1>
+    <div id="source"></div> 
+    <div id='create'>
+        <button type="button" onClick="createExampleContract();">create example contract</button>
+    </div>
+    <div id='call' style='visibility: hidden;'>
+        <input type="number" id="value" onkeyup='callExampleContract()'></input>
+    </div>
+    <div id="result"></div>
+</body>
+</html>
+

+ 41 - 0
cmd/ethtest/example/index.html

@@ -0,0 +1,41 @@
+<!doctype>
+<html>
+
+<head>
+<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
+<script type="text/javascript" src="../dist/ethereum.js"></script>
+<script type="text/javascript">
+   
+    var web3 = require('web3');
+    web3.setProvider(new web3.providers.AutoProvider());
+
+    function watchBalance() {
+        var coinbase = web3.eth.coinbase;
+        var originalBalance = 0;
+
+        web3.eth.balanceAt(coinbase).then(function (balance) {
+            originalBalance = web3.toDecimal(balance);
+            document.getElementById('original').innerText = 'original balance: ' + originalBalance + '    watching...';
+        });
+
+        web3.eth.watch({altered: coinbase}).changed(function() {
+            web3.eth.balanceAt(coinbase).then(function (balance) {
+                var currentBalance = web3.toDecimal(balance);
+                document.getElementById("current").innerText = 'current: ' + currentBalance;
+                document.getElementById("diff").innerText = 'diff:    ' + (currentBalance - originalBalance);
+            });
+        });
+    }
+
+</script>
+</head>
+<body>
+    <h1>coinbase balance</h1>
+    <button type="button" onClick="watchBalance();">watch balance</button>
+    <div></div>
+    <div id="original"></div>
+    <div id="current"></div>
+    <div id="diff"></div>
+</body>
+</html>
+

+ 16 - 0
cmd/ethtest/example/node-app.js

@@ -0,0 +1,16 @@
+#!/usr/bin/env node
+
+require('es6-promise').polyfill();
+
+var web3 = require("../index.js");
+
+web3.setProvider(new web3.providers.HttpRpcProvider('http://localhost:8080'));
+
+web3.eth.coinbase.then(function(result){
+  console.log(result);
+  return web3.eth.balanceAt(result);
+}).then(function(balance){
+  console.log(web3.toDecimal(balance));
+}).catch(function(err){
+  console.log(err);
+});

+ 123 - 0
cmd/ethtest/gulpfile.js

@@ -0,0 +1,123 @@
+#!/usr/bin/env node
+
+'use strict';
+
+var path = require('path');
+
+var del = require('del');
+var gulp = require('gulp');
+var browserify = require('browserify');
+var jshint = require('gulp-jshint');
+var uglify = require('gulp-uglify');
+var rename = require('gulp-rename');
+var envify = require('envify/custom');
+var unreach = require('unreachable-branch-transform');
+var source = require('vinyl-source-stream');
+var exorcist = require('exorcist');
+var bower = require('bower');
+
+var DEST = './dist/';
+
+var build = function(src, dst) {
+  return browserify({
+      debug: true,
+      insert_global_vars: false,
+      detectGlobals: false,
+      bundleExternal: false
+    })
+    .require('./' + src + '.js', {expose: 'web3'})
+    .add('./' + src + '.js')
+    .transform('envify', {
+      NODE_ENV: 'build'
+    })
+    .transform('unreachable-branch-transform')
+    .transform('uglifyify', {
+      mangle: false,
+      compress: {
+        dead_code: false,
+        conditionals: true,
+        unused: false,
+        hoist_funs: true,
+        hoist_vars: true,
+        negate_iife: false
+      },
+      beautify: true,
+      warnings: true
+    })
+    .bundle()
+    .pipe(exorcist(path.join( DEST, dst + '.js.map')))
+    .pipe(source(dst + '.js'))
+    .pipe(gulp.dest( DEST ));
+};
+
+var buildDev = function(src, dst) {
+  return browserify({
+      debug: true,
+      insert_global_vars: false,
+      detectGlobals: false,
+      bundleExternal: false
+    })
+    .require('./' + src + '.js', {expose: 'web3'})
+    .add('./' + src + '.js')
+    .transform('envify', {
+      NODE_ENV: 'build'
+    })
+    .transform('unreachable-branch-transform')
+    .bundle()
+    .pipe(exorcist(path.join( DEST, dst + '.js.map')))
+    .pipe(source(dst + '.js'))
+    .pipe(gulp.dest( DEST ));
+};
+
+var uglifyFile = function(file) {
+  return gulp.src( DEST + file + '.js')
+    .pipe(uglify())
+    .pipe(rename(file + '.min.js'))
+    .pipe(gulp.dest( DEST ));
+};
+
+gulp.task('bower', function(cb){
+  bower.commands.install().on('end', function (installed){
+    console.log(installed);
+    cb();
+  });
+});
+
+gulp.task('lint', function(){
+  return gulp.src(['./*.js', './lib/*.js'])
+    .pipe(jshint())
+    .pipe(jshint.reporter('default'));
+});
+
+gulp.task('clean', ['lint'], function(cb) {
+  del([ DEST ], cb);
+});
+
+gulp.task('build', ['clean'], function () {
+    return build('index', 'ethereum');
+});
+
+gulp.task('buildQt', ['clean'], function () {
+    return build('index_qt', 'ethereum');
+});
+
+gulp.task('buildDev', ['clean'], function () {
+    return buildDev('index', 'ethereum');
+});
+
+gulp.task('uglify', ['build'], function(){
+    return uglifyFile('ethereum');
+});
+
+gulp.task('uglifyQt', ['buildQt'], function () {
+    return uglifyFile('ethereum');
+});
+
+gulp.task('watch', function() {
+  gulp.watch(['./lib/*.js'], ['lint', 'prepare', 'build']);
+});
+
+gulp.task('default', ['bower', 'lint', 'build', 'uglify']);
+gulp.task('qt', ['bower', 'lint', 'buildQt', 'uglifyQt']);
+gulp.task('dev', ['bower', 'lint', 'buildDev']);
+

+ 8 - 0
cmd/ethtest/index.js

@@ -0,0 +1,8 @@
+var web3 = require('./lib/main');
+web3.providers.WebSocketProvider = require('./lib/websocket');
+web3.providers.HttpRpcProvider = require('./lib/httprpc');
+web3.providers.QtProvider = require('./lib/qt');
+web3.providers.AutoProvider = require('./lib/autoprovider');
+web3.contract = require('./lib/contract');
+
+module.exports = web3;

+ 5 - 0
cmd/ethtest/index_qt.js

@@ -0,0 +1,5 @@
+var web3 = require('./lib/main');
+web3.providers.QtProvider = require('./lib/qt');
+web3.contract = require('./lib/contract');
+
+module.exports = web3;

+ 218 - 0
cmd/ethtest/lib/abi.js

@@ -0,0 +1,218 @@
+/*
+    This file is part of ethereum.js.
+
+    ethereum.js is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    ethereum.js is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with ethereum.js.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @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;
+    for (; i < array.length && !end; i++) {
+        end = callback(array[i]);
+    }
+    return end ? i - 1 : -1;
+};
+
+var findMethodIndex = function (json, methodName) {
+    return findIndex(json, function (method) {
+        return method.name === methodName;
+    });
+};
+
+var padLeft = function (string, chars) {
+    return Array(chars - string.length + 1).join("0") + string;
+};
+
+var setupInputTypes = function () {
+    var prefixedType = function (prefix) {
+        return function (type, value) {
+            var expected = prefix;
+            if (type.indexOf(expected) !== 0) {
+                return false;
+            }
+
+            var padding = parseInt(type.slice(expected.length)) / 8;
+            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 padLeft(formatter ? formatter(value) : value, padding * 2);
+        };
+    };
+
+    var formatBool = function (value) {
+        return value ? '0x1' : '0x0';
+    };
+
+    return [
+        prefixedType('uint'),
+        prefixedType('int'),
+        prefixedType('hash'),
+        namedType('address', 20),
+        namedType('bool', 1, formatBool),
+    ];
+};
+
+var inputTypes = setupInputTypes();
+
+var toAbiInput = function (json, methodName, params) {
+    var bytes = "";
+    var index = findMethodIndex(json, methodName);
+
+    if (index === -1) {
+        return;
+    }
+
+    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++) {
+            found = inputTypes[j](method.inputs[i].type, params[i]);
+        }
+        if (!found) {
+            console.error('unsupported json type: ' + method.inputs[i].type);
+        }
+        bytes += found;
+    }
+    return bytes;
+};
+
+var setupOutputTypes = function () {
+    var prefixedType = function (prefix) {
+        return function (type) {
+            var expected = prefix;
+            if (type.indexOf(expected) !== 0) {
+                return -1;
+            }
+
+            var padding = parseInt(type.slice(expected.length)) / 8;
+            return padding * 2;
+        };
+    };
+
+    var namedType = function (name, padding) {
+        return function (type) {
+            return name === type ? padding * 2 : -1;
+        };
+    };
+
+    var formatInt = function (value) {
+        return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);
+    };
+
+    var formatHash = function (value) {
+        return "0x" + value;
+    };
+
+    var formatBool = function (value) {
+        return value === '1' ? true : false;
+    };
+
+    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 }
+    ];
+};
+
+var outputTypes = setupOutputTypes();
+
+var fromAbiOutput = function (json, methodName, output) {
+    var index = findMethodIndex(json, methodName);
+
+    if (index === -1) {
+        return;
+    }
+
+    output = output.slice(2);
+
+    var result = [];
+    var method = json[index];
+    for (var i = 0; i < method.outputs.length; i++) {
+        var padding = -1;
+        for (var j = 0; j < outputTypes.length && padding === -1; j++) {
+            padding = outputTypes[j].padding(method.outputs[i].type);
+        }
+
+        if (padding === -1) {
+            // not found output parsing
+            continue;
+        }
+        var res = output.slice(0, padding);
+        var formatter = outputTypes[j - 1].format;
+        result.push(formatter ? formatter(res) : ("0x" + res));
+        output = output.slice(padding);
+    }
+
+    return result;
+};
+
+var inputParser = function (json) {
+    var parser = {};
+    json.forEach(function (method) {
+        parser[method.name] = function () {
+            var params = Array.prototype.slice.call(arguments);
+            return toAbiInput(json, method.name, params);
+        };
+    });
+
+    return parser;
+};
+
+var outputParser = function (json) {
+    var parser = {};
+    json.forEach(function (method) {
+        parser[method.name] = function (output) {
+            return fromAbiOutput(json, method.name, output);
+        };
+    });
+
+    return parser;
+};
+
+module.exports = {
+    inputParser: inputParser,
+    outputParser: outputParser
+};

+ 103 - 0
cmd/ethtest/lib/autoprovider.js

@@ -0,0 +1,103 @@
+/*
+    This file is part of ethereum.js.
+
+    ethereum.js is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    ethereum.js is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with ethereum.js.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file autoprovider.js
+ * @authors:
+ *   Marek Kotewicz <marek@ethdev.com>
+ *   Marian Oancea <marian@ethdev.com>
+ * @date 2014
+ */
+
+/*
+ * @brief if qt object is available, uses QtProvider,
+ * if not tries to connect over websockets
+ * if it fails, it uses HttpRpcProvider
+ */
+
+// 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()) {
+        return;
+    }
+
+    // before we determine what provider we are, we have to cache request
+    this.sendQueue = [];
+    this.onmessageQueue = [];
+
+    if (navigator.qt) {
+        this.provider = new web3.providers.QtProvider();
+        return;
+    }
+
+    userOptions = userOptions || {};
+    var options = {
+        httprpc: userOptions.httprpc || 'http://localhost:8080',
+        websockets: userOptions.websockets || 'ws://localhost:40404/eth'
+    };
+
+    var self = this;
+    var closeWithSuccess = function (success) {
+        ws.close();
+        if (success) {
+            self.provider = new web3.providers.WebSocketProvider(options.websockets);
+        } else {
+            self.provider = new web3.providers.HttpRpcProvider(options.httprpc);
+            self.poll = self.provider.poll.bind(self.provider);
+        }
+        self.sendQueue.forEach(function (payload) {
+            self.provider(payload);
+        });
+        self.onmessageQueue.forEach(function (handler) {
+            self.provider.onmessage = handler;
+        });
+    };
+
+    var ws = new WebSocket(options.websockets);
+
+    ws.onopen = function() {
+        closeWithSuccess(true);
+    };
+
+    ws.onerror = function() {
+        closeWithSuccess(false);
+    };
+};
+
+AutoProvider.prototype.send = function (payload) {
+    if (this.provider) {
+        this.provider.send(payload);
+        return;
+    }
+    this.sendQueue.push(payload);
+};
+
+Object.defineProperty(AutoProvider.prototype, 'onmessage', {
+    set: function (handler) {
+        if (this.provider) {
+            this.provider.onmessage = handler;
+            return;
+        }
+        this.onmessageQueue.push(handler);
+    }
+});
+
+module.exports = AutoProvider;

+ 65 - 0
cmd/ethtest/lib/contract.js

@@ -0,0 +1,65 @@
+/*
+    This file is part of ethereum.js.
+
+    ethereum.js is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    ethereum.js is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with ethereum.js.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file contract.js
+ * @authors:
+ *   Marek Kotewicz <marek@ethdev.com>
+ * @date 2014
+ */
+
+// 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) {
+    var inputParser = abi.inputParser(desc);
+    var outputParser = abi.outputParser(desc);
+
+    var contract = {};
+
+    desc.forEach(function (method) {
+        contract[method.name] = function () {
+            var params = Array.prototype.slice.call(arguments);
+            var parsed = inputParser[method.name].apply(null, params);
+
+            var onSuccess = function (result) {
+                return outputParser[method.name](result);
+            };
+
+            return {
+                call: function (extra) {
+                    extra = extra || {};
+                    extra.to = address;
+                    extra.data = parsed;
+                    return web3.eth.call(extra).then(onSuccess);
+                },
+                transact: function (extra) {
+                    extra = extra || {};
+                    extra.to = address;
+                    extra.data = parsed;
+                    return web3.eth.transact(extra).then(onSuccess);
+                }
+            };
+        };
+    });
+
+    return contract;
+};
+
+module.exports = contract;

+ 95 - 0
cmd/ethtest/lib/httprpc.js

@@ -0,0 +1,95 @@
+/*
+    This file is part of ethereum.js.
+
+    ethereum.js is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    ethereum.js is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with ethereum.js.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file httprpc.js
+ * @authors:
+ *   Marek Kotewicz <marek@ethdev.com>
+ *   Marian Oancea <marian@ethdev.com>
+ * @date 2014
+ */
+
+// 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 = [];
+    this.host = host;
+};
+
+function formatJsonRpcObject(object) {
+    return {
+        jsonrpc: '2.0',
+        method: object.call,
+        params: object.args,
+        id: object._id
+    };
+}
+
+function formatJsonRpcMessage(message) {
+    var object = JSON.parse(message);
+
+    return {
+        _id: object.id,
+        data: object.result,
+        error: object.error
+    };
+}
+
+HttpRpcProvider.prototype.sendRequest = function (payload, cb) {
+    var data = formatJsonRpcObject(payload);
+
+    var request = new XMLHttpRequest();
+    request.open("POST", this.host, true);
+    request.send(JSON.stringify(data));
+    request.onreadystatechange = function () {
+        if (request.readyState === 4 && cb) {
+            cb(request);
+        }
+    };
+};
+
+HttpRpcProvider.prototype.send = function (payload) {
+    var self = this;
+    this.sendRequest(payload, function (request) {
+        self.handlers.forEach(function (handler) {
+            handler.call(self, formatJsonRpcMessage(request.responseText));
+        });
+    });
+};
+
+HttpRpcProvider.prototype.poll = function (payload, id) {
+    var self = this;
+    this.sendRequest(payload, function (request) {
+        var parsed = JSON.parse(request.responseText);
+        if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) {
+            return;
+        }
+        self.handlers.forEach(function (handler) {
+            handler.call(self, {_event: payload.call, _id: id, data: parsed.result});
+        });
+    });
+};
+
+Object.defineProperty(HttpRpcProvider.prototype, "onmessage", {
+    set: function (handler) {
+        this.handlers.push(handler);
+    }
+});
+
+module.exports = HttpRpcProvider;

+ 494 - 0
cmd/ethtest/lib/main.js

@@ -0,0 +1,494 @@
+/*
+    This file is part of ethereum.js.
+
+    ethereum.js is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    ethereum.js is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with ethereum.js.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file main.js
+ * @authors:
+ *   Jeffrey Wilcke <jeff@ethdev.com>
+ *   Marek Kotewicz <marek@ethdev.com>
+ *   Marian Oancea <marian@ethdev.com>
+ *   Gav Wood <g@ethdev.com>
+ * @date 2014
+ */
+
+function flattenPromise (obj) {
+    if (obj instanceof Promise) {
+        return Promise.resolve(obj);
+    }
+
+    if (obj instanceof Array) {
+        return new Promise(function (resolve) {
+            var promises = obj.map(function (o) {
+                return flattenPromise(o);
+            });
+
+            return Promise.all(promises).then(function (res) {
+                for (var i = 0; i < obj.length; i++) {
+                    obj[i] = res[i];
+                }
+                resolve(obj);
+            });
+        });
+    }
+
+    if (obj instanceof Object) {
+        return new Promise(function (resolve) {
+            var keys = Object.keys(obj);
+            var promises = keys.map(function (key) {
+                return flattenPromise(obj[key]);
+            });
+
+            return Promise.all(promises).then(function (res) {
+                for (var i = 0; i < keys.length; i++) {
+                    obj[keys[i]] = res[i];
+                }
+                resolve(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';
+    };
+
+    var uncleCall = function (args) {
+        return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber';
+    };
+
+    var methods = [
+    { name: 'balanceAt', call: 'eth_balanceAt' },
+    { name: 'stateAt', call: 'eth_stateAt' },
+    { name: 'storageAt', call: 'eth_storageAt' },
+    { name: 'countAt', call: 'eth_countAt'},
+    { name: 'codeAt', call: 'eth_codeAt' },
+    { name: 'transact', call: 'eth_transact' },
+    { name: 'call', call: 'eth_call' },
+    { name: 'block', call: blockCall },
+    { name: 'transaction', call: transactionCall },
+    { name: 'uncle', call: uncleCall },
+    { name: 'compilers', call: 'eth_compilers' },
+    { name: 'lll', call: 'eth_lll' },
+    { name: 'solidity', call: 'eth_solidity' },
+    { name: 'serpent', call: 'eth_serpent' },
+    { name: 'logs', call: 'eth_logs' }
+    ];
+    return methods;
+};
+
+var ethProperties = function () {
+    return [
+    { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },
+    { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },
+    { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },
+    { name: 'gasPrice', getter: 'eth_gasPrice' },
+    { name: 'account', getter: 'eth_account' },
+    { name: 'accounts', getter: 'eth_accounts' },
+    { name: 'peerCount', getter: 'eth_peerCount' },
+    { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },
+    { name: 'number', getter: 'eth_number'}
+    ];
+};
+
+var dbMethods = function () {
+    return [
+    { name: 'put', call: 'db_put' },
+    { name: 'get', call: 'db_get' },
+    { name: 'putString', call: 'db_putString' },
+    { name: 'getString', call: 'db_getString' }
+    ];
+};
+
+var shhMethods = function () {
+    return [
+    { name: 'post', call: 'shh_post' },
+    { name: 'newIdentity', call: 'shh_newIdentity' },
+    { name: 'haveIdentity', call: 'shh_haveIdentity' },
+    { name: 'newGroup', call: 'shh_newGroup' },
+    { name: 'addToGroup', call: 'shh_addToGroup' }
+    ];
+};
+
+var ethWatchMethods = function () {
+    var newFilter = function (args) {
+        return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';
+    };
+
+    return [
+    { name: 'newFilter', call: newFilter },
+    { name: 'uninstallFilter', call: 'eth_uninstallFilter' },
+    { name: 'getMessages', call: 'eth_filterLogs' }
+    ];
+};
+
+var shhWatchMethods = function () {
+    return [
+    { name: 'newFilter', call: 'shh_newFilter' },
+    { name: 'uninstallFilter', call: 'shh_uninstallFilter' },
+    { name: 'getMessage', call: 'shh_getMessages' }
+    ];
+};
+
+var setupMethods = function (obj, methods) {
+    methods.forEach(function (method) {
+        obj[method.name] = function () {
+            return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {
+                var call = typeof method.call === "function" ? method.call(args) : method.call;
+                return {call: call, args: args};
+            }).then(function (request) {
+                return new Promise(function (resolve, reject) {
+                    web3.provider.send(request, function (err, result) {
+                        if (!err) {
+                            resolve(result);
+                            return;
+                        }
+                        reject(err);
+                    });
+                });
+            }).catch(function(err) {
+                console.error(err);
+            });
+        };
+    });
+};
+
+var setupProperties = function (obj, properties) {
+    properties.forEach(function (property) {
+        var proto = {};
+        proto.get = function () {
+            return new Promise(function(resolve, reject) {
+                web3.provider.send({call: property.getter}, function(err, result) {
+                    if (!err) {
+                        resolve(result);
+                        return;
+                    }
+                    reject(err);
+                });
+            });
+        };
+        if (property.setter) {
+            proto.set = function (val) {
+                return flattenPromise([val]).then(function (args) {
+                    return new Promise(function (resolve) {
+                        web3.provider.send({call: property.setter, args: args}, function (err, result) {
+                            if (!err) {
+                                resolve(result);
+                                return;
+                            }
+                            reject(err);
+                        });
+                    });
+                }).catch(function (err) {
+                    console.error(err);
+                });
+            };
+        }
+        Object.defineProperty(obj, property.name, proto);
+    });
+};
+
+// 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: {},
+
+    toAscii: function(hex) {
+        // Find termination
+        var str = "";
+        var i = 0, l = hex.length;
+        if (hex.substring(0, 2) === '0x')
+            i = 2;
+        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) {
+        pad = pad === undefined ? 32 : pad;
+        var hex = this.toHex(str);
+        while(hex.length < pad*2)
+            hex += "00";
+        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) {
+            return new Filter(params, ethWatch);
+        }
+    },
+
+    db: {
+        prototype: Object() // jshint ignore:line
+    },
+
+    shh: {
+        prototype: Object(), // jshint ignore:line
+        watch: function (params) {
+            return new Filter(params, shhWatch);
+        }
+    },
+
+    on: function(event, id, cb) {
+        if(web3._events[event] === undefined) {
+            web3._events[event] = {};
+        }
+
+        web3._events[event][id] = cb;
+        return this;
+    },
+
+    off: function(event, id) {
+        if(web3._events[event] !== undefined) {
+            delete web3._events[event][id];
+        }
+
+        return this;
+    },
+
+    trigger: function(event, id, data) {
+        var callbacks = web3._events[event];
+        if (!callbacks || !callbacks[id]) {
+            return;
+        }
+        var cb = callbacks[id];
+        cb(data);
+    }
+};
+
+setupMethods(web3, web3Methods());
+setupMethods(web3.eth, ethMethods());
+setupProperties(web3.eth, ethProperties());
+setupMethods(web3.db, dbMethods());
+setupMethods(web3.shh, shhMethods());
+
+var ethWatch = {
+    changed: 'eth_changed'
+};
+setupMethods(ethWatch, ethWatchMethods());
+var shhWatch = {
+    changed: 'shh_changed'
+};
+setupMethods(shhWatch, shhWatchMethods());
+
+var ProviderManager = function() {
+    this.queued = [];
+    this.polls = [];
+    this.ready = false;
+    this.provider = undefined;
+    this.id = 1;
+
+    var self = this;
+    var poll = function () {
+        if (self.provider && self.provider.poll) {
+            self.polls.forEach(function (data) {
+                data.data._id = self.id;
+                self.id++;
+                self.provider.poll(data.data, data.id);
+            });
+        }
+        setTimeout(poll, 12000);
+    };
+    poll();
+};
+
+ProviderManager.prototype.send = function(data, cb) {
+    data._id = this.id;
+    if (cb) {
+        web3._callbacks[data._id] = cb;
+    }
+
+    data.args = data.args || [];
+    this.id++;
+
+    if(this.provider !== undefined) {
+        this.provider.send(data);
+    } else {
+        console.warn("provider is not set");
+        this.queued.push(data);
+    }
+};
+
+ProviderManager.prototype.set = function(provider) {
+    if(this.provider !== undefined && this.provider.unload !== undefined) {
+        this.provider.unload();
+    }
+
+    this.provider = provider;
+    this.ready = true;
+};
+
+ProviderManager.prototype.sendQueued = function() {
+    for(var i = 0; this.queued.length; i++) {
+        // Resend
+        this.send(this.queued[i]);
+    }
+};
+
+ProviderManager.prototype.installed = function() {
+    return this.provider !== undefined;
+};
+
+ProviderManager.prototype.startPolling = function (data, pollId) {
+    if (!this.provider || !this.provider.poll) {
+        return;
+    }
+    this.polls.push({data: data, id: pollId});
+};
+
+ProviderManager.prototype.stopPolling = function (pollId) {
+    for (var i = this.polls.length; i--;) {
+        var poll = this.polls[i];
+        if (poll.id === pollId) {
+            this.polls.splice(i, 1);
+        }
+    }
+};
+
+web3.provider = new ProviderManager();
+
+web3.setProvider = function(provider) {
+    provider.onmessage = messageHandler;
+    web3.provider.set(provider);
+    web3.provider.sendQueued();
+};
+
+web3.haveProvider = function() {
+    return !!web3.provider.provider;
+};
+
+var Filter = function(options, impl) {
+    this.impl = impl;
+    this.callbacks = [];
+
+    var self = this;
+    this.promise = impl.newFilter(options);
+    this.promise.then(function (id) {
+        self.id = id;
+        web3.on(impl.changed, id, self.trigger.bind(self));
+        web3.provider.startPolling({call: impl.changed, args: [id]}, id);
+    });
+};
+
+Filter.prototype.arrived = function(callback) {
+    this.changed(callback);
+};
+
+Filter.prototype.changed = function(callback) {
+    var self = this;
+    this.promise.then(function(id) {
+        self.callbacks.push(callback);
+    });
+};
+
+Filter.prototype.trigger = function(messages) {
+    for(var i = 0; i < this.callbacks.length; i++) {
+        this.callbacks[i].call(this, messages);
+    }
+};
+
+Filter.prototype.uninstall = function() {
+    var self = this;
+    this.promise.then(function (id) {
+        self.impl.uninstallFilter(id);
+        web3.provider.stopPolling(id);
+        web3.off(impl.changed, id);
+    });
+};
+
+Filter.prototype.messages = function() {
+    var self = this;
+    return this.promise.then(function (id) {
+        return self.impl.getMessages(id);
+    });
+};
+
+Filter.prototype.logs = function () {
+    return this.messages();
+};
+
+function messageHandler(data) {
+    if(data._event !== undefined) {
+        web3.trigger(data._event, data._id, data.data);
+        return;
+    }
+
+    if(data._id) {
+        var cb = web3._callbacks[data._id];
+        if (cb) {
+            cb.call(this, data.error, data.data);
+            delete web3._callbacks[data._id];
+        }
+    }
+}
+
+module.exports = web3;

+ 45 - 0
cmd/ethtest/lib/qt.js

@@ -0,0 +1,45 @@
+/*
+    This file is part of ethereum.js.
+
+    ethereum.js is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    ethereum.js is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with ethereum.js.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file qt.js
+ * @authors:
+ *   Jeffrey Wilcke <jeff@ethdev.com>
+ *   Marek Kotewicz <marek@ethdev.com>
+ * @date 2014
+ */
+
+var QtProvider = function() {
+    this.handlers = [];
+
+    var self = this;
+    navigator.qt.onmessage = function (message) {
+        self.handlers.forEach(function (handler) {
+            handler.call(self, JSON.parse(message.data));
+        });
+    };
+};
+
+QtProvider.prototype.send = function(payload) {
+    navigator.qt.postMessage(JSON.stringify(payload));
+};
+
+Object.defineProperty(QtProvider.prototype, "onmessage", {
+    set: function(handler) {
+        this.handlers.push(handler);
+    }
+});
+
+module.exports = QtProvider;

+ 78 - 0
cmd/ethtest/lib/websocket.js

@@ -0,0 +1,78 @@
+/*
+    This file is part of ethereum.js.
+
+    ethereum.js is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    ethereum.js is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with ethereum.js.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file websocket.js
+ * @authors:
+ *   Jeffrey Wilcke <jeff@ethdev.com>
+ *   Marek Kotewicz <marek@ethdev.com>
+ *   Marian Oancea <marian@ethdev.com>
+ * @date 2014
+ */
+
+// 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
+    this.handlers = [];
+    // queue will be filled with messages if send is invoked before the ws is ready
+    this.queued = [];
+    this.ready = false;
+
+    this.ws = new WebSocket(host);
+
+    var self = this;
+    this.ws.onmessage = function(event) {
+        for(var i = 0; i < self.handlers.length; i++) {
+            self.handlers[i].call(self, JSON.parse(event.data), event);
+        }
+    };
+
+    this.ws.onopen = function() {
+        self.ready = true;
+
+        for(var i = 0; i < self.queued.length; i++) {
+            // Resend
+            self.send(self.queued[i]);
+        }
+    };
+};
+
+WebSocketProvider.prototype.send = function(payload) {
+    if(this.ready) {
+        var data = JSON.stringify(payload);
+
+        this.ws.send(data);
+    } else {
+        this.queued.push(payload);
+    }
+};
+
+WebSocketProvider.prototype.onMessage = function(handler) {
+    this.handlers.push(handler);
+};
+
+WebSocketProvider.prototype.unload = function() {
+    this.ws.close();
+};
+Object.defineProperty(WebSocketProvider.prototype, "onmessage", {
+    set: function(provider) { this.onMessage(provider); }
+});
+
+module.exports = WebSocketProvider;

+ 67 - 0
cmd/ethtest/package.json

@@ -0,0 +1,67 @@
+{
+  "name": "ethereum.js",
+  "namespace": "ethereum",
+  "version": "0.0.5",
+  "description": "Ethereum Compatible JavaScript API",
+  "main": "./index.js",
+  "directories": {
+    "lib": "./lib"
+  },
+  "dependencies": {
+    "es6-promise": "*",
+    "ws": "*",
+    "xmlhttprequest": "*"
+  },
+  "devDependencies": {
+    "bower": ">=1.3.0",
+    "browserify": ">=6.0",
+    "del": ">=0.1.1",
+    "envify": "^3.0.0",
+    "exorcist": "^0.1.6",
+    "gulp": ">=3.4.0",
+    "gulp-jshint": ">=1.5.0",
+    "gulp-rename": ">=1.2.0",
+    "gulp-uglify": ">=1.0.0",
+    "jshint": ">=2.5.0",
+    "uglifyify": "^2.6.0",
+    "unreachable-branch-transform": "^0.1.0",
+    "vinyl-source-stream": "^1.0.0"
+  },
+  "scripts": {
+    "build": "gulp",
+    "watch": "gulp watch",
+    "lint": "gulp lint"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/ethereum/ethereum.js.git"
+  },
+  "homepage": "https://github.com/ethereum/ethereum.js",
+  "bugs": {
+    "url": "https://github.com/ethereum/ethereum.js/issues"
+  },
+  "keywords": [
+    "ethereum",
+    "javascript",
+    "API"
+  ],
+  "author": "ethdev.com",
+  "authors": [
+    {
+      "name": "Jeffery Wilcke",
+      "email": "jeff@ethdev.com",
+      "url": "https://github.com/obscuren"
+    },
+    {
+      "name": "Marek Kotewicz",
+      "email": "marek@ethdev.com",
+      "url": "https://github.com/debris"
+    },
+    {
+      "name": "Marian Oancea",
+      "email": "marian@ethdev.com",
+      "url": "https://github.com/cubedro"
+    }
+  ],
+  "license": "LGPL-3.0"
+}

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است