Browse Source

Merge pull request #205 from SuperNETorg/electrum

electrum branch update
pkg_automation_electrum
ca333 7 years ago
committed by GitHub
parent
commit
1e9c7fc51a
  1. 3
      gui/startup/agama-instance-error.html
  2. 4
      gui/startup/app-closing.html
  3. 2
      gui/startup/app-settings.html
  4. 36
      gui/startup/index.html
  5. 119
      gui/startup/main.html
  6. 18
      index.html
  7. 181
      main.js
  8. 15
      package.json
  9. 98
      routes/appConfig.js
  10. 962
      routes/cache.js
  11. 347
      routes/electrumjs/electrumjs.core.js
  12. 205
      routes/electrumjs/electrumjs.networks.js
  13. 120
      routes/electrumjs/electrumjs.txdecoder.js
  14. 45
      routes/mock.js
  15. 98
      routes/nativeCoind.js
  16. 2
      routes/ports.js
  17. 4858
      routes/shepherd.js
  18. 2
      version
  19. 2
      version_build

3
gui/startup/agama-instance-error.html

@ -3,14 +3,12 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/global/css/bootstrap.min.css">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/mainWindow/css/jRoll.min.css">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/mainWindow/css/loading.css">
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/module-hack.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/global/vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/scripts/config.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/bluebird.min.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/loading.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/jRoll.min.js"></script>
<script>if (window.module) module = window.module;</script>
</head>
<body class="agamaMode agama-default-window-height">
@ -30,6 +28,5 @@
class="btn btn-primary btn-close-app">Quit</button>
</div>
</div>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/init.js"></script>
</body>
</html>

4
gui/startup/app-closing.html

@ -3,17 +3,15 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/global/css/bootstrap.min.css">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/mainWindow/css/jRoll.min.css">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/mainWindow/css/loading.css">
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/module-hack.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/global/vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/scripts/config.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/bluebird.min.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/loading.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/jRoll.min.js"></script>
<script>if (window.module) module = window.module;</script>
</head>
<body class="agamaMode agama-default-window-height">
<body class="agamaMode closing-window-height">
<div class="text-center">
<div
id="agamaMode"

2
gui/startup/app-settings.html

@ -3,14 +3,12 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/global/css/bootstrap.min.css">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/mainWindow/css/jRoll.min.css">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/mainWindow/css/loading.css">
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/module-hack.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/global/vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/scripts/config.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/bluebird.min.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/loading.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/jRoll.min.js"></script>
<script>if (window.module) module = window.module;</script>
</head>
<body class="agamaMode agama-app-settings-window">

36
gui/startup/index.html

@ -3,14 +3,12 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/global/css/bootstrap.min.css">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/mainWindow/css/jRoll.min.css">
<link rel="stylesheet" href="../EasyDEX-GUI/assets/mainWindow/css/loading.css">
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/module-hack.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/global/vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/scripts/config.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/bluebird.min.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/loading.js"></script>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/jRoll.min.js"></script>
<script>if (window.module) module = window.module;</script>
</head>
<body class="agamaMode loading-window">
@ -40,7 +38,7 @@
onClick="toggleDropdown()">
<img src="../EasyDEX-GUI/assets/mainWindow/img/fa-caret-down.png">
</div>
<ul class="dropdown-menu hide">
<ul class="dropdown-menu native hide">
<li onClick="closeMainWindow()">
<a>KMD + REVS + JUMBLR</a>
</li>
@ -51,22 +49,42 @@
<a>KMD (passive)</a>
</li>
</ul>
<button
id="normalStartBtn"
onClick="normalStart()"
class="btn btn-primary btn-mode">
<img src="../EasyDEX-GUI/assets/mainWindow/img/fa-cubes.png"> All modes
id="spvBtn"
onClick="startSPV('KMD')"
class="btn btn-primary btn-mode btn-native margin-left-20">
<img src="../EasyDEX-GUI/assets/mainWindow/img/fa-flash.png"> KMD lite
</button>
<div class="margin-top-20 settings-stick-to-right">
<div
id="spvBtnCarret"
class="btn btn-primary btn-caret"
onClick="toggleDropdown('lite')">
<img src="../EasyDEX-GUI/assets/mainWindow/img/fa-caret-down.png">
</div>
<ul class="dropdown-menu lite hide">
<li onClick="startSPV('KMD+REVS+JUMBLR')">
<a>Lite: KMD + REVS + JUMBLR</a>
</li>
<li onClick="startSPV('CHIPS')">
<a>CHIPS lite</a>
</li>
<li onClick="closeMainWindow(null, true)">
<a>Custom</a>
</li>
</ul>
<div class="margin-top-20">
<button
id="settingsBtn"
onClick="openSettingsWindow()"
class="btn btn-info btn-mode">
<img src="../EasyDEX-GUI/assets/mainWindow/img/fa-cogs.png"> Settings
</button>
<button class="btn btn-primary btn-mode hide" onClick="closeMainWindow(null, true)">Custom</button>
</div>
</div>
</div>
<script type="text/javascript" src="../EasyDEX-GUI/assets/mainWindow/js/init.js"></script>
<script type="text/javascript">init()</script>
</body>
</html>

119
gui/startup/main.html

@ -1,119 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" href="EasyDEX-GUI/assets/global/css/bootstrap.min.css">
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
<script type="text/javascript" src="EasyDEX-GUI/assets/global/vendor/jquery/jquery.min.js"></script>
<script>if (window.module) module = window.module;</script>
<script type="text/javascript">
function resizeMainWindow() {
/* set default map height */
var mapH = $(window).height();
$(".page-main").outerHeight(mapH);
}
function StartIguana() {
var ajax_data = {"herd":"iguana"};
console.log(ajax_data);
$.ajax({
type: 'POST',
data: JSON.stringify(ajax_data),
url: 'http://127.0.0.1:17777/shepherd/herd',
dataType: "xml/html/script/json", // expected format for response
contentType: "application/json", // send as JSON
success: function(data, textStatus, jqXHR) {
var AjaxOutputData = JSON.parse(data);
console.log('== ActiveHandle Data OutPut ==');
console.log(AjaxOutputData);
},
error: function(xhr, textStatus, error) {
console.log(xhr.statusText);
if ( xhr.readyState == 0 ) {
}
console.log(textStatus);
console.log(error);
}
});
}
function StartCorsproxy() {
var ajax_data = {"herd":"corsproxy"};
console.log(ajax_data);
$.ajax({
type: 'POST',
data: JSON.stringify(ajax_data),
url: 'http://127.0.0.1:17777/shepherd/herd',
dataType: "xml/html/script/json", // expected format for response
contentType: "application/json", // send as JSON
success: function(data, textStatus, jqXHR) {
var AjaxOutputData = JSON.parse(data);
console.log('== ActiveHandle Data OutPut ==');
console.log(AjaxOutputData);
},
error: function(xhr, textStatus, error) {
console.log(xhr.statusText);
if ( xhr.readyState == 0 ) {
}
console.log(textStatus);
console.log(error);
}
});
}
function StartKomodod() {
var ajax_data = {"herd":"komodod"};
console.log(ajax_data);
$.ajax({
type: 'POST',
data: JSON.stringify(ajax_data),
url: 'http://127.0.0.1:17777/shepherd/herd',
dataType: "xml/html/script/json", // expected format for response
contentType: "application/json", // send as JSON
success: function(data, textStatus, jqXHR) {
var AjaxOutputData = JSON.parse(data);
console.log('== ActiveHandle Data OutPut ==');
console.log(AjaxOutputData);
},
error: function(xhr, textStatus, error) {
console.log(xhr.statusText);
if ( xhr.readyState == 0 ) {
}
console.log(textStatus);
console.log(error);
}
});
}
function StartKMDNativeIGUI() {
var secToLaunch = 60;
$('#kmdNativeBtn').text('Starting Komodo in ' + secToLaunch + 's');
StartCorsproxy();
StartKomodod();
setInterval(function() {
$('#kmdNativeBtn').text('Starting Komodo in ' + secToLaunch + 's');
secToLaunch--;
}, 1000);
setTimeout(function() {
document.location = 'Iguana-GUI/index.html';
}, secToLaunch * 1000);
}
jQuery(document).ready(function() {
resizeMainWindow();
window.onresize = function(event) { resizeMainWindow(); };
});
</script>
</head>
<body>
<div class="page-main">
<div class="col-xs-6 text-center" style="height: 100%; background: url(bg.jpg) no-repeat fixed; background-color: #c7c7c7; vertical-align: middle;" id="iguanaGuiStart">
<h1 style="color: white;">Iguana Wallet<h1>
<a type="button" class="btn btn-default btn-lg" href="Iguana-GUI/index.html">Open Iguana Wallet</a><br/><br/>
<a type="button" class="btn btn-default btn-lg" href="#" onclick="StartCorsproxy()">Launch proxy server</a><br/><br/>
<a type="button" class="btn btn-default btn-lg" href="#" onclick="StartKMDNativeIGUI()" id="kmdNativeBtn">Komodo Native</a><br/><br/>
<a type="button" class="btn btn-default btn-lg" href="#" onclick="StartIguana()">Start Iguana Core</a>
</div>
<div class="col-xs-6 text-center" style="height: 100%; background: url(bg2.jpg) no-repeat fixed; background-color: #d8d8d8; vertical-align: middle;" id="edexGuiStart">
<h1 style="color: white;">EasyDEX</h1>
<a type="button" class="btn btn-default btn-lg" href="EasyDEX-GUI/index.html">Open EasyDEX</a>
</div>
</div>
</body>
</html>

