-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
gobitfly
committed
May 11, 2017
0 parents
commit a7c2c23
Showing
27 changed files
with
1,514 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
*.pid.lock | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# nyc test coverage | ||
.nyc_output | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# Bower dependency directory (https://bower.io/) | ||
bower_components | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directories | ||
node_modules/ | ||
jspm_packages/ | ||
|
||
# Typescript v1 declaration files | ||
typings/ | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional eslint cache | ||
.eslintcache | ||
|
||
# Optional REPL history | ||
.node_repl_history | ||
|
||
# Output of 'npm pack' | ||
*.tgz | ||
|
||
# Yarn Integrity file | ||
.yarn-integrity | ||
|
||
# dotenv environment variables file | ||
.env | ||
|
||
# Data directory | ||
data.db | ||
|
||
# Configuration file | ||
config.js |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# ERC20-Exporter | ||
### Lightweight explorer for ERC20 based Ethereum tokens | ||
|
||
ERC20-Exporter is an explorer built with NodeJS, Express and Parity. It does not require an external database and retrieves all information on the fly from a backend Ethereum node. | ||
|
||
|
||
A demo instance connected to the Golem Network Token is available at [gnt.etherchain.org](http://gnt.etherchain.org). | ||
|
||
## Current Features | ||
* Browse transactions and accounts | ||
* Named accounts | ||
* Event log browser | ||
* Supports Transfer and Approval events | ||
* Live Backend Node status display | ||
* Support for all [Bootswatch](https://bootswatch.com/) skins | ||
* Accounts enumeration | ||
* Supports IPC and HTTP backend connections | ||
* Responsive layout | ||
|
||
Missing a feature? Please request it by creating a new [Issue](https://github.com/gobitfly/erc20-exporter/issues). | ||
|
||
## Getting started | ||
|
||
Supported OS: Ubuntu 16.04 | ||
|
||
Supported Ethereum backend nodes: Parity, Geth (untested) | ||
|
||
1. Setup a nodejs & npm environment | ||
2. Install the latest version of the Parity Ethereum client | ||
3. Start parity using the following options: `parity --warp` | ||
4. Clone this repository to your local machine: `git clone https://github.com/gobitfly/erc20-exporter` | ||
5. Install all dependencies: `npm install` | ||
6. Rename `config.js.example` into `config.js` and adjust the file to your local environment & token | ||
7. Start the explorer: `npm start` | ||
8. Browse to `http://localhost:3000` | ||
|
||
Please note that for large tokens the initial data export can take up to 30 minutes. Once completed it is recommended to change the exportStartBlock parameter in the config file to a block number that is around 30.000 blocks behind the current tip of the chain and restart the exporter. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
var express = require('express'); | ||
var path = require('path'); | ||
var favicon = require('serve-favicon'); | ||
var logger = require('morgan'); | ||
var cookieParser = require('cookie-parser'); | ||
var bodyParser = require('body-parser'); | ||
|
||
var index = require('./routes/index'); | ||
var account = require('./routes/account'); | ||
var accounts = require('./routes/accounts'); | ||
var event = require('./routes/event'); | ||
var events = require('./routes/events'); | ||
var search = require('./routes/search'); | ||
|
||
var config = new(require('./config.js'))(); | ||
var Datastore = require('nedb-core') | ||
var db = new Datastore({ filename: './data.db', autoload: true }); | ||
|
||
db.ensureIndex({ fieldName: 'balance' }, function (err) { | ||
if (err) { | ||
console.log("Error creating balance db index:", err); | ||
} | ||
}); | ||
|
||
db.ensureIndex({ fieldName: 'timestamp' }, function (err) { | ||
if (err) { | ||
console.log("Error creating timestamp db index:", err); | ||
} | ||
}); | ||
|
||
db.ensureIndex({ fieldName: 'args._from' }, function (err) { | ||
if (err) { | ||
console.log("Error creating _from db index:", err); | ||
} | ||
}); | ||
|
||
db.ensureIndex({ fieldName: 'args._to' }, function (err) { | ||
if (err) { | ||
console.log("Error creating _to db index:", err); | ||
} | ||
}); | ||
|
||
var exporterService = require('./services/exporter.js'); | ||
var exporter = new exporterService(config, db); | ||
|
||
var app = express(); | ||
|
||
// view engine setup | ||
app.set('views', path.join(__dirname, 'views')); | ||
app.set('view engine', 'pug'); | ||
app.set('config', config); | ||
app.set('db', db); | ||
app.set('trust proxy', true); | ||
|
||
// uncomment after placing your favicon in /public | ||
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); | ||
app.use(logger(config.logFormat)); | ||
app.use(bodyParser.json()); | ||
app.use(bodyParser.urlencoded({ extended: false })); | ||
app.use(cookieParser()); | ||
app.use(express.static(path.join(__dirname, 'public'))); | ||
|
||
app.use('/', index); | ||
app.use('/account', account); | ||
app.use('/accounts', accounts); | ||
app.use('/event', event); | ||
app.use('/events', events); | ||
app.use('/search', search); | ||
|
||
app.locals.moment = require('moment'); | ||
app.locals.nodeStatus = new(require('./utils/nodeStatus.js'))(config); | ||
app.locals.nameformatter = new(require('./utils/nameformatter.js'))(config); | ||
app.locals.tokenformatter = new(require('./utils/tokenformatter.js'))(config); | ||
app.locals.config = config; | ||
|
||
// catch 404 and forward to error handler | ||
app.use(function(req, res, next) { | ||
var err = new Error('Not Found'); | ||
err.status = 404; | ||
next(err); | ||
}); | ||
|
||
// error handler | ||
app.use(function(err, req, res, next) { | ||
// set locals, only providing error in development | ||
res.locals.message = err.message; | ||
res.locals.error = req.app.get('env') === 'development' ? err : {}; | ||
|
||
// render the error page | ||
res.status(err.status || 500); | ||
res.render('error'); | ||
}); | ||
|
||
module.exports = app; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
#!/usr/bin/env node | ||
|
||
/** | ||
* Module dependencies. | ||
*/ | ||
|
||
var app = require('../app'); | ||
var debug = require('debug')('erc20-explorer:server'); | ||
var http = require('http'); | ||
|
||
/** | ||
* Get port from environment and store in Express. | ||
*/ | ||
|
||
var port = normalizePort(process.env.PORT || '3000'); | ||
app.set('port', port); | ||
|
||
/** | ||
* Create HTTP server. | ||
*/ | ||
|
||
var server = http.createServer(app); | ||
|
||
/** | ||
* Listen on provided port, on all network interfaces. | ||
*/ | ||
|
||
server.listen(port); | ||
server.on('error', onError); | ||
server.on('listening', onListening); | ||
|
||
/** | ||
* Normalize a port into a number, string, or false. | ||
*/ | ||
|
||
function normalizePort(val) { | ||
var port = parseInt(val, 10); | ||
|
||
if (isNaN(port)) { | ||
// named pipe | ||
return val; | ||
} | ||
|
||
if (port >= 0) { | ||
// port number | ||
return port; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Event listener for HTTP server "error" event. | ||
*/ | ||
|
||
function onError(error) { | ||
if (error.syscall !== 'listen') { | ||
throw error; | ||
} | ||
|
||
var bind = typeof port === 'string' | ||
? 'Pipe ' + port | ||
: 'Port ' + port; | ||
|
||
// handle specific listen errors with friendly messages | ||
switch (error.code) { | ||
case 'EACCES': | ||
console.error(bind + ' requires elevated privileges'); | ||
process.exit(1); | ||
break; | ||
case 'EADDRINUSE': | ||
console.error(bind + ' is already in use'); | ||
process.exit(1); | ||
break; | ||
default: | ||
throw error; | ||
} | ||
} | ||
|
||
/** | ||
* Event listener for HTTP server "listening" event. | ||
*/ | ||
|
||
function onListening() { | ||
var addr = server.address(); | ||
var bind = typeof addr === 'string' | ||
? 'pipe ' + addr | ||
: 'port ' + addr.port; | ||
debug('Listening on ' + bind); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
var web3 = require('web3'); | ||
var net = require('net'); | ||
|
||
var config = function () { | ||
|
||
this.logFormat = "combined"; | ||
this.ipcPath = process.env["HOME"] + "/.local/share/io.parity.ethereum/jsonrpc.ipc"; | ||
this.provider = new web3.providers.IpcProvider(this.ipcPath, net); | ||
|
||
this.bootstrapUrl = "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/yeti/bootstrap.min.css"; | ||
|
||
this.names = { | ||
"0x007733a1fe69cf3f2cf989f81c7b4cac1693387a": "POA-Digix", | ||
"0x00e4a10650e5a6d6001c38ff8e64f97016a1645c": "POA-Aurel", | ||
"0x00e6d2b931f55a3f1701c7389d592a7778897879": "POA-Maker", | ||
"0x0010f94b296a852aaac52ea6c5ac72e03afd032d": "POA-Paritytech", | ||
"0x0020ee4be0e2027d76603cb751ee069519ba81a1": "POA-Melonport", | ||
"0x4ed9b08e6354c70fe6f8cb0411b0d3246b424d6c": "POA-OneBit", | ||
"0x00d6cc1ba9cf89bd2e58009741f4f7325badc0ed": "POA-Etherscan", | ||
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de": "POA-GridS", | ||
"0x00427feae2419c15b89d1c21af10d1b6650a4d3d": "POA-Attores" | ||
} | ||
|
||
} | ||
|
||
module.exports = config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"name": "erc20-explorer", | ||
"version": "0.0.0", | ||
"private": true, | ||
"scripts": { | ||
"start": "node ./bin/www" | ||
}, | ||
"dependencies": { | ||
"async": "^2.4.0", | ||
"body-parser": "~1.16.0", | ||
"cookie-parser": "~1.4.3", | ||
"debug": "~2.6.0", | ||
"express": "~4.14.1", | ||
"moment": "^2.18.1", | ||
"morgan": "~1.7.0", | ||
"nedb-core": "^3.0.6", | ||
"pug": "~2.0.0-beta10", | ||
"serve-favicon": "~2.3.2", | ||
"web3": "^0.19.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
body { | ||
padding: 50px; | ||
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; | ||
} | ||
|
||
a { | ||
color: #00B7FF; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
var express = require('express'); | ||
var router = express.Router(); | ||
|
||
router.get('/:account/:offset?', function(req, res, next) { | ||
var db = req.app.get('db'); | ||
|
||
if (!req.params.offset) { | ||
req.params.offset = 0; | ||
} else { | ||
req.params.offset = parseInt(req.params.offset); | ||
} | ||
db.find({_id: req.params.account}).exec(function (err, balance) { | ||
|
||
if (err) { | ||
return next(err); | ||
} | ||
|
||
if (balance.length === 0 || !balance[0]._id) { | ||
return next({message: "Account not found!"}); | ||
} | ||
|
||
db.find( {$or: [{ "args._from": req.params.account }, { "args._to": req.params.account }] }).sort({ timestamp: -1 }).skip(req.params.offset).limit(50).exec(function(err, events) { | ||
res.render('account', { balance: balance[0], events: events, offset: req.params.offset, stepSize: 50 }); | ||
}); | ||
}); | ||
|
||
}); | ||
|
||
module.exports = router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
var express = require('express'); | ||
var router = express.Router(); | ||
|
||
router.get('/:offset?', function(req, res, next) { | ||
var db = req.app.get('db'); | ||
|
||
if (!req.params.offset) { | ||
req.params.offset = 0; | ||
} else { | ||
req.params.offset = parseInt(req.params.offset); | ||
} | ||
|
||
db.find({ balance: { $exists: true } }).sort({ _id: 1 }).skip(req.params.offset).limit(50).exec(function(err, accounts) { | ||
res.render('accounts', {accounts: accounts, offset: req.params.offset, stepSize: 50 }); | ||
}); | ||
|
||
}); | ||
|
||
module.exports = router; |
Oops, something went wrong.