diff --git a/.bowerrc b/.bowerrc
new file mode 100644
index 000000000..c3a8813e8
--- /dev/null
+++ b/.bowerrc
@@ -0,0 +1,5 @@
+{
+ "directory": "example/js/",
+ "cwd": "./",
+ "analytics": false
+}
\ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000..60a2751d3
--- /dev/null
+++ b/.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
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index de3a847ac..399b6dc88 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile ~/.gitignore_global
+*.swp
/tmp
*/**/*un~
*un~
@@ -11,4 +12,7 @@
*/**/.DS_Store
ethereum/ethereum
ethereal/ethereal
-
+example/js
+node_modules
+bower_components
+npm-debug.log
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 000000000..c0ec5f89d
--- /dev/null
+++ b/.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
+}
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 000000000..5bbffe4fd
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,9 @@
+example/js
+node_modules
+test
+.gitignore
+.editorconfig
+.travis.yml
+.npmignore
+component.json
+testling.html
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..148e4e797
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - "0.11"
+ - "0.10"
+before_script:
+ - npm install
+after_script:
+ - npm run-script gulp
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..0f187b873
--- /dev/null
+++ b/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 .
\ No newline at end of file
diff --git a/README.md b/README.md
index 86e2969be..865b62c6b 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,61 @@
# 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.
+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
-For an example see `index.html`.
+[![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]
+
+
+
+## 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.**
@@ -16,3 +68,12 @@ 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
\ No newline at end of file
diff --git a/bower.json b/bower.json
new file mode 100644
index 000000000..cedae9023
--- /dev/null
+++ b/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"
+ ]
+}
\ No newline at end of file
diff --git a/dist/ethereum.js b/dist/ethereum.js
new file mode 100644
index 000000000..f750cf864
--- /dev/null
+++ b/dist/ethereum.js
@@ -0,0 +1,16 @@
+require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oi&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){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,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],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},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;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){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,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],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},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;ir&&(t=e.charCodeAt(r),0!==t);r+=2)n+=String.fromCharCode(parseInt(e.substr(r,2),16));return n},toDecimal:function(e){return parseInt(e,16)},fromAscii:function(e,t){t=void 0===t?32:t;for(var n=this.toHex(e);n.length<2*t;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(e){return new a(e,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(e){return new a(e,i)}},on:function(e,t,n){return void 0===g._events[e]&&(g._events[e]={}),g._events[e][t]=n,this},off:function(e,t){return void 0!==g._events[e]&&delete g._events[e][t],this},trigger:function(e,t,n){var r,o=g._events[e];o&&o[t]&&(r=o[t])(n)}},m=g.eth;f(m,c()),v(m,u()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,d()),i={changed:"shh_changed"},f(i,p()),s=function(){var e,t;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,e=this,(t=function(){e.provider&&e.provider.poll&&e.polls.forEach(function(t){t.data._id=e.id,e.id++,e.provider.poll(t.data,t.id)}),setTimeout(t,12e3)})()},s.prototype.send=function(e,t){e._id=this.id,t&&(g._callbacks[e._id]=t),e.args=e.args||[],this.id++,void 0!==this.provider?this.provider.send(e):(console.warn("provider is not set"),this.queued.push(e))},s.prototype.set=function(e){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=e,this.ready=!0},s.prototype.sendQueued=function(){for(var e=0;this.queued.length;e++)this.send(this.queued[e])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(e,t){this.provider&&this.provider.poll&&this.polls.push({data:e,id:t})},s.prototype.stopPolling=function(e){var t,n;for(t=this.polls.length;t--;)n=this.polls[t],n.id===e&&this.polls.splice(t,1)},g.provider=new s,g.setProvider=function(e){e.onmessage=r,g.provider.set(e),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(e,t){this.impl=t,this.callbacks=[];var n=this;this.promise=t.newFilter(e),this.promise.then(function(e){n.id=e,g.on(t.changed,e,n.trigger.bind(n)),g.provider.startPolling({call:t.changed,args:[e]},e)})},a.prototype.arrived=function(e){this.changed(e)},a.prototype.changed=function(e){var t=this;this.promise.then(function(){t.callbacks.push(e)})},a.prototype.trigger=function(e){for(var t=0;t
+
+
+
+
+
+
+
+
+
+
+
+std::name_reg
+
+
+
+
+result:
+
+
+
+
diff --git a/example/node-app.js b/example/node-app.js
new file mode 100644
index 000000000..f63fa9115
--- /dev/null
+++ b/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);
+});
\ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 000000000..9e0717d8b
--- /dev/null
+++ b/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']);
+
diff --git a/httprpc.js b/httprpc.js
deleted file mode 100644
index 085b4693d..000000000
--- a/httprpc.js
+++ /dev/null
@@ -1,70 +0,0 @@
-(function () {
- 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
- };
- };
-
- 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.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);
- }
- });
-
- if (typeof(web3) !== "undefined" && web3.providers !== undefined) {
- web3.providers.HttpRpcProvider = HttpRpcProvider;
- }
-})();
-
diff --git a/index.html b/index.html
deleted file mode 100644
index 2b3f50a14..000000000
--- a/index.html
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-std::name_reg
-
-
-
-
-
-
-
diff --git a/index.js b/index.js
new file mode 100644
index 000000000..4cf36348f
--- /dev/null
+++ b/index.js
@@ -0,0 +1,7 @@
+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');
+
+module.exports = web3;
diff --git a/index_qt.js b/index_qt.js
new file mode 100644
index 000000000..df66321b0
--- /dev/null
+++ b/index_qt.js
@@ -0,0 +1,4 @@
+var web3 = require('./lib/main');
+web3.providers.QtProvider = require('./lib/qt');
+
+module.exports = web3;
diff --git a/lib/autoprovider.js b/lib/autoprovider.js
new file mode 100644
index 000000000..470861686
--- /dev/null
+++ b/lib/autoprovider.js
@@ -0,0 +1,100 @@
+/*
+ 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 .
+*/
+/** @file websocket.js
+ * @authors:
+ * Marek Kotewicz
+ * Marian Oancea
+ * @date 2014
+ */
+
+/*
+ * @brief if qt object is available, uses QtProvider,
+ * if not tries to connect over websockets
+ * if it fails, it uses HttpRpcProvider
+ */
+if (process.env.NODE_ENV !== 'build') {
+ var WebSocket = require('ws'); // jshint ignore:line
+ var web3 = require('./web3'); // 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;
diff --git a/lib/httprpc.js b/lib/httprpc.js
new file mode 100644
index 000000000..8141a6bae
--- /dev/null
+++ b/lib/httprpc.js
@@ -0,0 +1,93 @@
+/*
+ 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 .
+*/
+/** @file httprpc.js
+ * @authors:
+ * Marek Kotewicz
+ * Marian Oancea
+ * @date 2014
+ */
+
+if (process.env.NODE_ENV !== "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;
diff --git a/lib/main.js b/lib/main.js
new file mode 100644
index 000000000..c3ed22f8b
--- /dev/null
+++ b/lib/main.js
@@ -0,0 +1,456 @@
+/*
+ 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 .
+*/
+/** @file main.js
+ * @authors:
+ * Jeffrey Wilcke
+ * Marek Kotewicz
+ * Marian Oancea
+ * @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 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: '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: 'compile', call: 'eth_compile' },
+ { name: 'lll', call: 'eth_lll' }
+ ];
+ 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_getMessages' }
+ ];
+};
+
+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);
+ });
+};
+
+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
+ 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;
+ },
+
+ toDecimal: function (val) {
+ return parseInt(val, 16);
+ },
+
+ fromAscii: function(str, pad) {
+ pad = pad === undefined ? 32 : pad;
+ var hex = this.toHex(str);
+ while(hex.length < pad*2)
+ hex += "00";
+ return "0x" + hex;
+ },
+
+ 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);
+ }
+};
+
+var eth = web3.eth;
+setupMethods(eth, ethMethods());
+setupProperties(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);
+ });
+};
+
+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;
+
diff --git a/lib/qt.js b/lib/qt.js
new file mode 100644
index 000000000..f02239547
--- /dev/null
+++ b/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 .
+*/
+/** @file qt.js
+ * @authors:
+ * Jeffrey Wilcke
+ * Marek Kotewicz
+ * @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;
diff --git a/lib/websocket.js b/lib/websocket.js
new file mode 100644
index 000000000..0c7563062
--- /dev/null
+++ b/lib/websocket.js
@@ -0,0 +1,76 @@
+/*
+ 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 .
+*/
+/** @file websocket.js
+ * @authors:
+ * Jeffrey Wilcke
+ * Marek Kotewicz
+ * Marian Oancea
+ * @date 2014
+ */
+
+if (process.env.NODE_ENV !== "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;
diff --git a/main.js b/main.js
deleted file mode 100644
index 1f609220b..000000000
--- a/main.js
+++ /dev/null
@@ -1,436 +0,0 @@
-(function(window) {
- function isPromise(o) {
- return o instanceof Promise
- }
-
- 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 ethMethods = function () {
- var blockCall = function (args) {
- return typeof args[0] === "string" ? "blockByHash" : "blockByNumber";
- };
-
- var transactionCall = function (args) {
- return typeof args[0] === "string" ? 'transactionByHash' : 'transactionByNumber';
- };
-
- var uncleCall = function (args) {
- return typeof args[0] === "string" ? 'uncleByHash' : 'uncleByNumber';
- };
-
- var methods = [
- { name: 'balanceAt', call: 'balanceAt' },
- { name: 'stateAt', call: 'stateAt' },
- { name: 'countAt', call: 'countAt'},
- { name: 'codeAt', call: 'codeAt' },
- { name: 'transact', call: 'transact' },
- { name: 'call', call: 'call' },
- { name: 'block', call: blockCall },
- { name: 'transaction', call: transactionCall },
- { name: 'uncle', call: uncleCall },
- { name: 'compile', call: 'compile' }
- ];
- return methods;
- };
-
- var ethProperties = function () {
- return [
- { name: 'coinbase', getter: 'coinbase', setter: 'setCoinbase' },
- { name: 'listening', getter: 'listening', setter: 'setListening' },
- { name: 'mining', getter: 'mining', setter: 'setMining' },
- { name: 'gasPrice', getter: 'gasPrice' },
- { name: 'account', getter: 'account' },
- { name: 'accounts', getter: 'accounts' },
- { name: 'peerCount', getter: 'peerCount' },
- { name: 'defaultBlock', getter: 'defaultBlock', setter: 'setDefaultBlock' },
- { name: 'number', getter: 'number'}
- ];
- };
-
- var dbMethods = function () {
- return [
- { name: 'put', call: 'put' },
- { name: 'get', call: 'get' },
- { name: 'putString', call: 'putString' },
- { name: 'getString', call: 'getString' }
- ];
- };
-
- var shhMethods = function () {
- return [
- { name: 'post', call: 'post' },
- { name: 'newIdentity', call: 'newIdentity' },
- { name: 'haveIdentity', call: 'haveIdentity' },
- { name: 'newGroup', call: 'newGroup' },
- { name: 'addToGroup', call: 'addToGroup' }
- ];
- };
-
- var ethWatchMethods = function () {
- var newFilter = function (args) {
- return typeof args[0] === 'string' ? 'newFilterString' : 'newFilter';
- };
-
- return [
- { name: 'newFilter', call: newFilter },
- { name: 'uninstallFilter', call: 'uninstallFilter' },
- { name: 'getMessages', call: 'getMessages' }
- ];
- };
-
- var shhWatchMethods = function () {
- return [
- { name: 'newFilter', call: 'shhNewFilter' },
- { name: 'uninstallFilter', call: 'shhUninstallFilter' },
- { name: 'getMessage', call: 'shhGetMessages' }
- ];
- };
-
- 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 (result) {
- if (result || typeof result === "boolean") {
- resolve(result);
- return;
- }
- reject(result);
- });
- });
- }).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(result) {
- resolve(result);
- });
- });
- };
- 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 (result) {
- if (result) {
- resolve(result);
- } else {
- reject(result);
- }
- });
- });
- }).catch(function (err) {
- console.error(err);
- });
- }
- }
- Object.defineProperty(obj, property.name, proto);
- });
- };
-
- 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
- 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;
- },
-
- toDecimal: function (val) {
- return parseInt(val, 16);
- },
-
- fromAscii: function(str, pad) {
- pad = pad === undefined ? 32 : pad;
- var hex = this.toHex(str);
- while(hex.length < pad*2)
- hex += "00";
- return hex
- },
-
- eth: {
- prototype: Object(),
- watch: function (params) {
- return new Filter(params, ethWatch);
- },
- },
-
- db: {
- prototype: Object()
- },
-
- shh: {
- prototype: Object(),
- 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);
- },
- };
-
- var eth = web3.eth;
- setupMethods(eth, ethMethods());
- setupProperties(eth, ethProperties());
- setupMethods(web3.db, dbMethods());
- setupMethods(web3.shh, shhMethods());
-
- var ethWatch = {
- changed: 'changed'
- };
- setupMethods(ethWatch, ethWatchMethods());
- var shhWatch = {
- changed: 'shhChanged'
- };
- 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();
- };
-
- 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);
- });
- };
-
- 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.data)
- delete web3._callbacks[data._id];
- }
- }
- }
-
- /*
- // Install default provider
- if(!web3.provider.installed()) {
- var sock = new web3.WebSocket("ws://localhost:40404/eth");
-
- web3.setProvider(sock);
- }
- */
-
- window.web3 = web3;
-
-})(this);
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..38465e7bd
--- /dev/null
+++ b/package.json
@@ -0,0 +1,67 @@
+{
+ "name": "ethereum.js",
+ "namespace": "ethereum",
+ "version": "0.0.3",
+ "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 --git a/qt.js b/qt.js
deleted file mode 100644
index 644c37737..000000000
--- a/qt.js
+++ /dev/null
@@ -1,27 +0,0 @@
-(function() {
- 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);
- },
- });
-
- if(typeof(web3) !== "undefined" && web3.providers !== undefined) {
- web3.providers.QtProvider = QtProvider;
- }
-})();
-
diff --git a/websocket.js b/websocket.js
deleted file mode 100644
index 732a086f2..000000000
--- a/websocket.js
+++ /dev/null
@@ -1,51 +0,0 @@
-(function() {
- 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); }
- });
-
- if(typeof(web3) !== "undefined" && web3.providers !== undefined) {
- web3.providers.WebSocketProvider = WebSocketProvider;
- }
-})();