18
index.html

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>iguanaElectronApp</title>
</head>
<body>
<h3>some version information:</h3>
node.js <script>document.write(process.versions.node)</script>,
chromium <script>document.write(process.versions.chrome)</script>,
electron <script>document.write(process.versions.electron)</script>.
</body>
<script>
//bind other code refs
//require('./xxx.js')
</script>
</html>

181
main.js

@ -1,4 +1,4 @@
// main proc for EasyDEX GUI
// main proc for Agama
// this app spawns iguana in background in nontech-mode
const electron = require('electron'),
@ -19,20 +19,21 @@ var express = require('express'),
fs = require('fs'),
fsnode = require('fs'),
fs = require('fs-extra'),
pm2 = require('pm2'),
cluster = require('cluster'),
numCPUs = require('os').cpus().length;
Promise = require('bluebird');
if (osPlatform === 'linux') {
process.env.ELECTRON_RUN_AS_NODE = true;
// console.log(process.env);
}
// GUI APP settings and starting gui on address http://120.0.0.1:17777
var shepherd = require('./routes/shepherd');
var guiapp = express();
var appConfig = shepherd.loadLocalConfig(); // load app config
const nativeCoindList = shepherd.scanNativeCoindBins();
shepherd.setVar('nativeCoindList', nativeCoindList);
let localVersion;
let localVersionFile = shepherd.readVersionFile();
@ -52,7 +53,7 @@ app.setName(appBasicInfo.name);
app.setVersion(appBasicInfo.version);
shepherd.binFixRights();
shepherd.createIguanaDirs();
shepherd.createAgamaDirs();
const appSessionHash = md5(Date.now().toString());
@ -67,20 +68,28 @@ shepherd.writeLog(`platform: ${osPlatform}`);
shepherd.writeLog(`os_release: ${os.release()}`);
shepherd.writeLog(`os_type: ${os.type()}`);
var appConfig = shepherd.loadLocalConfig(); // load app config
shepherd.log(`app init ${appSessionHash}`);
shepherd.log(`app info: ${appBasicInfo.name} ${appBasicInfo.version}`);
shepherd.log('sys info:');
shepherd.log(`totalmem_readable: ${formatBytes(os.totalmem())}`);
shepherd.log(`arch: ${os.arch()}`);
shepherd.log(`cpu: ${os.cpus()[0].model}`);
shepherd.log(`cpu_cores: ${os.cpus().length}`);
shepherd.log(`platform: ${osPlatform}`);
shepherd.log(`os_release: ${os.release()}`);
shepherd.log(`os_type: ${os.type()}`);
appConfig['daemonOutput'] = false; // shadow setting
let __defaultAppSettings = require('./routes/appConfig.js').config;
__defaultAppSettings['daemonOutput'] = false; // shadow setting
const _defaultAppSettings = __defaultAppSettings;
shepherd.log(`app started in ${(appConfig.dev ? 'dev mode' : ' user mode')}`);
shepherd.writeLog(`app started in ${(appConfig.dev ? 'dev mode' : ' user mode')}`);
shepherd.setConfKMD();
if (appConfig.killIguanaOnStart) {
shepherd.killRogueProcess('iguana');
}
shepherd.setConfKMD('CHIPS');
guiapp.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', appConfig.dev ? '*' : 'http://127.0.0.1:3000');
@ -103,7 +112,7 @@ process.once('loaded', () => {
process.setFdLimit(appConfig.maxDescriptors.darwin);
app.setAboutPanelOptions({
applicationName: app.getName(),
applicationVersion: app.getVersion(),
applicationVersion: `app.getVersion().replace('version=', '')}-beta`,
copyright: 'Released under the MIT license',
credits: 'SuperNET Team'
})
@ -148,13 +157,13 @@ let forceQuitApp = false;
const _zcashParamsExist = shepherd.zcashParamsExist();
module.exports = guiapp;
let iguanaIcon;
let agamaIcon;
if (os.platform() === 'linux') {
iguanaIcon = path.join(__dirname, '/assets/icons/agama_icons/128x128.png');
agamaIcon = path.join(__dirname, '/assets/icons/agama_icons/128x128.png');
}
if (os.platform() === 'win32') {
iguanaIcon = path.join(__dirname, '/assets/icons/agama_app_icon.ico');
agamaIcon = path.join(__dirname, '/assets/icons/agama_app_icon.ico');
}
function createLoadingWindow() {
@ -166,7 +175,7 @@ function createLoadingWindow() {
width: 500,
height: 355,
frame: false,
icon: iguanaIcon,
icon: agamaIcon,
show: false,
});
} catch(e) {}
@ -183,7 +192,7 @@ function createLoadingWindow() {
// start sockets.io
io.set('origins', appConfig.dev ? 'http://127.0.0.1:3000' : `http://127.0.0.1:${appConfig.agamaPort}`); // set origin
io.on('connection', function(client) {
/*io.on('connection', function(client) {
shepherd.log('EDEX GUI is connected...');
shepherd.writeLog('EDEX GUI is connected...');
@ -197,7 +206,7 @@ function createLoadingWindow() {
shepherd.log(data);
client.emit('messages', 'Sockets server is listening');
});
});
});*/
});
} else {
willQuitApp = true;
@ -219,6 +228,7 @@ function createLoadingWindow() {
loadingWindow.forseCloseApp = forseCloseApp;
loadingWindow.createAppSettingsWindow = createAppSettingsWindow;
loadingWindow.startKMDNative = shepherd.startKMDNative;
loadingWindow.startSPV = shepherd.startSPV;
// load our index.html (i.e. easyDEX GUI)
loadingWindow.loadURL(`http://${appConfig.host}:${appConfig.agamaPort}/gui/startup`);
@ -229,9 +239,6 @@ function createLoadingWindow() {
});
shepherd.writeLog('show loading window');
// DEVTOOLS - only for dev purposes - ca333
// loadingWindow.webContents.openDevTools()
// if window closed we kill iguana proc
loadingWindow.on('hide', function() {
// our app does not have multiwindow - so we dereference the window object instead of
@ -276,7 +283,7 @@ function createAppCloseWindow() {
width: 500,
height: 355,
frame: false,
icon: iguanaIcon,
icon: agamaIcon,
show: false,
});
@ -299,9 +306,9 @@ function createAppSettingsWindow() {
// initialise window
appSettingsWindow = new BrowserWindow({ // dirty hack to prevent main window flash on quit
width: 750,
height: !appConfig.experimentalFeatures ? 570 : 700,
height: 570,
frame: false,
icon: iguanaIcon,
icon: agamaIcon,
show: false,
});
@ -343,7 +350,7 @@ function createWindow(status) {
mainWindow = new BrowserWindow({ // dirty hack to prevent main window flash on quit
width: closeAppAfterLoading ? 1 : 1280,
height: closeAppAfterLoading ? 1 : 800,
icon: iguanaIcon,
icon: agamaIcon,
show: false,
});
@ -371,39 +378,36 @@ function createWindow(status) {
]);
// load our index.html (i.e. easyDEX GUI)
if (appConfig.edexGuiOnly) {
if (appConfig.v2) {
shepherd.writeLog('show edex gui');
mainWindow.appConfig = appConfig;
mainWindow.appConfigSchema = shepherd.appConfigSchema;
mainWindow.appBasicInfo = appBasicInfo;
mainWindow.appSessionHash = appSessionHash;
mainWindow.assetChainPorts = require('./routes/ports.js');
mainWindow.zcashParamsExist = _zcashParamsExist;
mainWindow.iguanaIcon = iguanaIcon;
mainWindow.testLocation = shepherd.testLocation;
mainWindow.kmdMainPassiveMode = shepherd.kmdMainPassiveMode;
mainWindow.getAppRuntimeLog = shepherd.getAppRuntimeLog;
if (appConfig.dev) {
mainWindow.loadURL('http://127.0.0.1:3000');
} else {
mainWindow.loadURL(`http://${appConfig.host}:${appConfig.agamaPort}/gui/EasyDEX-GUI/react/build`);
}
mainWindow.webContents.on('did-finish-load', function() {
setTimeout(function() {
mainWindow.show();
}, 40);
});
} else {
shepherd.writeLog('show edex gui');
mainWindow.loadURL(`http://${appConfig.host}:${appConfig.agamaPort}/gui/EasyDEX-GUI/`);
}
shepherd.writeLog('show edex gui');
mainWindow.appConfig = appConfig;
mainWindow.appConfigSchema = shepherd.appConfigSchema;
mainWindow.appBasicInfo = appBasicInfo;
mainWindow.appSessionHash = appSessionHash;
mainWindow.assetChainPorts = require('./routes/ports.js');
mainWindow.zcashParamsExist = _zcashParamsExist;
mainWindow.agamaIcon = agamaIcon;
mainWindow.testLocation = shepherd.testLocation;
mainWindow.kmdMainPassiveMode = shepherd.kmdMainPassiveMode;
mainWindow.getAppRuntimeLog = shepherd.getAppRuntimeLog;
mainWindow.nativeCoindList = nativeCoindList;
mainWindow.zcashParamsDownloadLinks = shepherd.zcashParamsDownloadLinks;
mainWindow.isWindows = os.platform() === 'win32' ? true : false;
mainWindow.appExit = appExit;
mainWindow.getMaxconKMDConf = shepherd.getMaxconKMDConf;
mainWindow.setMaxconKMDConf = shepherd.setMaxconKMDConf;
if (appConfig.dev) {
mainWindow.loadURL('http://127.0.0.1:3000');
} else {
mainWindow.loadURL(`http://${appConfig.host}:${appConfig.agamaPort}/gui/startup/main.html`);
mainWindow.loadURL(`http://${appConfig.host}:${appConfig.agamaPort}/gui/EasyDEX-GUI/react/build`);
}
mainWindow.webContents.on('did-finish-load', function() {
setTimeout(function() {
mainWindow.show();
}, 40);
});
mainWindow.webContents.on('context-menu', (e, params) => { // context-menu returns params
const { selectionText, isEditable } = params; // params obj
@ -417,25 +421,15 @@ function createWindow(status) {
// DEVTOOLS - only for dev purposes - ca333
// mainWindow.webContents.openDevTools()
function pm2Exit() {
const ConnectToPm2 = function() {
function appExit() {
const CloseDaemons = function() {
return new Promise(function(resolve, reject) {
shepherd.log('Closing Main Window...');
shepherd.writeLog('exiting app...');
shepherd.dumpCacheBeforeExit();
shepherd.quitKomodod(1000);
pm2.connect(true, function(err) {
shepherd.log('connecting to pm2...');
shepherd.writeLog('connecting to pm2...');
if (err) {
shepherd.log(err);
}
});
const result = 'Connecting To Pm2: done';
const result = 'Closing daemons: done';
shepherd.log(result);
shepherd.writeLog(result);
@ -443,31 +437,6 @@ function createWindow(status) {
})
}
const KillPm2 = function() {
return new Promise(function(resolve, reject) {
shepherd.log('killing to pm2...');
shepherd.writeLog('killing to pm2...');
pm2.killDaemon(function(err) {
pm2.disconnect();
shepherd.log('killed to pm2...');
shepherd.writeLog('killed to pm2...');
if (err)
throw err;
});
const result = 'Killing Pm2: done';
setTimeout(function() {
shepherd.log(result);
shepherd.writeLog(result);
resolve(result);
}, 2000);
})
}
const HideMainWindow = function() {
return new Promise(function(resolve, reject) {
const result = 'Hiding Main Window: done';
@ -490,7 +459,6 @@ function createWindow(status) {
return new Promise(function(resolve, reject) {
const result = 'Quiting App: done';
KillPm2(); // required for normal app quit in iguana-less mode
app.quit();
shepherd.log(result);
resolve(result);
@ -498,10 +466,7 @@ function createWindow(status) {
}
const closeApp = function() {
ConnectToPm2()
.then(function(result) {
return KillPm2();
})
CloseDaemons()
.then(HideMainWindow)
.then(HideAppClosingWindow)
.then(QuitApp);
@ -524,7 +489,7 @@ function createWindow(status) {
// if window closed we kill iguana proc
mainWindow.on('closed', function() {
pm2Exit();
appExit();
});
}
}
@ -543,13 +508,15 @@ app.on('window-all-closed', function() {
// Calling event.preventDefault() will prevent the default behaviour, which is terminating the application.
app.on('before-quit', function(event) {
shepherd.log('before-quit');
shepherd.killRogueProcess('iguana'); // kill any rogue iguana core instances
if (!forceQuitApp && mainWindow === null && loadingWindow != null) { // mainWindow not intitialised and loadingWindow not dereferenced
if (!forceQuitApp &&
mainWindow === null &&
loadingWindow != null) { // mainWindow not intitialised and loadingWindow not dereferenced
// loading window is still open
shepherd.log('before-quit prevented');
shepherd.writeLog('quit app after loading is done');
closeAppAfterLoading = true;
// obsolete(?)
let code = `$('#loading_status_text').html('Preparing to shutdown the wallet.<br/>Please wait while all daemons are closed...')`;
loadingWindow.webContents.executeJavaScript(code);
event.preventDefault();
@ -559,7 +526,9 @@ app.on('before-quit', function(event) {
// Emitted when all windows have been closed and the application will quit.
// Calling event.preventDefault() will prevent the default behaviour, which is terminating the application.
app.on('will-quit', function(event) {
if (!forceQuitApp && mainWindow === null && loadingWindow != null) {
if (!forceQuitApp &&
mainWindow === null &&
loadingWindow != null) {
// loading window is still open
shepherd.log('will-quit while loading window active');
event.preventDefault();
@ -569,18 +538,20 @@ app.on('will-quit', function(event) {
// Emitted when the application is quitting.
// Calling event.preventDefault() will prevent the default behaviour, which is terminating the application.
app.on('quit', function(event) {
if (!forceQuitApp && mainWindow === null && loadingWindow != null) {
if (!forceQuitApp &&
mainWindow === null &&
loadingWindow != null) {
shepherd.log('quit while loading window active');
event.preventDefault();
}
})
app.on('activate', function() {
if (mainWindow === null) {
// createWindow('open');
}
if (mainWindow === null) {}
});
app.commandLine.appendSwitch('ignore-certificate-errors'); // dirty hack
function formatBytes(bytes, decimals) {
if (bytes === 0) {
return '0 Bytes';

15
package.json

@ -1,7 +1,7 @@
{
"name": "agama_app",
"productName": "Agama",
"version": "0.2.22",
"version": "0.2.23",
"description": "Agama Desktop App",
"main": "main.js",
"scripts": {
@ -10,34 +10,35 @@
},
"repository": "https://github.com/SuperNETorg/Agama/",
"keywords": [
"iguana",
"agama",
"superNET",
"SuperNET",
"komodo",
"easydex",
"instantdex",
"pax"
],
"author": "ca333, grewalsatinder",
"author": "SuperNET",
"license": "MIT",
"devDependencies": {
"electron": "^1.4.1"
},
"dependencies": {
"adm-zip": "^0.4.7",
"bitcoinjs-lib": "^3.2.0",
"bluebird": "^3.4.7",
"body-parser": "^1.15.2",
"buffer-reverse": "^1.0.1",
"coinkey": "^2.0.0",
"coinselect": "github:bitcoinjs/coinselect",
"electron": "1.6.5",
"express": "^4.14.0",
"fix-path": "^2.1.0",
"fs-extra": "^1.0.0",
"graceful-fs": "^4.1.11",
"nodejs-aes256": "^1.0.1",
"pm2": "^2.4.3",
"portscanner": "^2.1.1",
"ps-node": "^0.1.5",
"remote-file-size": "^3.0.3",
"request": "^2.80.0",
"sha256": "^0.2.0",
"socket.io": "^1.7.3"
}
}

98
routes/appConfig.js

@ -1,58 +1,21 @@
const appConfig = {
config: { // default config
edexGuiOnly: true,
iguanaGuiOnly: false,
manualIguanaStart: false,
skipBasiliskNetworkCheck: true,
minNotaries: 8,
host: '127.0.0.1',
agamaPort: 17777,
iguanaCorePort: 7778,
maxDescriptors: {
darwin: 90000,
linux: 1000000,
},
killIguanaOnStart: true,
dev: false,
v2: true,
useBasiliskInstance: true,
debug: false,
cli: {
passthru: true,
default: true,
},
iguanaLessMode: true,
roundValues: false,
experimentalFeatures: false,
dataDir: '',
dex: {
walletUnlockTimeout: 3600,
},
},
schema: {
edexGuiOnly: {
display: false,
type: 'boolean',
displayName: 'EDEX GUI only',
},
iguanaGuiOnly: {
display: false,
type: 'boolean',
displayName: 'Iguana GUI only',
},
manualIguanaStart: {
display: false,
type: 'boolean',
displayName: 'Manual Iguana Start',
},
skipBasiliskNetworkCheck: {
display: false,
type: 'boolean',
displayName: 'Skip Basilisk Network Check',
},
minNotaries: {
display: false,
type: 'number',
displayName: 'Minimum notaries count',
info: 'Minimum number of notaries to connect to on startup',
},
host: {
display: true,
type: 'string',
@ -65,13 +28,6 @@ const appConfig = {
displayName: 'Agama Port',
info: 'Agama HTTP port. Required to run GUI.',
},
iguanaCorePort: {
display: true,
initDisplay: true,
type: 'number',
displayName: 'Iguana Core Port',
info: 'Default Iguana Core Port. Change it if you have conflicts with other applications.',
},
maxDescriptors: {
display: false,
displayName: 'Max Descriptors per Process',
@ -86,12 +42,6 @@ const appConfig = {
type: 'number',
},
},
killIguanaOnStart: {
display: true,
displayName: 'Kill Iguana Core Processes on Startup',
info: 'Kill any rogue Iguana Core processes during app startup',
type: 'boolean',
},
dev: {
display: true,
initDisplay: true,
@ -99,17 +49,6 @@ const appConfig = {
info: 'Enable developer mode',
type: 'boolean',
},
v2: {
display: false,
type: 'boolean',
},
useBasiliskInstance: {
display: true,
initDisplay: true,
displayName: 'Iguana Core Basilisk Instance',
info: 'Enable dedicated Iguana Core instance to handle all Basilisk network requests',
type: 'boolean',
},
debug: {
display: true,
initDisplay: true,
@ -117,28 +56,6 @@ const appConfig = {
info: 'Enable debug output',
type: 'boolean',
},
cli: {
display: true,
displayName: 'Direct BitcoinRPC passthru interface',
info: 'Enable direct BitcoinRPC passthru interface. It will bypass Iguana Core and send requests directly to Bitcoin JSON server.',
passthru: {
display: true,
displayName: 'Enable Direct Passthru',
type: 'boolean',
},
default: {
display: true,
displayName: 'Enable CLI passthru',
info: 'Enable komodo-cli passthru. This allows you to send CLI compatible commands directly from UI to komodo-cli.',
type: 'boolean',
},
},
iguanaLessMode: {
display: true,
displayName: 'Enable Native Only mode',
info: 'Limited to only Komodo native mode to speed up loading and reduce hardware resources consumption.',
type: 'boolean',
},
roundValues: {
display: true,
displayName: 'Enable amount rounding',
@ -165,6 +82,15 @@ const appConfig = {
info: 'Output daemon prints to GUI for debug purposes',
type: 'boolean',
},
dex: {
display: false,
displayName: 'dex',
walletUnlockTimeout: {
display: true,
displayName: 'walletUnlockTimeout',
type: 'number',
},
},
},
};

962
routes/cache.js

@ -1,962 +0,0 @@
const fs = require('fs-extra');
const request = require('request');
const async = require('async');
var cache = {};
var inMemCache;
var inMemPubkey;
cache.setVar = function(variable, value) {
cache[variable] = value;
}
/*
* cache data is dumped to disk before app quit or after cache.one call is finished
*/
cache.dumpCacheBeforeExit = function() {
if (inMemCache) {
cache.shepherd.log('dumping cache before exit');
fs.writeFileSync(`${cache.iguanaDir}/shepherd/cache-${inMemPubkey}.json`, JSON.stringify(inMemCache), 'utf8');
}
}
cache.get = function(req, res, next) {
const pubkey = req.query.pubkey;
if (pubkey) {
inMemPubkey = pubkey;
if (!inMemCache) {
cache.shepherd.log('serving cache from disk');
if (fs.existsSync(`${cache.iguanaDir}/shepherd/cache-${pubkey}.json`)) {
fs.readFile(`${cache.iguanaDir}/shepherd/cache-${pubkey}.json`, 'utf8', function(err, data) {
if (err) {
const errorObj = {
msg: 'error',
result: err,
};
res.end(JSON.stringify(errorObj));
} else { // deprecated
try {
const parsedJSON = JSON.parse(data);
const successObj = {
msg: 'success',
result: parsedJSON,
};
inMemCache = parsedJSON;
res.end(JSON.stringify(successObj));
} catch (e) {
cache.shepherd.log('JSON parse error while reading cache data from disk:');
cache.shepherd.log(e);
if (e.toString().indexOf('at position') > -1) {
const errorPos = e.toString().split(' ');
cache.shepherd.log(`JSON error ---> ${data.substring(errorPos[errorPos.length - 1] - 20, errorPos[errorPos.length - 1] + 20)} | error sequence: ${data.substring(errorPos[errorPos.length - 1], errorPos[errorPos.length - 1] + 1)}`);
cache.shepherd.log('attempting to recover JSON data');
fs.writeFile(`${cache.iguanaDir}/shepherd/cache-${pubkey}.json`, data.substring(0, errorPos[errorPos.length - 1]), function(err) {
const successObj = {
msg: 'success',
result: data.substring(0, errorPos[errorPos.length - 1]),
};
inMemCache = JSON.parse(data.substring(0, errorPos[errorPos.length - 1]));
res.end(JSON.stringify(successObj));
});
}
}
}
});
} else {
const errorObj = {
msg: 'error',
result: `no file with handle ${pubkey}`,
};
res.end(JSON.stringify(errorObj));
}
} else {
const successObj = {
msg: 'success',
result: inMemCache,
};
res.end(JSON.stringify(successObj));
}
} else {
const errorObj = {
msg: 'error',
result: 'no pubkey provided',
};
res.end(JSON.stringify(errorObj));
}
}
cache.groomGet = function(req, res, next) {
const _filename = req.query.filename;
if (_filename) {
if (fs.existsSync(`${cache.iguanaDir}/shepherd/cache-${_filename}.json`)) {
fs.readFile(`${cache.iguanaDir}/shepherd/cache-${_filename}.json`, 'utf8', function(err, data) {
if (err) {
const errorObj = {
msg: 'error',
result: err,
};
res.end(JSON.stringify(errorObj));
} else {
const successObj = {
msg: 'success',
result: data ? JSON.parse(data) : '',
};
res.end(JSON.stringify(successObj));
}
});
} else {
const errorObj = {
msg: 'error',
result: `no file with name ${_filename}`,
};
res.end(JSON.stringify(errorObj));
}
} else {
const errorObj = {
msg: 'error',
result: 'no file name provided',
};
res.end(JSON.stringify(errorObj));
}
}
cache.groomDelete = function(req, res, next) {
const _filename = req.body.filename;
if (_filename) {
if (fs.existsSync(`${cache.iguanaDir}/shepherd/cache-${_filename}.json`)) {
inMemCache = null;
fs.unlink(`${cache.iguanaDir}/shepherd/cache-${_filename}.json`, function(err) {
if (err) {
const errorObj = {
msg: 'error',
result: err,
};
res.end(JSON.stringify(errorObj));
} else {
const successObj = {
msg: 'success',
result: 'deleted',
};
res.end(JSON.stringify(successObj));
}
});
} else {
const errorObj = {
msg: 'error',
result: `no file with name ${_filename}`,
};
res.end(JSON.stringify(errorObj));
}
} else {
const errorObj = {
msg: 'error',
result: 'no file name provided',
};
res.end(JSON.stringify(errorObj));
}
}
cache.groomPost = function(req, res) {
const _filename = req.body.filename;
const _payload = req.body.payload;
if (!cacheCallInProgress) {
cacheCallInProgress = true;
if (_filename) {
if (!_payload) {
const errorObj = {
msg: 'error',
result: 'no payload provided',
};
res.end(JSON.stringify(errorObj));
} else {
inMemCache = JSON.parse(_payload);
cache.shepherd.log('appending groom post to in mem cache');
cache.shepherd.log('appending groom post to on disk cache');
fs.writeFile(`${cache.iguanaDir}/shepherd/cache-${_filename}.json`, _payload, function(err) {
if (err) {
const errorObj = {
msg: 'error',
result: err,
};
cacheCallInProgress = false;
res.end(JSON.stringify(errorObj));
} else {
const successObj = {
msg: 'success',
result: 'done',
};
cacheCallInProgress = false;
res.end(JSON.stringify(successObj));
}
});
}
} else {
const errorObj = {
msg: 'error',
result: 'no file name provided',
};
res.end(JSON.stringify(errorObj));
}
} else {
const errorObj = {
msg: 'error',
result: 'another job is in progress',
};
res.end(JSON.stringify(errorObj));
}
}
var cacheCallInProgress = false;
const cacheGlobLifetime = 600; // sec
// TODO: reset calls' states on new /cache call start
var mock = require('./mock');
var callStack = {};
const checkCallStack = function() {
let total = 0;
for (let coin in callStack) {
total =+ callStack[coin];
}
if (total / Object.keys(callStack).length === 1) {
cache.dumpCacheBeforeExit();
cacheCallInProgress = false;
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'done',
resp: 'success',
},
},
});
}
};
/*
* type: GET
* params: userpass, pubkey, coin, address, skip
*/
cache.one = function(req, res, next) {
if (req.query.pubkey &&
!fs.existsSync(`${cache.iguanaDir}/shepherd/cache-${req.query.pubkey}.json`)) {
cacheCallInProgress = false;
}
if (cacheCallInProgress) {
checkCallStack();
}
if (!cacheCallInProgress) {
cache.dumpCacheBeforeExit();
if (fs.existsSync(`${cache.iguanaDir}/shepherd/cache-${req.query.pubkey}.json`)) {
let _data = fs.readFileSync(`${cache.iguanaDir}/shepherd/cache-${req.query.pubkey}.json`, 'utf8');
if (_data) {
inMemCache = JSON.parse(_data);
_data = _data.replace('waiting', 'failed');
cache.dumpCacheBeforeExit();
}
}
// TODO: add check to allow only one cache call/sequence in progress
cacheCallInProgress = true;
let sessionKey = req.query.userpass;
let coin = req.query.coin;
let address = req.query.address;
let addresses = req.query.addresses && req.query.addresses.indexOf(':') > -1 ? req.query.addresses.split(':') : null;
let pubkey = req.query.pubkey;
let mock = req.query.mock;
let skipTimeout = req.query.skip;
let callsArray = req.query.calls.split(':');
let iguanaCorePort = req.query.port ? req.query.port : cache.appConfig.iguanaCorePort;
let errorObj = {
msg: 'error',
result: 'error',
};
let outObj = {};
const writeCache = function(timeStamp) {
if (timeStamp) {
outObj.timestamp = timeStamp;
}
inMemCache = outObj;
};
const checkTimestamp = function(dateToCheck) {
const currentEpochTime = new Date(Date.now()) / 1000;
const secondsElapsed = Number(currentEpochTime) - Number(dateToCheck / 1000);
return Math.floor(secondsElapsed);
};
let internalError = false;
inMemPubkey = pubkey;
callStack[coin] = 1;
cache.shepherd.log(callsArray);
cache.shepherd.log(`iguana core port ${iguanaCorePort}`);
if (!sessionKey) {
const errorObj = {
msg: 'error',
result: 'no session key provided',
};
res.end(JSON.stringify(errorObj));
internalError = true;
}
if (!pubkey) {
const errorObj = {
msg: 'error',
result: 'no pubkey provided',
};
res.end(JSON.stringify(errorObj));
internalError = true;
}
cache.shepherd.log('cache-one call started');
function fixJSON(data) {
if (data &&
data.length) {
try {
const parsedJSON = JSON.parse(data);
return parsedJSON;
} catch (e) {
cache.shepherd.log(e);
if (e.toString().indexOf('at position') > -1) {
const errorPos = e.toString().split(' ');
cache.shepherd.log(`JSON error ---> ${data.substring(errorPos[errorPos.length - 1] - 20, errorPos[errorPos.length - 1] + 20)} | error sequence: ${data.substring(errorPos[errorPos.length - 1], errorPos[errorPos.length - 1] + 1)}`);
cache.shepherd.log('attempting to recover JSON data');
return JSON.parse(data.substring(0, errorPos[errorPos.length - 1]));
}
if (e.toString().indexOf('Unexpected end of JSON input')) {
return {};
}
}
} else {
return {};
}
}
if (fs.existsSync(`${cache.iguanaDir}/shepherd/cache-${pubkey}.json`) &&
coin !== 'all') {
if (inMemCache) {
cache.shepherd.log('cache one from mem');
outObj = inMemCache;
} else {
const _file = fs.readFileSync(`${cache.iguanaDir}/shepherd/cache-${pubkey}.json`, 'utf8');
cache.shepherd.log('cache one from disk');
outObj = fixJSON(_file);
}
if (!outObj ||
!outObj.basilisk) {
cache.shepherd.log('no local basilisk info');
outObj['basilisk'] = {};
outObj['basilisk'][coin] = {};
} else {
if (!outObj['basilisk'][coin]) {
cache.shepherd.log('no local coin info');
outObj['basilisk'][coin] = {};
}
}
} else {
outObj['basilisk'] = {};
outObj['basilisk'][coin] = {};
}
res.end(JSON.stringify({
msg: 'success',
result: 'call is initiated',
}));
if (!internalError) {
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
},
},
});
function execDEXRequests(coin, address) {
let dexUrls = {
listunspent: `http://${cache.appConfig.host}:${iguanaCorePort}/api/dex/listunspent?userpass=${sessionKey}&symbol=${coin}&address=${address}`,
listtransactions: `http://${cache.appConfig.host}:${iguanaCorePort}/api/dex/listtransactions?userpass=${sessionKey}&count=100&skip=0&symbol=${coin}&address=${address}`,
getbalance: `http://${cache.appConfig.host}:${iguanaCorePort}/api/dex/getbalance?userpass=${sessionKey}&symbol=${coin}&address=${address}`,
refresh: `http://${cache.appConfig.host}:${iguanaCorePort}/api/basilisk/refresh?userpass=${sessionKey}&symbol=${coin}&address=${address}`
};
let _dexUrls = {};
for (let a = 0; a < callsArray.length; a++) {
_dexUrls[callsArray[a]] = dexUrls[callsArray[a]];
}
if (coin === 'BTC' ||
coin === 'SYS') {
delete _dexUrls.refresh;
delete _dexUrls.getbalance;
}
cache.shepherd.log(`${coin} address ${address}`);
if (!outObj.basilisk[coin][address]) {
outObj.basilisk[coin][address] = {};
writeCache();
}
// set current call status
async.forEachOf(_dexUrls, function(dexUrl, key) {
if (!outObj.basilisk[coin][address][key]) {
outObj.basilisk[coin][address][key] = {};
outObj.basilisk[coin][address][key].status = 'waiting';
} else {
outObj.basilisk[coin][address][key].status = 'waiting';
}
});
writeCache();
async.forEachOf(_dexUrls, function(dexUrl, key) {
var tooEarly = false;
if (outObj.basilisk[coin][address][key] &&
outObj.basilisk[coin][address][key].timestamp &&
(!skipTimeout && checkTimestamp(outObj.basilisk[coin][address][key].timestamp) < cacheGlobLifetime)) {
tooEarly = true;
outObj.basilisk[coin][address][key].status = 'done';
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
method: key,
coin: coin,
address: address,
status: 'done',
resp: 'too early',
},
},
},
});
}
if (!tooEarly) {
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
method: key,
coin: coin,
address: address,
status: 'in progress',
},
},
},
});
outObj.basilisk[coin][address][key].status = 'in progress';
request({
url: mock ? `http://localhost:17777/shepherd/mock?url=${dexUrl}` : dexUrl,
method: 'GET',
timeout: 30000,
}, function(error, response, body) {
if (response &&
response.statusCode &&
response.statusCode === 200) {
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
method: key,
coin: coin,
address: address,
status: 'done',
resp: body,
},
},
},
});
// basilisk fallback
const _parsedJSON = JSON.parse(body);
_explorerURL = {
getbalance: `http://kmd.explorer.supernet.org/api/addr/${address}/?noTxList=1`,
listtransactions: `https://kmd.explorer.supernet.org/api/txs?address=${address}&pageNum=0`
};
if ((key === 'getbalance' &&
coin === 'KMD' &&
((_parsedJSON && _parsedJSON.balance === 0) || body === [])) ||
(key === 'listtransactions' &&
coin === 'KMD' &&
(_parsedJSON === [] || !_parsedJSON.length))) {
cache.shepherd.log('fallback to kmd explorer ======>');
request({
url: _explorerURL[key],
method: 'GET'
}, function(error, response, _body) {
if (response &&
response.statusCode &&
response.statusCode === 200) {
let _parsedExplorerJSON = JSON.parse(_body);
_parsedExplorerJSON['source'] = 'explorer';
let _formattedTxs = [];
if (key === 'listtransactions' &&
_parsedExplorerJSON['txs'] &&
_parsedExplorerJSON['txs'].length) {
const _txList = _parsedExplorerJSON['txs'];
for (let i = 0; i < _txList.length; i++) {
_formattedTxs.push({
type: 'unknown',
height: _txList[i].blockheight,
confirmations: _txList[i].confirmations,
timestamp: _txList[i].time,
amount: _txList[i].vout[1].value,
txid: _txList[i].txid,
source: 'explorer',
});
}
_parsedExplorerJSON = _formattedTxs;
}
if ((key === 'getbalance' &&
Number(_parsedExplorerJSON.balance) !== Number(_parsedJSON.balance) &&
Number(_parsedExplorerJSON.txApperances) < 500) || key === 'listtransactions') {
body = JSON.stringify(_parsedExplorerJSON);
}
cache.io.emit('messages', {
'message': {
'shepherd': {
'method': 'cache-one',
'status': 'in progress',
'iguanaAPI': {
'method': key,
'coin': coin,
'address': address,
'status': 'done',
'resp': _body
}
}
}
});
outObj.basilisk[coin][address][key] = {};
outObj.basilisk[coin][address][key].data = JSON.parse(body);
outObj.basilisk[coin][address][key].timestamp = Date.now(); // add timestamp
outObj.basilisk[coin][address][key].status = 'done';
cache.shepherd.log(dexUrl);
cache.shepherd.log(body);
callStack[coin]--;
cache.shepherd.log(`${coin} _stack len ${callStack[coin]}`);
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
currentStackLength: callStack[coin],
},
},
},
});
checkCallStack();
writeCache();
} else {
cache.shepherd.log(`explorer ${key} for address ${address} fallback failed`);
}
});
} else {
outObj.basilisk[coin][address][key] = {};
outObj.basilisk[coin][address][key].data = JSON.parse(body);
outObj.basilisk[coin][address][key].timestamp = Date.now(); // add timestamp
outObj.basilisk[coin][address][key].status = 'done';
cache.shepherd.log(dexUrl);
cache.shepherd.log(body);
callStack[coin]--;
cache.shepherd.log(`${coin} _stack len ${callStack[coin]}`);
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
currentStackLength: callStack[coin],
},
},
},
});
checkCallStack();
writeCache();
}
}
if (error ||
!body ||
!response) {
// basilisk fallback
_explorerURL = {
getbalance: `http://kmd.explorer.supernet.org/api/addr/${address}/?noTxList=1`,
listtransactions: `https://kmd.explorer.supernet.org/api/txs?address=${address}&pageNum=0`
};
if ((key === 'getbalance' &&
coin === 'KMD') ||
(key === 'listtransactions' &&
coin === 'KMD')) {
cache.shepherd.log('fallback to kmd explorer ======>');
request({
url: _explorerURL[key],
method: 'GET'
}, function(error, response, _body) {
if (response &&
response.statusCode &&
response.statusCode === 200) {
let _parsedExplorerJSON = JSON.parse(_body);
_parsedExplorerJSON['source'] = 'explorer';
if ((key === 'getbalance' &&
Number(_parsedExplorerJSON.balance) !== Number(_parsedJSON.balance) &&
Number(_parsedExplorerJSON.txApperances) < 500) || key === 'listtransactions') {
body = JSON.stringify(_parsedExplorerJSON);
}
cache.io.emit('messages', {
'message': {
'shepherd': {
'method': 'cache-one',
'status': 'in progress',
'iguanaAPI': {
'method': key,
'coin': coin,
'address': address,
'status': 'done',
'resp': _body
}
}
}
});
outObj.basilisk[coin][address][key] = {};
outObj.basilisk[coin][address][key].data = JSON.parse(body);
outObj.basilisk[coin][address][key].timestamp = Date.now(); // add timestamp
outObj.basilisk[coin][address][key].status = 'done';
cache.shepherd.log(dexUrl);
cache.shepherd.log(body);
callStack[coin]--;
cache.shepherd.log(`${coin} _stack len ${callStack[coin]}`);
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
currentStackLength: callStack[coin],
},
},
},
});
checkCallStack();
writeCache();
} else {
cache.shepherd.log(`explorer ${key} for address ${address} fallback failed`);
outObj.basilisk[coin][address][key] = {};
outObj.basilisk[coin][address][key].data = { 'error': 'request failed' };
outObj.basilisk[coin][address][key].timestamp = 1471620867 // add timestamp
outObj.basilisk[coin][address][key].status = 'done';
callStack[coin]--;
cache.shepherd.log(`${coin} request ${key} for address ${address} failed`);
cache.shepherd.log(`${coin} _stack len ${callStack[coin]}`);
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
currentStackLength: callStack[coin],
},
},
},
});
checkCallStack();
writeCache();
}
});
} else {
outObj.basilisk[coin][address][key] = {};
outObj.basilisk[coin][address][key].data = { 'error': 'request failed' };
outObj.basilisk[coin][address][key].timestamp = 1471620867 // add timestamp
outObj.basilisk[coin][address][key].status = 'done';
callStack[coin]--;
cache.shepherd.log(`${coin} request ${key} for address ${address} failed`);
cache.shepherd.log(`${coin} _stack len ${callStack[coin]}`);
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
currentStackLength: callStack[coin],
},
},
},
});
checkCallStack();
writeCache();
}
}
});
} else {
cache.shepherd.log(`${key} is fresh, check back in ${(cacheGlobLifetime - checkTimestamp(outObj.basilisk[coin][address][key].timestamp))}s`);
callStack[coin]--;
cache.shepherd.log(`${coin} _stack len ${callStack[coin]}`);
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
currentStackLength: callStack[coin],
},
},
},
});
checkCallStack();
}
});
}
function parseAddresses(coin, addrArray) {
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
method: 'getaddressesbyaccount',
coin: coin,
status: 'done',
resp: addrArray,
},
},
},
});
outObj.basilisk[coin].addresses = addrArray;
cache.shepherd.log(addrArray);
writeCache();
const addrCount = outObj.basilisk[coin].addresses ? outObj.basilisk[coin].addresses.length : 0;
let callsArrayBTC = callsArray.length;
if (callsArray.indexOf('getbalance') > - 1) {
callsArrayBTC--;
}
if (callsArray.indexOf('refresh') > - 1) {
callsArrayBTC--;
}
callStack[coin] = callStack[coin] + addrCount * (coin === 'BTC' || coin === 'SYS' ? callsArrayBTC : callsArray.length);
cache.shepherd.log(`${coin} stack len ${callStack[coin]}`);
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
totalStackLength: callStack[coin],
},
},
},
});
async.each(outObj.basilisk[coin].addresses, function(address) {
execDEXRequests(coin, address);
});
}
function getAddresses(coin) {
if (addresses) {
parseAddresses(coin, addresses);
} else {
const tempUrl = `http://${cache.appConfig.host}:${cache.appConfig.iguanaCorePort}/api/bitcoinrpc/getaddressesbyaccount?userpass=${sessionKey}&coin=${coin}&account=*`;
request({
url: mock ? `http://localhost:17777/shepherd/mock?url=${tempUrl}` : tempUrl,
method: 'GET'
}, function(error, response, body) {
if (response &&
response.statusCode &&
response.statusCode === 200) {
parseAddresses(coin, JSON.parse(body).result);
} else {
// TODO: error
}
});
}
}
// update all available coin addresses
if (!address) {
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
method: 'getaddressesbyaccount',
coin: coin,
status: 'in progress',
},
},
},
});
if (coin === 'all') {
const tempUrl = `http://${cache.appConfig.host}:${cache.appConfig.iguanaCorePort}/api/InstantDEX/allcoins?userpass=${sessionKey}`;
request({
url: mock ? `http://localhost:17777/shepherd/mock?url=${tempUrl}` : tempUrl,
method: 'GET'
}, function(error, response, body) {
if (response &&
response.statusCode &&
response.statusCode === 200) {
cache.shepherd.log(JSON.parse(body).basilisk);
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
method: 'allcoins',
status: 'done',
resp: body,
},
},
},
});
body = JSON.parse(body);
// basilisk coins
if (body.basilisk &&
body.basilisk.length) {
// get coin addresses
async.each(body.basilisk, function(coin) {
callStack[coin] = 1;
});
async.each(body.basilisk, function(coin) {
outObj.basilisk[coin] = {};
writeCache();
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
method: 'getaddressesbyaccount',
coin: coin,
status: 'in progress',
},
},
},
});
getAddresses(coin);
});
}
}
if (error) { // stop further requests on failure, exit
callStack[coin] = 1;
checkCallStack();
}
});
} else {
getAddresses(coin);
}
} else {
let callsArrayBTC = callsArray.length; // restrict BTC and SYS only to listunspent and listtransactions calls
if (callsArray.indexOf('getbalance') > - 1) {
callsArrayBTC--;
}
if (callsArray.indexOf('refresh') > - 1) {
callsArrayBTC--;
}
callStack[coin] = callStack[coin] + (coin === 'BTC' || coin === 'SYS' ? callsArrayBTC : callsArray.length);
cache.shepherd.log(`${coin} stack len ${callStack[coin]}`);
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-one',
status: 'in progress',
iguanaAPI: {
totalStackLength: callStack[coin],
currentStackLength: callStack[coin],
},
},
},
});
execDEXRequests(coin, address);
}
} else {
cache.io.emit('messages', {
message: {
shepherd: {
method: 'cache-all',
status: 'done',
resp: 'internal error',
},
},
});
cacheCallInProgress = false;
}
} else {
res.end(JSON.stringify({
msg: 'error',
result: 'another call is in progress already',
}));
}
};
module.exports = cache;

347
routes/electrumjs/electrumjs.core.js

@ -0,0 +1,347 @@
/*
MIT License
Copyright (c) 2017 Yuki Akiyama, SuperNET
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
const tls = require('tls');
const net = require('net');
const EventEmitter = require('events').EventEmitter;
const makeRequest = function(method, params, id) {
return JSON.stringify({
jsonrpc : '2.0',
method : method,
params : params,
id : id,
});
}
const createRecursiveParser = function(maxDepth, delimiter) {
const MAX_DEPTH = maxDepth;
const DELIMITER = delimiter;
const recursiveParser = function(n, buffer, callback) {
if (buffer.length === 0) {
return {
code: 0,
buffer: buffer,
};
}
if (n > MAX_DEPTH) {
return {
code: 1,
buffer: buffer,
};
}
const xs = buffer.split(DELIMITER);
if (xs.length === 1) {
return {
code: 0,
buffer: buffer,
};
}
callback(xs.shift(), n);
return recursiveParser(n + 1, xs.join(DELIMITER), callback);
}
return recursiveParser;
}
const createPromiseResult = function(resolve, reject) {
return (err, result) => {
if (err) {
console.log('electrum error:');
console.log(err);
resolve(err);
// reject(err);
} else {
resolve(result);
}
}
}
class MessageParser {
constructor(callback) {
this.buffer = '';
this.callback = callback;
this.recursiveParser = createRecursiveParser(20, '\n');
}
run(chunk) {
this.buffer += chunk;
while (true) {
const res = this.recursiveParser(0, this.buffer, this.callback);
this.buffer = res.buffer;
if (res.code === 0) {
break;
}
}
}
}
const util = {
makeRequest,
createRecursiveParser,
createPromiseResult,
MessageParser,
};
const getSocket = function(protocol, options) {
switch (protocol) {
case 'tcp':
return new net.Socket();
case 'tls':
// todo
case 'ssl':
return new tls.TLSSocket(options);
}
throw new Error('unknown protocol');
}
const initSocket = function(self, protocol, options) {
const conn = getSocket(protocol, options);
conn.setEncoding('utf8');
conn.setKeepAlive(true, 0);
conn.setNoDelay(true);
conn.on('connect', () => {
self.onConnect();
});
conn.on('close', (e) => {
self.onClose(e);
});
conn.on('data', (chunk) => {
self.onReceive(chunk);
});
conn.on('end', (e) => {
self.onEnd(e);
});
conn.on('error', (e) => {
self.onError(e);
});
return conn;
}
class Client {
constructor(port, host, protocol = 'tcp', options = void 0) {
this.id = 0;
this.port = port;
this.host = host;
this.callbackMessageQueue = {};
this.subscribe = new EventEmitter();
this.conn = initSocket(this, protocol, options);
this.mp = new util.MessageParser((body, n) => {
this.onMessage(body, n);
});
this.status = 0;
}
connect() {
if (this.status) {
return Promise.resolve();
}
this.status = 1;
return new Promise((resolve, reject) => {
const errorHandler = (e) => reject(e)
this.conn.connect(this.port, this.host, () => {
this.conn.removeListener('error', errorHandler);
resolve();
});
this.conn.on('error', errorHandler);
});
}
close() {
if (!this.status) {
return
}
this.conn.end();
this.conn.destroy();
this.status = 0;
}
request(method, params) {
if (!this.status) {
return Promise.reject(new Error('ESOCKET'));
}
return new Promise((resolve, reject) => {
const id = ++this.id;
const content = util.makeRequest(method, params, id);
this.callbackMessageQueue[id] = util.createPromiseResult(resolve, reject);
this.conn.write(`${content}\n`);
});
}
response(msg) {
const callback = this.callbackMessageQueue[msg.id];
if (callback) {
delete this.callbackMessageQueue[msg.id];
if (msg.error) {
callback(msg.error);
} else {
callback(null, msg.result);
}
} else {
// can't get callback
}
}
onMessage(body, n) {
const msg = JSON.parse(body);
if (msg instanceof Array) {
// don't support batch request
} else {
if (msg.id !== void 0) {
this.response(msg);
} else {
this.subscribe.emit(msg.method, msg.params);
}
}
}
onConnect() {
}
onClose() {
Object.keys(this.callbackMessageQueue).forEach((key) => {
this.callbackMessageQueue[key](new Error('close connect'));
delete this.callbackMessageQueue[key];
});
}
onReceive(chunk) {
this.mp.run(chunk);
}
onEnd() {
}
onError(e) {
}
}
class ElectrumJSCore extends Client {
constructor(protocol, port, host, options) {
super(protocol, port, host, options);
}
onClose() {
super.onClose();
const list = [
'server.peers.subscribe',
'blockchain.numblocks.subscribe',
'blockchain.headers.subscribe',
'blockchain.address.subscribe'
];
list.forEach(event => this.subscribe.removeAllListeners(event));
}
// ref: http://docs.electrum.org/en/latest/protocol.html
serverVersion(client_name, protocol_version) {
return this.request('server.version', [client_name, protocol_version]);
}
serverBanner() {
return this.request('server.banner', []);
}
serverDonationAddress() {
return this.request('server.donation_address', []);
}
serverPeersSubscribe() {
return this.request('server.peers.subscribe', []);
}
blockchainAddressGetBalance(address) {
return this.request('blockchain.address.get_balance', [address]);
}
blockchainAddressGetHistory(address) {
return this.request('blockchain.address.get_history', [address]);
}
blockchainAddressGetMempool(address) {
return this.request('blockchain.address.get_mempool', [address]);
}
blockchainAddressListunspent(address) {
return this.request('blockchain.address.listunspent', [address]);
}
blockchainBlockGetHeader(height) {
return this.request('blockchain.block.get_header', [height]);
}
blockchainBlockGetChunk(index) {
return this.request('blockchain.block.get_chunk', [index]);
}
blockchainEstimatefee(number) {
return this.request('blockchain.estimatefee', [number]);
}
blockchainHeadersSubscribe() {
return this.request('blockchain.headers.subscribe', []);
}
blockchainNumblocksSubscribe() {
return this.request('blockchain.numblocks.subscribe', []);
}
blockchainRelayfee() {
return this.request('blockchain.relayfee', []);
}
blockchainTransactionBroadcast(rawtx) {
return this.request('blockchain.transaction.broadcast', [rawtx]);
}
blockchainTransactionGet(tx_hash, height) {
return this.request('blockchain.transaction.get', [tx_hash, height]);
}
blockchainTransactionGetMerkle(tx_hash, height) {
return this.request('blockchain.transaction.get_merkle', [tx_hash, height]);
}
}
module.exports = ElectrumJSCore;

205
routes/electrumjs/electrumjs.networks.js

@ -0,0 +1,205 @@
'use strict'
var bitcoin = require('bitcoinjs-lib');
var networks = exports;
Object.keys(bitcoin.networks).forEach(function(key){
networks[key] = bitcoin.networks[key]
});
networks.litecoin = {
messagePrefix: '\x19Litecoin Signed Message:\n',
bip32: {
public: 0x019da462,
private: 0x019d9cfe
},
pubKeyHash: 0x30,
scriptHash: 0x32,
wif: 0xb0,
dustThreshold: 0, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L360-L365
}
networks.dogecoin = {
messagePrefix: '\x19Dogecoin Signed Message:\n',
bip32: {
public: 0x02facafd,
private: 0x02fac398,
},
pubKeyHash: 0x1e,
scriptHash: 0x16,
wif: 0x9e,
dustThreshold: 0 // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160
};
// https://github.com/monacoinproject/monacoin/blob/master-0.10/src/chainparams.cpp#L161
networks.monacoin = {
messagePrefix: '\x19Monacoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x32,
scriptHash: 0x05,
wif: 0xB2,
dustThreshold: 546, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162
};
// https://github.com/gamecredits-project/GameCredits/blob/master/src/chainparams.cpp#L136
networks.game = {
messagePrefix: '\x19GameCredits Signed Message:\n',
bip32: {
public: 0x043587cf,
private: 0x04358394,
},
pubKeyHash: 0x6f,
scriptHash: 0xc4,
wif: 0xef,
dustThreshold: 546, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162
};
// https://github.com/dashpay/dash/blob/master/src/chainparams.cpp#L171
networks.dash = {
messagePrefix: '\x19DarkCoin Signed Message:\n',
bip32: {
public: 0x02fe52f8,
private: 0x02fe52cc,
},
pubKeyHash: 0x4c,
scriptHash: 0x10,
wif: 0xcc,
dustThreshold: 5460, // https://github.com/dashpay/dash/blob/v0.12.0.x/src/primitives/transaction.h#L144-L155
};
// https://github.com/zcoinofficial/zcoin/blob/c93eccb39b07a6132cb3d787ac18be406b24c3fa/src/base58.h#L275
networks.zcoin = {
messagePrefix: '\x19ZCoin Signed Message:\n',
bip32: {
public: 0x0488b21e, // todo
private: 0x0488ade4, // todo
},
pubKeyHash: 0x52,
scriptHash: 0x07,
wif: 0x52 + 128,
dustThreshold: 1000, // https://github.com/zcoinofficial/zcoin/blob/f755f95a036eedfef7c96bcfb6769cb79278939f/src/main.h#L59
};
// https://raw.githubusercontent.com/jl777/komodo/beta/src/chainparams.cpp
networks.komodo = {
messagePrefix: '\x19Komodo Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x3c,
scriptHash: 0x55,
wif: 0xbc,
dustThreshold: 1000,
};
networks.viacoin = {
messagePrefix: '\x19Viacoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x47,
scriptHash: 0x21,
wif: 0xc7,
dustThreshold: 1000,
};
networks.vertcoin = {
messagePrefix: '\x19Vertcoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x47,
scriptHash: 0x5,
wif: 0x80,
dustThreshold: 1000,
};
networks.namecoin = {
messagePrefix: '\x19Namecoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x34,
scriptHash: 0xd,
wif: 0xb4,
dustThreshold: 1000,
};
networks.faircoin = {
messagePrefix: '\x19Faircoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x5f,
scriptHash: 0x24,
wif: 0xdf,
dustThreshold: 1000,
};
networks.digibyte = {
messagePrefix: '\x19Digibyte Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x1e,
scriptHash: 0x5,
wif: 0x80,
dustThreshold: 1000,
};
networks.crown = {
messagePrefix: '\x19Crown Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x0,
scriptHash: 0x1c,
wif: 0x80,
dustThreshold: 1000,
};
networks.argentum = {
messagePrefix: '\x19Argentum Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x17,
scriptHash: 0x5,
wif: 0x97,
dustThreshold: 1000,
};
networks.chips = {
messagePrefix: '\x19Chips Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x3c,
scriptHash: 0x55,
wif: 0xbc,
dustThreshold: 1000,
};
/*networks.zcash = {
messagePrefix: '\x19Zcash Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x1cb8,
scriptHash: 0x1cbd,
wif: 0x80,
dustThreshold: 1000,
};*/

120
routes/electrumjs/electrumjs.txdecoder.js

@ -0,0 +1,120 @@
/*
MIT License
Copyright (c) 2017 Yuki Akiyama, SuperNET
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
var bitcoin = require('bitcoinjs-lib');
var decodeFormat = function(tx) {
var result = {
txid: tx.getId(),
version: tx.version,
locktime: tx.locktime,
};
return result;
}
var decodeInput = function(tx) {
var result = [];
tx.ins.forEach(function(input, n) {
var vin = {
txid: input.hash.reverse().toString('hex'),
n: input.index,
script: bitcoin.script.toASM(input.script),
sequence: input.sequence,
};
result.push(vin);
});
return result;
}
var decodeOutput = function(tx, network) {
var format = function(out, n, network) {
var vout = {
satoshi: out.value,
value: (1e-8 * out.value).toFixed(8),
n: n,
scriptPubKey: {
asm: bitcoin.script.toASM(out.script),
hex: out.script.toString('hex'),
type: bitcoin.script.classifyOutput(out.script),
addresses: [],
},
};
switch(vout.scriptPubKey.type) {
case 'pubkeyhash':
vout.scriptPubKey.addresses.push(bitcoin.address.fromOutputScript(out.script, network));
break;
case 'pubkey':
const pubKeyBuffer = new Buffer(vout.scriptPubKey.asm.split(' ')[0], 'hex');
vout.scriptPubKey.addresses.push(bitcoin.ECPair.fromPublicKeyBuffer(pubKeyBuffer, network).getAddress());
break;
case 'scripthash':
vout.scriptPubKey.addresses.push(bitcoin.address.fromOutputScript(out.script, network));
break;
}
return vout;
}
var result = [];
tx.outs.forEach(function(out, n) {
result.push(format(out, n, network));
});
return result;
}
var TxDecoder = module.exports = function(rawtx, network) {
try {
const _tx = bitcoin.Transaction.fromHex(rawtx);
return {
tx: _tx,
network: network,
format: decodeFormat(_tx),
inputs: decodeInput(_tx),
outputs: decodeOutput(_tx, network),
};
} catch (e) {
return false;
}
}
TxDecoder.prototype.decode = function() {
var result = {};
var self = this;
Object.keys(self.format).forEach(function(key) {
result[key] = self.format[key];
});
result.outputs = self.outputs;
return result;
}

45
routes/mock.js

@ -1,45 +0,0 @@
const fs = require('fs-extra'),
request = require('request'),
async = require('async'),
url = require('url');
let mock = {};
mock.setVar = function(variable, value) {
mock[variable] = value;
}
mock.get = function(req, res, next) {
const _url = req.query.url;
if (_url.indexOf('/InstantDEX/allcoins') > -1) {
res.end(JSON.stringify({
'native': [],
'basilisk': [ 'KMD', 'BTC'],
'full':[],
'tag': '18430609759584422959'
}));
}
if (_url.indexOf('/bitcoinrpc/getaddressesbyaccount') > -1) {
console.log(_url.indexOf('/bitcoinrpc/getaddressesbyaccount'));
res.end(JSON.stringify({
'result': [
"RDbGxL8QYdEp8sMULaVZS2E6XThcTKT9Jd",
"RL4orv22Xch7PhM5w9jUHhVQhX6kF6GkfS",
"RUrxvPTEKGWEDTvAtgiqbUTTFE53Xdpj8a",
"RPJoLDa7RezvfUUBr7R3U8wrP16AgUsNw3",
"RQPTpRJEeafNx5hkDzgjcsPyU4E8RFVApT"
]
}));
}
if (_url.indexOf('/api/dex/listunspent') > -1 ||
_url.indexOf('/api/dex/listtransactions') > -1 ||
_url.indexOf('/api/ss/getbalance') > -1 ||
_url.indexOf('/api/ww/refresh') > -1) {
res.end(JSON.stringify({
'some key': 'some value'
}));
}
}
module.exports = mock;

98
routes/nativeCoind.js

@ -0,0 +1,98 @@
const nativeCoind = {
'btc': {
name: 'Bitcoin',
bin: 'bitcoin',
fullMode: true,
port: 8332,
},
'btcd': {
name: 'BitcoinDark',
bin: 'bitcoindarkd',
fullMode: true,
port: 14632,
},
'ltc': {
name: 'Litecoin',
bin: 'litecoin',
fullMode: true,
port: 9332,
},
'sys': {
name: 'Syscoin',
bin: 'syscoin',
fullMode: true,
port: 8368,
},
'uno': {
name: 'Unobtanium',
bin: 'unobtanium',
fullMode: true,
port: 65535,
},
'nmc': {
name: 'Namecoin',
bin: 'namecoin',
fullMode: true,
port: 8336,
},
'game': {
name: 'GameCredits',
bin: 'gamecredits',
fullMode: true,
port: 40001,
},
'mzc': {
name: 'MazaCoin',
bin: 'maza',
fullMode: true,
port: 12832,
},
'frk': {
name: 'Franko',
bin: 'franko',
fullMode: true,
port: 7913,
},
'doge': {
name: 'Dogecoin',
bin: 'dogecoin',
fullMode: true,
port: 22555,
},
'dgb': {
name: 'Digibyte',
bin: 'digibyte',
port: 14022,
},
'zet': {
name: 'Zetacoin',
bin: 'zetacoin',
fullMode: true,
port: 17335,
},
'btm': {
name: 'Bitmark',
bin: 'bitmark',
fullMode: true,
port: 9266,
},
'carb': {
name: 'Carboncoin',
bin: 'carboncoin',
fullMode: true,
port: 9351,
},
'anc': {
name: 'Anoncoin',
bin: 'anoncoin',
fullMode: true,
port: 28332,
},
'lbc': {
name: 'LBRY Credits',
bin: 'lbrycrd',
port: 9245,
}
};
module.exports = nativeCoind;

2
routes/ports.js

@ -1,7 +1,9 @@
const assetChainPorts = {
'komodod': '7771',
'CHIPS': '57776',
'SUPERNET': '11341',
'REVS': '10196',
'MNZ': '14337',
'WLC': '12167',
'PANGEA': '14068',
'DEX': '11890',

4858
routes/shepherd.js

File diff suppressed because it is too large

2
version

@ -1,3 +1,3 @@
version=0.2.0.22a
version=0.2.0.23a
type=e-beta
minversion=0.2.0.2

2
version_build

@ -1 +1 @@
0.2.0.22a-beta
0.2.0.23a-beta

Loading…
Cancel
Save