Browse Source

Merge pull request #2 from KomodoPlatform/dev

Dev
dev
siulynot 7 years ago
committed by GitHub
parent
commit
da3ff81e10
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      AgamaApp-windows.md
  2. 8
      README.md
  3. 2
      gui/EasyDEX-GUI
  4. 8
      main.js
  5. 13
      package.json
  6. 51
      routes/electrumjs/electrumServers.js
  7. 551
      routes/electrumjs/electrumjs.networks.js
  8. 2
      routes/shepherd.js
  9. 15
      routes/shepherd/addCoinShortcuts.js
  10. 12
      routes/shepherd/binsUtils.js
  11. 11
      routes/shepherd/coindWalletKeys.js
  12. 8
      routes/shepherd/coinsList.js
  13. 5
      routes/shepherd/confMaxconnections.js
  14. 21
      routes/shepherd/config.js
  15. 16
      routes/shepherd/daemonControl.js
  16. 16
      routes/shepherd/dashboardUpdate.js
  17. 12
      routes/shepherd/debugLog.js
  18. 19
      routes/shepherd/downloadBins.js
  19. 28
      routes/shepherd/downloadPatch.js
  20. 7
      routes/shepherd/downloadUtil.js
  21. 16
      routes/shepherd/downloadZcparams.js
  22. 47
      routes/shepherd/elections.js
  23. 10
      routes/shepherd/electrum/balance.js
  24. 6
      routes/shepherd/electrum/block.js
  25. 115
      routes/shepherd/electrum/btcFees.js
  26. 30
      routes/shepherd/electrum/createtx-multi.js
  27. 5
      routes/shepherd/electrum/createtx-split.js
  28. 16
      routes/shepherd/electrum/createtx.js
  29. 235
      routes/shepherd/electrum/insight.js
  30. 8
      routes/shepherd/electrum/keys.js
  31. 29
      routes/shepherd/electrum/listunspent.js
  32. 21
      routes/shepherd/electrum/merkle.js
  33. 24
      routes/shepherd/electrum/network.js
  34. 36
      routes/shepherd/electrum/transactions.js
  35. 2
      routes/shepherd/init.js
  36. 17
      routes/shepherd/log.js
  37. 1
      routes/shepherd/quitDaemon.js
  38. 15
      routes/shepherd/rpc.js
  39. 6
      version
  40. 2
      version_build

12
AgamaApp-windows.md

@ -1,12 +0,0 @@
# Agama application build summary is here:
Platform: windows
Version: 0.2.0.1a-beta
Date: Mon Jun 12 11:57:21 CEST 2017
Download link:
* [https://f001.backblazeb2.com/file/supernet/files/AgamaApp-0.2.0.1a-beta-windows-installer.zip](https://f001.backblazeb2.com/file/supernet/files/AgamaApp-0.2.0.1a-beta-windows-installer.zip)
* [checksum](https://f001.backblazeb2.com/file/supernet/files/AgamaApp-0.2.0.1a-beta-windows.checksum)

8
README.md

@ -78,3 +78,11 @@ change architecture build parameter to ```--arch=x64``` for 64 bit build
On Windows it's noticed iguana.exe complains about `VCRUNTIME140D.DLL` and `ucrtbased.dll` file.
Please see **windeps** directory and README file for instructions to install the required DLL files on Windows, and then try again running Agama App.
## Optional packages to make rpm and deb distros
electron-installer-debian
electron-installer-redhat
refer to ./make-deb.js and ./make-rpm.js

2
gui/EasyDEX-GUI

@ -1 +1 @@
Subproject commit 54f9dfc6e7b519a5a2295b49813cfd99be131cae
Subproject commit b9b1283f55561064794a7ba58bc8ae4371b106fc

8
main.js

@ -7,6 +7,7 @@ const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const url = require('url');
const os = require('os');
const { randomBytes } = require('crypto');
const md5 = require('./routes/md5');
const exec = require('child_process').exec;
const { Menu } = require('electron');
@ -54,7 +55,7 @@ app.setVersion(appBasicInfo.version);
shepherd.createAgamaDirs();
const appSessionHash = md5(Date.now().toString());
const appSessionHash = randomBytes(32).toString('hex');
const _spvFees = shepherd.getSpvFees();
shepherd.writeLog(`app info: ${appBasicInfo.name} ${appBasicInfo.version}`);
@ -70,6 +71,7 @@ shepherd.writeLog(`os_type: ${os.type()}`);
if (process.argv.indexOf('devmode') > -1) {
shepherd.log(`app init ${appSessionHash}`);
}
shepherd.log(`app info: ${appBasicInfo.name} ${appBasicInfo.version}`);
shepherd.log('sys info:');
shepherd.log(`totalmem_readable: ${formatBytes(os.totalmem())}`);
@ -100,7 +102,7 @@ guiapp.use((req, res, next) => {
next();
});
// preload.js
// preload js
const _setImmediate = setImmediate;
const _clearImmediate = clearImmediate;
@ -462,8 +464,6 @@ app.on('quit', (event) => {
}
});
app.commandLine.appendSwitch('ignore-certificate-errors'); // dirty hack
function formatBytes(bytes, decimals) {
if (bytes === 0) {
return '0 Bytes';

13
package.json

@ -1,7 +1,7 @@
{
"name": "agama-app",
"productName": "Agama",
"version": "0.2.29",
"version": "0.2.30",
"description": "Agama Wallet Desktop App",
"main": "main.js",
"scripts": {
@ -11,21 +11,20 @@
"make-deb": "node make-deb.js"
},
"repository": "https://github.com/KomodoPlatform/Agama/",
"homepage": "http://supernet.org",
"homepage": "http://komodoplatform.com",
"keywords": [
"agama",
"SuperNET",
"komodo",
"multicoin",
"wallet",
"spv"
"spv",
"jumblr"
],
"author": "SuperNET Team",
"license": "MIT",
"devDependencies": {
"electron": "1.7.10",
"electron-installer-debian": "^0.6.0",
"electron-installer-redhat": "^0.5.0"
"electron": "1.8.4"
},
"dependencies": {
"adm-zip": "^0.4.7",
@ -41,7 +40,7 @@
"body-parser": "^1.15.2",
"buffer-reverse": "^1.0.1",
"coinselect": "github:bitcoinjs/coinselect",
"electron": "1.8.2",
"electron": "1.8.4",
"express": "^4.14.0",
"fix-path": "^2.1.0",
"fs-extra": "^4.0.2",

51
routes/electrumjs/electrumServers.js

@ -214,12 +214,15 @@ let electrumServers = {
],
},
ninja: { // !estimatefee
address: 'electrum.fund.ninja',
address: 'electrum1.fund.ninja',
port: 50001,
proto: 'tcp',
txfee: 10000,
abbr: 'NINJA',
serverList: 'none',
serverList: [
'electrum1.fund.ninja:50001',
'electrum2.fund.ninja:50001'
],
},
jumblr: { // !estimatefee
address: 'electrum1.cipig.net',
@ -457,6 +460,17 @@ let electrumServers = {
'136.243.45.140:50013'
],
},
sng: { // ssl 50002
address: 'electrumsvr.snowgem.org',
port: 50001,
proto: 'tcp',
txfee: 10000,
abbr: 'SNG',
serverList: [
'electrumsvr.snowgem.org:50001',
'electrumsvr.snowgem.org:50001'
],
},
xmy: {
address: 'cetus.cryptap.us',
port: 50004,
@ -534,6 +548,39 @@ let electrumServers = {
's2.qtum.info:50001'
],
},
// insight
aby: {
address: 'http://explorer.artbyte.me/api/',
proto: 'insight',
insightRawApi: false,
txfee: 100000,
abbr: 'ABY',
serverList: 'none',
},
mac: { // cloudfare captcha :(
address: 'https://explorer.machinecoin.org/api/',
proto: 'insight',
insightRawApi: false,
txfee: 100000,
abbr: 'MAC',
serverList: 'none',
},
vot: {
address: 'http://explorer.votecoin.site/insight-api-zcash/',
proto: 'insight',
insightRawApi: false,
txfee: 10000,
abbr: 'VOT',
serverList: 'none',
},
bdl: {
address: 'https://explorer.bitdeal.co.in/api/',
proto: 'insight',
insightRawApi: false,
txfee: 10000,
abbr: 'BDL',
serverList: 'none',
},
};
electrumServers.crw = electrumServers.crown;

551
routes/electrumjs/electrumjs.networks.js

@ -56,18 +56,16 @@ networks.monacoin = {
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,
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x6f,
scriptHash: 0xc4,
wif: 0xef,
dustThreshold: 546, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162
pubKeyHash: 0x26,
scriptHash: 0x5,
wif: 0xA6,
dustThreshold: 546,
};
// https://github.com/dashpay/dash/blob/master/src/chainparams.cpp#L171
@ -84,11 +82,11 @@ networks.dash = {
};
// https://github.com/zcoinofficial/zcoin/blob/c93eccb39b07a6132cb3d787ac18be406b24c3fa/src/base58.h#L275
networks.zcoin = {
networks.xzc = {
messagePrefix: '\x19ZCoin Signed Message:\n',
bip32: {
public: 0x0488b21e, // todo
private: 0x0488ade4, // todo
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x52,
scriptHash: 0x07,
@ -290,6 +288,18 @@ networks.zcl = {
dustThreshold: 1000,
};
networks.sng = {
messagePrefix: '\x19Snowgem Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x05358394,
},
pubKeyHash: 0x1c28,
scriptHash: 0x1c2D,
wif: 0x80,
dustThreshold: 1000,
};
networks.xmy = {
messagePrefix: '\x19Myriad Signed Message:\n',
bip32: {
@ -362,6 +372,525 @@ networks.grs = { // fails to gen a proper addr
dustThreshold: 1000,
};
networks.aby = {
messagePrefix: '\x19ArtByte Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x17,
scriptHash: 0x5,
wif: 0x97,
dustThreshold: 1000,
};
networks.mac = {
messagePrefix: '\x19Machinecoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x32,
scriptHash: 0x5,
wif: 0xB2,
dustThreshold: 1000,
};
networks.vot = {
messagePrefix: '\x19VoteCoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x05358394,
},
pubKeyHash: 0x1cb8,
scriptHash: 0x1cbd,
wif: 0x80,
dustThreshold: 1000,
};
networks.iop = {
messagePrefix: '\x19IOP Signed Message:\n',
bip32: {
public: 0x2780915F,
private: 0xAE3416F6,
},
pubKeyHash: 0x75,
scriptHash: 0xAE,
wif: 0x31,
dustThreshold: 1000,
};
networks.bdl = {
messagePrefix: '\x19Bitdeal Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x26,
scriptHash: 0x5,
wif: 0xB0,
dustThreshold: 1000,
};
networks.btcp = {
messagePrefix: '\x19BitcoinPrivate Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x1325,
scriptHash: 0x13AF,
wif: 0x80,
dustThreshold: 1000,
};
// https://github.com/zencashio/zen/blob/master/src/chainparams.cpp#L118
networks.zen = { // new address type
messagePrefix: '\x19Zencashio Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x2089,
scriptHash: 0x2086,
wif: 0x80,
dustThreshold: 1000,
};
networks.sys = { // zec based
messagePrefix: '\x19Syscoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x3F,
scriptHash: 0x5,
wif: 0x80,
dustThreshold: 1000,
};
networks.emc2 = {
messagePrefix: '\x19Einsteinium Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x21,
scriptHash: 0x5,
wif: 0x37,
dustThreshold: 1000,
};
// https://github.com/BTA-BATA/BATA-SOURCE/blob/master/src/chainparams.cpp#L156
networks.bta = {
messagePrefix: '\x19Bata Signed Message:\n',
bip32: {
public: 0xA40C86FA,
private: 0xA40B91BD,
},
pubKeyHash: 0x19,
scriptHash: 0x5,
wif: 0x55,
dustThreshold: 1000,
};
// https://github.com/EuropecoinEUORG/Europecoin-V3/blob/master/src/chainparams.cpp#L139
networks.erc = {
messagePrefix: '\x19Europecoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x21,
scriptHash: 0x5,
wif: 0x28 + 128,
dustThreshold: 1000,
};
// https://github.com/lbryio/lbrycrd/blob/master/src/chainparams.cpp#L176
networks.lbc = {
messagePrefix: '\x19LBRY Credits Signed Message:\n',
bip32: {
public: 0x019C354f,
private: 0x019C3118,
},
pubKeyHash: 0x55,
scriptHash: 0x7a,
wif: 0x1c,
dustThreshold: 1000,
};
// https://github.com/LIMXTEC/BitSend/blob/master/src/chainparams.cpp#L136
networks.bsd = {
messagePrefix: '\x19Bitsend Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x66,
scriptHash: 0x5,
wif: 0xCC,
dustThreshold: 1000,
};
// https://github.com/gobytecoin/gobyte/blob/master/src/chainparams.cpp#L127
networks.gbx = {
messagePrefix: '\x19GoByte Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x26,
scriptHash: 0xA,
wif: 0xC6,
dustThreshold: 1000,
};
// https://github.com/Electronic-Gulden-Foundation/egulden/blob/master/src/chainparams.cpp#L139
networks.efl = {
messagePrefix: '\x19E-Gulden Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x30,
scriptHash: 0x5,
wif: 0xB0,
dustThreshold: 1000,
};
// https://github.com/Whitecoin-org/whitecoin/blob/master/src/chainparams.cpp#L91
networks.xwc = { // wrong address generated
messagePrefix: '\x19Whitecoin Signed Message:\n',
bip32: {
public: 0x043587CF,
private: 0x04358394,
},
pubKeyHash: 0x6F,
scriptHash: 0xC4,
wif: 0xEF,
dustThreshold: 1000,
};
// https://github.com/vivocoin/vivo/blob/master/src/chainparams.cpp#L133
networks.vivo = {
messagePrefix: '\x19Vivo Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x46,
scriptHash: 0xA,
wif: 0xC6,
dustThreshold: 1000,
};
networks.xvg = {
messagePrefix: '\x19Verge Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x1e,
scriptHash: 0x9e,
wif: 0x6,
dustThreshold: 1000,
};
networks.vcash = { // wrong address generated
messagePrefix: '\x19Vcash Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x47,
scriptHash: 0xc7,
wif: 0x6,
dustThreshold: 1000,
};
// https://github.com/unobtanium-official/Unobtanium/blob/master/src/chainparams.cpp#L157
networks.uno = {
messagePrefix: '\x19Unobtanium Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x82,
scriptHash: 0x1E,
wif: 0xBF,
dustThreshold: 1000,
};
networks.smart = { // wrong address generated
messagePrefix: '\x19Smartcash Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x3F,
scriptHash: 0x12,
wif: 0xBF,
dustThreshold: 1000,
};
// https://github.com/reddcoin-project/reddcoin/blob/master/src/chainparams.cpp#L79
networks.rdd = {
messagePrefix: '\x19Reddcoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x3D,
scriptHash: 0x5,
wif: 0xBD,
dustThreshold: 1000,
};
// https://github.com/PIVX-Project/PIVX/blob/master/src/chainparams.cpp#L180
networks.pivx = {
messagePrefix: '\x19Pivx Signed Message:\n',
bip32: {
public: 0x022D2533,
private: 0x0221312B,
},
pubKeyHash: 0x1E,
scriptHash: 0xD,
wif: 0xD4,
dustThreshold: 1000,
};
// https://github.com/OmniLayer/omnicore/blob/master/src/chainparams.cpp#L128
networks.omni = {
messagePrefix: '\x19OmniLayer Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x0,
scriptHash: 0x5,
wif: 0x80,
dustThreshold: 1000,
};
networks.ok = {
messagePrefix: '\x19OKCash Signed Message:\n',
bip32: {
public: 0x03CC23D7,
private: 0x03CC1C73,
},
pubKeyHash: 0x37,
scriptHash: 0x1C,
wif: 0xB7,
dustThreshold: 1000,
};
networks.neos = {
messagePrefix: '\x19Neoscoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x35,
scriptHash: 0x5,
wif: 0xB1,
dustThreshold: 1000,
};
// https://github.com/NAVCoin/navcoin-core/blob/master/src/chainparams.cpp#L160
networks.nav = {
messagePrefix: '\x19Navcoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x35,
scriptHash: 0x55,
wif: 0x96,
dustThreshold: 1000,
};
// https://github.com/minexcoin/minexcoin/blob/master/src/chainparams.cpp#L259
networks.mnx = {
messagePrefix: '\x19Minexcoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x4B,
scriptHash: 0x5,
wif: 0x80,
dustThreshold: 1000,
};
networks.lcc = {
messagePrefix: '\x19Litecoin Cash Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x1C,
scriptHash: 0x5,
wif: 0x32,
dustThreshold: 1000,
};
// https://github.com/Gulden/gulden-official/blob/master/src/chainparams.cpp#L128
networks.nlg = {
messagePrefix: '\x19Gulden Cash Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x26,
scriptHash: 0x62,
wif: 0x26 + 128,
dustThreshold: 1000,
};
// https://github.com/fujicoin/fujicoin/blob/master/src/chainparams.cpp#L132
networks.fjc = {
messagePrefix: '\x19Fujicoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x24,
scriptHash: 0x10,
wif: 0xA4,
dustThreshold: 1000,
};
// https://github.com/flash-coin/bitcore-lib/commit/97d72267f3577173ee90d46b43553af801b214f2#diff-014a66be6f0ee0e90f9357d497267195R144
networks.flash = {
messagePrefix: '\x19Flash Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x44,
scriptHash: 0x82,
wif: 0xc4,
dustThreshold: 1000,
};
// https://github.com/FeatherCoin/Feathercoin/blob/master-0.13/src/chainparams.cpp#L132
networks.ftc = {
messagePrefix: '\x19FeatherCoin Signed Message:\n',
bip32: {
public: 0x048BC26,
private: 0x0488DAEE,
},
pubKeyHash: 0xE,
scriptHash: 0x5,
wif: 0x8E,
dustThreshold: 1000,
};
// https://github.com/exclfork/ExclusiveCoin/blob/master/src/chainparams.cpp#L82
networks.excl = {
messagePrefix: '\x19ExclusiveCoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x21,
scriptHash: 0x89,
wif: 0xA1,
dustThreshold: 1000,
};
// https://github.com/DMDcoin/Diamond/blob/master/src/chainparams.cpp#L166
networks.dmd = {
messagePrefix: '\x19Diamond Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x5A,
scriptHash: 0x8,
wif: 0xDA,
dustThreshold: 1000,
};
// https://github.com/CooleRRSA/crave/blob/master/src/chainparams.cpp#L99
networks.crave = { // wrong address generated, another fork is used?
messagePrefix: '\x19Crave Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x1B,
scriptHash: 0x55,
wif: 0x99,
dustThreshold: 1000,
};
// https://github.com/BitClubDev/ClubCoin/blob/master/src/chainparams.cpp#L114
networks.club = {
messagePrefix: '\x19ClubCoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x1C,
scriptHash: 0x55,
wif: 0x99,
dustThreshold: 1000,
};
// https://github.com/nochowderforyou/clams/blob/master/src/chainparams.cpp#L93
networks.clam = {
messagePrefix: '\x19Clams Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x89,
scriptHash: 0xD,
wif: 0x85,
dustThreshold: 1000,
};
// https://github.com/bitcoin-atom/bitcoin-atom/blob/master/src/chainparams.cpp#L168
networks.bca = {
messagePrefix: '\x19Bitcoin Atom Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x17,
scriptHash: 0xA,
wif: 0x80,
dustThreshold: 1000,
};
// https://github.com/aurarad/Auroracoin/blob/master/src/chainparams.cpp#L77
networks.aur = {
messagePrefix: '\x19Auroracoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x17,
scriptHash: 0xA,
wif: 0xB0,
dustThreshold: 1000,
};
// https://github.com/adcoin-project/AdCoin/blob/master/src/chainparams.cpp#L129
networks.acc = {
messagePrefix: '\x19AdCoin Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x17,
scriptHash: 0x5,
wif: 0xB0,
dustThreshold: 1000,
};
networks.btc = networks.bitcoin;
networks.crw = networks.crown;
networks.dgb = networks.digibyte;

2
routes/shepherd.js

@ -103,6 +103,8 @@ shepherd = require('./shepherd/electrum/createtx-multi.js')(shepherd);
shepherd = require('./shepherd/electrum/interest.js')(shepherd);
shepherd = require('./shepherd/electrum/listunspent.js')(shepherd);
shepherd = require('./shepherd/electrum/estimate.js')(shepherd);
shepherd = require('./shepherd/electrum/btcFees.js')(shepherd);
shepherd = require('./shepherd/electrum/insight.js')(shepherd);
// dex
shepherd = require('./shepherd/dex/coind.js')(shepherd);

15
routes/shepherd/addCoinShortcuts.js

@ -1,4 +1,7 @@
const electrumServers = require('../electrumjs/electrumServers');
const request = require('request');
// TODO: refactor
module.exports = (shepherd) => {
shepherd.startSPV = (coin) => {
@ -44,7 +47,7 @@ module.exports = (shepherd) => {
}),
};
shepherd.request(options, (error, response, body) => {
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
@ -78,7 +81,7 @@ module.exports = (shepherd) => {
}),
};
shepherd.request(options, (error, response, body) => {
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
@ -112,7 +115,7 @@ module.exports = (shepherd) => {
}),
};
shepherd.request(options, (error, response, body) => {
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
@ -146,7 +149,7 @@ module.exports = (shepherd) => {
}),
};
shepherd.request(options, (error, response, body) => {
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
@ -180,7 +183,7 @@ module.exports = (shepherd) => {
}),
};
shepherd.request(options, (error, response, body) => {
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
@ -231,7 +234,7 @@ module.exports = (shepherd) => {
}),
};
shepherd.request(options, (error, response, body) => {
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {

12
routes/shepherd/binsUtils.js

@ -1,7 +1,11 @@
const os = require('os');
const fsnode = require('fs');
const _fs = require('graceful-fs');
module.exports = (shepherd) => {
// osx and linux
shepherd.binFixRights = () => {
const osPlatform = shepherd.os.platform();
const osPlatform = os.platform();
const _bins = [
shepherd.komododBin,
shepherd.komodocliBin
@ -10,11 +14,11 @@ module.exports = (shepherd) => {
if (osPlatform === 'darwin' ||
osPlatform === 'linux') {
for (let i = 0; i < _bins.length; i++) {
shepherd._fs.stat(_bins[i], (err, stat) => {
_fs.stat(_bins[i], (err, stat) => {
if (!err) {
if (parseInt(stat.mode.toString(8), 10) !== 100775) {
shepherd.log(`${_bins[i]} fix permissions`);
shepherd.fsnode.chmodSync(_bins[i], '0775');
fsnode.chmodSync(_bins[i], '0775');
}
} else {
shepherd.log(`error: ${_bins[i]} not found`);
@ -26,8 +30,8 @@ module.exports = (shepherd) => {
shepherd.killRogueProcess = (processName) => {
// kill rogue process copies on start
const osPlatform = os.platform();
let processGrep;
const osPlatform = shepherd.os.platform();
switch (osPlatform) {
case 'darwin':

11
routes/shepherd/coindWalletKeys.js

@ -1,3 +1,8 @@
const fs = require('fs-extra');
const _fs = require('graceful-fs');
const wif = require('wif');
const bitcoinJS = require('bitcoinjs-lib');
module.exports = (shepherd) => {
/*
* type: GET
@ -5,8 +10,6 @@ module.exports = (shepherd) => {
*/
shepherd.get('/coindwalletkeys', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const wif = require('wif');
const fs = require('fs');
const chain = req.query.chain;
// ref: https://gist.github.com/kendricktan/1e62495150ad236b38616d733aac4eb9
@ -14,7 +17,7 @@ module.exports = (shepherd) => {
_walletDatLocation = chain === 'CHIPS' ? `${shepherd.chipsDir}/wallet.dat` : _walletDatLocation;
try {
shepherd._fs.access(_walletDatLocation, shepherd.fs.constants.R_OK, (err) => {
_fs.access(_walletDatLocation, shepherd.fs.constants.R_OK, (err) => {
if (err) {
shepherd.log(`error reading ${_walletDatLocation}`);
successObj = {
@ -60,7 +63,7 @@ module.exports = (shepherd) => {
const keyObj = wif.decode(key);
const wifKey = wif.encode(keyObj);
const keyPair = shepherd.bitcoinJS.ECPair.fromWIF(wifKey, shepherd.electrumJSNetworks.komodo);
const keyPair = bitcoinJS.ECPair.fromWIF(wifKey, shepherd.electrumJSNetworks.komodo);
const _keyPair = {
priv: keyPair.toWIF(),
pub: keyPair.getAddress(),

8
routes/shepherd/coinsList.js

@ -1,3 +1,5 @@
const fs = require('fs-extra');
module.exports = (shepherd) => {
/*
* type: GET
@ -5,8 +7,8 @@ module.exports = (shepherd) => {
*/
shepherd.get('/coinslist', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
if (shepherd.fs.existsSync(`${shepherd.agamaDir}/shepherd/coinslist.json`)) {
shepherd.fs.readFile(`${shepherd.agamaDir}/shepherd/coinslist.json`, 'utf8', (err, data) => {
if (fs.existsSync(`${shepherd.agamaDir}/shepherd/coinslist.json`)) {
fs.readFile(`${shepherd.agamaDir}/shepherd/coinslist.json`, 'utf8', (err, data) => {
if (err) {
const errorObj = {
msg: 'error',
@ -57,7 +59,7 @@ module.exports = (shepherd) => {
res.end(JSON.stringify(errorObj));
} else {
shepherd.fs.writeFile(`${shepherd.agamaDir}/shepherd/coinslist.json`, JSON.stringify(_payload), (err) => {
fs.writeFile(`${shepherd.agamaDir}/shepherd/coinslist.json`, JSON.stringify(_payload), (err) => {
if (err) {
const errorObj = {
msg: 'error',

5
routes/shepherd/confMaxconnections.js

@ -1,8 +1,9 @@
const fs = require('fs-extra');
const Promise = require('bluebird');
module.exports = (shepherd) => {
shepherd.getMaxconKMDConf = () => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
fs.readFile(`${shepherd.komodoDir}/komodo.conf`, 'utf8', (err, data) => {
if (err) {
shepherd.log('kmd conf maxconnections param read failed');
@ -23,7 +24,7 @@ module.exports = (shepherd) => {
}
shepherd.setMaxconKMDConf = (limit) => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
fs.readFile(`${shepherd.komodoDir}/komodo.conf`, 'utf8', (err, data) => {
const _maxconVal = limit ? 1 : 10;

21
routes/shepherd/config.js

@ -1,7 +1,12 @@
const fs = require('fs-extra');
const _fs = require('graceful-fs');
const fsnode = require('fs');
const Promise = require('bluebird');
module.exports = (shepherd) => {
shepherd.loadLocalConfig = () => {
if (shepherd.fs.existsSync(`${shepherd.agamaDir}/config.json`)) {
let localAppConfig = shepherd.fs.readFileSync(`${shepherd.agamaDir}/config.json`, 'utf8');
if (fs.existsSync(`${shepherd.agamaDir}/config.json`)) {
let localAppConfig = fs.readFileSync(`${shepherd.agamaDir}/config.json`, 'utf8');
shepherd.log('app config set from local file');
shepherd.writeLog('app config set from local file');
@ -53,14 +58,14 @@ module.exports = (shepherd) => {
shepherd.saveLocalAppConf = (appSettings) => {
let appConfFileName = `${shepherd.agamaDir}/config.json`;
shepherd._fs.access(shepherd.agamaDir, shepherd.fs.constants.R_OK, (err) => {
_fs.access(shepherd.agamaDir, shepherd.fs.constants.R_OK, (err) => {
if (!err) {
const FixFilePermissions = () => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
const result = 'config.json file permissions updated to Read/Write';
shepherd.fsnode.chmodSync(appConfFileName, '0666');
fsnode.chmodSync(appConfFileName, '0666');
setTimeout(() => {
shepherd.log(result);
@ -71,10 +76,10 @@ module.exports = (shepherd) => {
}
const FsWrite = () => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
const result = 'config.json write file is done';
shepherd.fs.writeFile(appConfFileName,
fs.writeFile(appConfFileName,
JSON.stringify(appSettings)
.replace(/,/g, ',\n') // format json in human readable form
.replace(/":/g, '": ')
@ -84,7 +89,7 @@ module.exports = (shepherd) => {
return shepherd.log(err);
});
shepherd.fsnode.chmodSync(appConfFileName, '0666');
fsnode.chmodSync(appConfFileName, '0666');
setTimeout(() => {
shepherd.log(result);
shepherd.log(`app conf.json file is created successfully at: ${shepherd.agamaDir}`);

16
routes/shepherd/daemonControl.js

@ -58,12 +58,12 @@ module.exports = (shepherd) => {
}
break;
case 'coind':
DaemonConfPath = _platform === 'win32' ? shepherd.path.normalize(`${shepherd.coindRootDir}/${coind.toLowerCase()}`) : `${shepherd.coindRootDir}/${coind.toLowerCase()}`;
DaemonConfPath = _platform === 'win32' ? path.normalize(`${shepherd.coindRootDir}/${coind.toLowerCase()}`) : `${shepherd.coindRootDir}/${coind.toLowerCase()}`;
break;
default:
DaemonConfPath = `${shepherd.komodoDir}/${flock}`;
if (_platform === 'win32') {
DaemonConfPath = shepherd.path.normalize(DaemonConfPath);
DaemonConfPath = path.normalize(DaemonConfPath);
}
}
@ -230,7 +230,11 @@ module.exports = (shepherd) => {
let spawnErr = fs.openSync(_daemonLogName, 'a');
spawn(shepherd.komododBin, _arg, {
stdio: ['ignore', spawnOut, spawnErr],
stdio: [
'ignore',
spawnOut,
spawnErr
],
detached: true,
}).unref();
} else {
@ -439,7 +443,7 @@ module.exports = (shepherd) => {
fs.unlink(coindDebugLogLocation);
}
});
} catch(e) {
} catch (e) {
shepherd.log(`coind ${coind} debug.log access err: ${e}`);
shepherd.writeLog(`coind ${coind} debug.log access err: ${e}`);
}
@ -475,7 +479,7 @@ module.exports = (shepherd) => {
shepherd.writeLog(`port ${_port} (${coind}) is already in use`);
}
});
} catch(e) {
} catch (e) {
shepherd.log(`failed to start ${coind} err: ${e}`);
shepherd.writeLog(`failed to start ${coind} err: ${e}`);
}
@ -609,7 +613,7 @@ module.exports = (shepherd) => {
shepherd.log('rpcuser: OK');
shepherd.writeLog('rpcuser: OK');
} else {
const randomstring = shepherd.md5((Math.random() * Math.random() * 999).toString());
const randomstring = md5((Math.random() * Math.random() * 999).toString());
shepherd.log('rpcuser: NOT FOUND');
shepherd.writeLog('rpcuser: NOT FOUND');

16
routes/shepherd/dashboardUpdate.js

@ -1,4 +1,5 @@
const Promise = require('bluebird');
const request = require('request');
module.exports = (shepherd) => {
/*
@ -24,7 +25,7 @@ module.exports = (shepherd) => {
_promiseStack = [
'getinfo',
'listtransactions',
'getbalance',
'getbalance'
];
} else {
_returnObj = {
@ -58,7 +59,7 @@ module.exports = (shepherd) => {
_bitcoinRPC(
coin,
_type === 'public' ? 'getaddressesbyaccount' : 'z_listaddresses',
['']
_type === 'public' ? [''] : null
)
.then((_json) => {
if (_json === 'Work queue depth exceeded' ||
@ -86,10 +87,13 @@ module.exports = (shepherd) => {
const filteredArray = json.filter(res => res.address === allAddrArray[a]).map(res => res.amount);
let isNewAddr = true;
for (let x = 0; x < result.length && isNewAddr; x++) {
for (let y = 0; y < result[x].length && isNewAddr; y++) {
if (allAddrArray[a] === result[x][y]) {
isNewAddr = false;
if (result[x]) {
for (let y = 0; y < result[x].length && isNewAddr; y++) {
if (allAddrArray[a] === result[x][y]) {
isNewAddr = false;
}
}
}
}
@ -272,7 +276,7 @@ module.exports = (shepherd) => {
timeout: 120000,
};
shepherd.request(options, (error, response, body) => {
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {

12
routes/shepherd/debugLog.js

@ -1,3 +1,7 @@
const path = require('path');
const _fs = require('graceful-fs');
const Promise = require('bluebird');
module.exports = (shepherd) => {
/*
* type: POST
@ -20,7 +24,7 @@ module.exports = (shepherd) => {
if (shepherd.os.platform() === 'win32') {
shepherd.komodoDir = shepherd.appConfig.dataDir.length ? shepherd.appConfig.dataDir : `${process.env.APPDATA}/Komodo`;
shepherd.komodoDir = shepherd.path.normalize(shepherd.komodoDir);
shepherd.komodoDir = path.normalize(shepherd.komodoDir);
}
if (_herd === 'komodo') {
@ -93,18 +97,18 @@ module.exports = (shepherd) => {
});
shepherd.readDebugLog = (fileLocation, lastNLines) => {
return new shepherd.Promise(
return new Promise(
(resolve, reject) => {
if (lastNLines) {
try {
shepherd._fs.access(fileLocation, shepherd.fs.constants.R_OK, (err) => {
_fs.access(fileLocation, shepherd.fs.constants.R_OK, (err) => {
if (err) {
shepherd.log(`error reading ${fileLocation}`);
shepherd.writeLog(`error reading ${fileLocation}`);
reject(`readDebugLog error: ${err}`);
} else {
shepherd.log(`reading ${fileLocation}`);
shepherd._fs.readFile(fileLocation, 'utf-8', (err, data) => {
_fs.readFile(fileLocation, 'utf-8', (err, data) => {
if (err) {
shepherd.writeLog(`readDebugLog err: ${err}`);
shepherd.log(`readDebugLog err: ${err}`);

19
routes/shepherd/downloadBins.js

@ -1,3 +1,8 @@
const path = require('path');
const os = require('os');
const fs = require('fs-extra');
const remoteFileSize = require('remote-file-size');
const remoteBinLocation = {
win32: 'https://artifacts.supernet.org/latest/windows/',
darwin: 'https://artifacts.supernet.org/latest/osx/',
@ -47,7 +52,7 @@ module.exports = (shepherd) => {
// TODO: promises
shepherd.get('/update/bins/check', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const rootLocation = shepherd.path.join(__dirname, '../../');
const rootLocation = path.join(__dirname, '../../');
const successObj = {
msg: 'success',
result: 'bins',
@ -55,7 +60,7 @@ module.exports = (shepherd) => {
res.end(JSON.stringify(successObj));
const _os = shepherd.os.platform();
const _os = os.platform();
shepherd.log(`checking bins: ${_os}`);
shepherd.io.emit('patch', {
@ -67,8 +72,8 @@ module.exports = (shepherd) => {
});
// get list of bins/dlls that can be updated to the latest
for (let i = 0; i < latestBins[_os].length; i++) {
shepherd.remoteFileSize(remoteBinLocation[_os] + latestBins[_os][i], (err, remoteBinSize) => {
const localBinSize = shepherd.fs.statSync(rootLocation + localBinLocation[_os] + latestBins[_os][i]).size;
remoteFileSize(remoteBinLocation[_os] + latestBins[_os][i], (err, remoteBinSize) => {
const localBinSize = fs.statSync(rootLocation + localBinLocation[_os] + latestBins[_os][i]).size;
shepherd.log('remote url: ' + (remoteBinLocation[_os] + latestBins[_os][i]) + ' (' + remoteBinSize + ')');
shepherd.log('local file: ' + (rootLocation + localBinLocation[_os] + latestBins[_os][i]) + ' (' + localBinSize + ')');
@ -110,8 +115,8 @@ module.exports = (shepherd) => {
*/
shepherd.get('/update/bins', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const rootLocation = shepherd.path.join(__dirname, '../../');
const _os = shepherd.os.platform();
const rootLocation = path.join(__dirname, '../../');
const _os = os.platform();
const successObj = {
msg: 'success',
result: {
@ -145,7 +150,7 @@ module.exports = (shepherd) => {
})
.then(() => {
// verify that remote file is matching to DL'ed file
const localBinSize = shepherd.fs.statSync(`${rootLocation}${localBinLocation[_os]}patch/${binsToUpdate[i].name}`).size;
const localBinSize = fs.statSync(`${rootLocation}${localBinLocation[_os]}patch/${binsToUpdate[i].name}`).size;
shepherd.log('compare dl file size');
if (localBinSize === binsToUpdate[i].rSize) {

28
routes/shepherd/downloadPatch.js

@ -1,3 +1,9 @@
const path = require('path');
const AdmZip = require('adm-zip');
const remoteFileSize = require('remote-file-size');
const fs = require('fs-extra');
const request = require('request');
module.exports = (shepherd) => {
/*
* DL app patch
@ -25,7 +31,7 @@ module.exports = (shepherd) => {
});
shepherd.updateAgama = () => {
const rootLocation = shepherd.path.join(__dirname, '../../');
const rootLocation = path.join(__dirname, '../../');
shepherd.downloadFile({
remoteFile: 'https://github.com/pbca26/dl-test/raw/master/patch.zip',
@ -50,18 +56,18 @@ module.exports = (shepherd) => {
.then(() => {
shepherd.remoteFileSize('https://github.com/pbca26/dl-test/raw/master/patch.zip', (err, remotePatchSize) => {
// verify that remote file is matching to DL'ed file
const localPatchSize = shepherd.fs.statSync(`${rootLocation}patch.zip`).size;
const localPatchSize = fs.statSync(`${rootLocation}patch.zip`).size;
shepherd.log('compare dl file size');
if (localPatchSize === remotePatchSize) {
const zip = new shepherd.AdmZip(`${rootLocation}patch.zip`);
const zip = new AdmZip(`${rootLocation}patch.zip`);
shepherd.log('patch succesfully downloaded');
shepherd.log('extracting contents');
if (shepherd.appConfig.dev) {
if (!shepherd.fs.existsSync(`${rootLocation}/patch`)) {
shepherd.fs.mkdirSync(`${rootLocation}/patch`);
if (!fs.existsSync(`${rootLocation}/patch`)) {
fs.mkdirSync(`${rootLocation}/patch`);
}
}
@ -73,7 +79,7 @@ module.exports = (shepherd) => {
status: 'done',
},
});
shepherd.fs.unlinkSync(`${rootLocation}patch.zip`);
fs.unlinkSync(`${rootLocation}patch.zip`);
} else {
shepherd.io.emit('patch', {
msg: {
@ -95,18 +101,18 @@ module.exports = (shepherd) => {
*/
shepherd.get('/update/patch/check', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const rootLocation = shepherd.path.join(__dirname, '../../');
const rootLocation = path.join(__dirname, '../../');
const options = {
url: 'https://github.com/pbca26/dl-test/raw/master/version',
method: 'GET',
};
shepherd.request(options, (error, response, body) => {
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
const remoteVersion = body.split('\n');
const localVersionFile = shepherd.fs.readFileSync(`${rootLocation}version`, 'utf8');
const localVersionFile = fs.readFileSync(`${rootLocation}version`, 'utf8');
let localVersion;
if (localVersionFile.indexOf('\r\n') > -1) {
@ -157,8 +163,8 @@ module.exports = (shepherd) => {
*/
shepherd.get('/unpack', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const dlLocation = shepherd.path.join(__dirname, '../../');
const zip = new shepherd.AdmZip(`${dlLocation}patch.zip`);
const dlLocation = path.join(__dirname, '../../');
const zip = new AdmZip(`${dlLocation}patch.zip`);
zip.extractAllTo(/*target path*/ `${dlLocation}/patch/unpack`, /*overwrite*/true);
const successObj = {

7
routes/shepherd/downloadUtil.js

@ -1,9 +1,12 @@
const Promise = require('bluebird');
const fs = require('fs-extra');
module.exports = (shepherd) => {
/**
* Promise based download file method
*/
shepherd.downloadFile = (configuration) => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
// Save variable to know progress
let receivedBytes = 0;
let totalBytes = 0;
@ -17,7 +20,7 @@ module.exports = (shepherd) => {
},
});
let out = shepherd.fs.createWriteStream(configuration.localFile);
let out = fs.createWriteStream(configuration.localFile);
req.pipe(out);
req.on('response', (data) => {

16
routes/shepherd/downloadZcparams.js

@ -1,3 +1,7 @@
const fs = require('fs-extra');
const _fs = require('graceful-fs');
const Promise = require('bluebird');
module.exports = (shepherd) => {
shepherd.zcashParamsDownloadLinks = {
'agama.komodoplatform.com': {
@ -16,10 +20,10 @@ module.exports = (shepherd) => {
shepherd.zcashParamsExist = () => {
let _checkList = {
rootDir: shepherd._fs.existsSync(shepherd.zcashParamsDir),
provingKey: shepherd._fs.existsSync(`${shepherd.zcashParamsDir}/sprout-proving.key`),
rootDir: _fs.existsSync(shepherd.zcashParamsDir),
provingKey: _fs.existsSync(`${shepherd.zcashParamsDir}/sprout-proving.key`),
provingKeySize: false,
verifyingKey: shepherd._fs.existsSync(`${shepherd.zcashParamsDir}/sprout-verifying.key`),
verifyingKey: _fs.existsSync(`${shepherd.zcashParamsDir}/sprout-verifying.key`),
verifyingKeySize: false,
errors: false,
};
@ -28,8 +32,8 @@ module.exports = (shepherd) => {
_checkList.provingKey ||
_checkList.verifyingKey) {
// verify each key size
const _provingKeySize = _checkList.provingKey ? shepherd.fs.lstatSync(`${shepherd.zcashParamsDir}/sprout-proving.key`) : 0;
const _verifyingKeySize = _checkList.verifyingKey ? shepherd.fs.lstatSync(`${shepherd.zcashParamsDir}/sprout-verifying.key`) : 0;
const _provingKeySize = _checkList.provingKey ? fs.lstatSync(`${shepherd.zcashParamsDir}/sprout-proving.key`) : 0;
const _verifyingKeySize = _checkList.verifyingKey ? fs.lstatSync(`${shepherd.zcashParamsDir}/sprout-verifying.key`) : 0;
if (Number(_provingKeySize.size) === 910173851) { // bytes
_checkList.provingKeySize = true;
@ -55,7 +59,7 @@ module.exports = (shepherd) => {
}
shepherd.zcashParamsExistPromise = () => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
const _verify = shepherd.zcashParamsExist();
resolve(_verify);
});

47
routes/shepherd/elections.js

@ -1,5 +1,6 @@
const bs58check = require('bs58check');
const bitcoin = require('bitcoinjs-lib');
const Promise = require('bluebird');
module.exports = (shepherd) => {
shepherd.elections = {};
@ -111,11 +112,11 @@ module.exports = (shepherd) => {
shepherd.electionsDecodeTx = (decodedTx, ecl, network, _network, transaction, blockInfo, address) => {
let txInputs = [];
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
if (decodedTx &&
decodedTx.inputs) {
shepherd.Promise.all(decodedTx.inputs.map((_decodedInput, index) => {
return new shepherd.Promise((_resolve, _reject) => {
Promise.all(decodedTx.inputs.map((_decodedInput, index) => {
return new Promise((_resolve, _reject) => {
if (_decodedInput.txid !== '0000000000000000000000000000000000000000000000000000000000000000') {
ecl.blockchainTransactionGet(_decodedInput.txid)
.then((rawInput) => {
@ -186,8 +187,8 @@ module.exports = (shepherd) => {
shepherd.log(json.length, true);
shepherd.Promise.all(json.map((transaction, index) => {
return new shepherd.Promise((resolve, reject) => {
Promise.all(json.map((transaction, index) => {
return new Promise((resolve, reject) => {
ecl.blockchainBlockGetHeader(transaction.height)
.then((blockInfo) => {
if (blockInfo &&
@ -256,7 +257,8 @@ module.exports = (shepherd) => {
if (type === 'candidate') {
if (_region === 'ne2k18-na-1-eu-2-ae-3-sh-4') {
if (decodedTx.outputs[i].scriptPubKey.addresses[0] === _address && decodedTx.outputs[i].scriptPubKey.asm.indexOf('OP_RETURN') === -1) {
if (decodedTx.outputs[i].scriptPubKey.addresses[0] === _address &&
decodedTx.outputs[i].scriptPubKey.asm.indexOf('OP_RETURN') === -1) {
const _regionsLookup = [
'ne2k18-na',
'ne2k18-eu',
@ -264,7 +266,15 @@ module.exports = (shepherd) => {
'ne2k18-sh'
];
shepherd.electionsDecodeTx(decodedTx, ecl, network, _network, transaction, blockInfo, _address)
shepherd.electionsDecodeTx(
decodedTx,
ecl,
network,
_network,
transaction,
blockInfo,
_address
)
.then((res) => {
shepherd.log(`i received ${decodedTx.outputs[i].value} from ${res.outputAddresses[0]} out ${i} region ${_regionsLookup[i]}`);
_rawtx.push({
@ -277,7 +287,15 @@ module.exports = (shepherd) => {
});
}
} else {
shepherd.electionsDecodeTx(decodedTx, ecl, network, _network, transaction, blockInfo, _address)
shepherd.electionsDecodeTx(
decodedTx,
ecl,
network,
_network,
transaction,
blockInfo,
_address
)
.then((res) => {
if (decodedTx.outputs[i].scriptPubKey.addresses[0] === _address) {
_candidate.amount = decodedTx.outputs[i].value;
@ -298,7 +316,15 @@ module.exports = (shepherd) => {
}
} else {
shepherd.log('elections regular tx', true);
shepherd.electionsDecodeTx(decodedTx, ecl, network, _network, transaction, blockInfo, _address)
shepherd.electionsDecodeTx(
decodedTx,
ecl,
network,
_network,
transaction,
blockInfo,
_address
)
.then((_regularTx) => {
if (_regularTx[0] &&
_regularTx[1]) {
@ -311,7 +337,8 @@ module.exports = (shepherd) => {
hash: transaction['tx_hash'],
});
} else {
if ((type === 'voter' && _regularTx.type !== 'received') && (type === 'candidate' && _regularTx.type !== 'sent')) {
if ((type === 'voter' && _regularTx.type !== 'received') &&
(type === 'candidate' && _regularTx.type !== 'sent')) {
_rawtx.push({
address: _regularTx.address || 'self',
timestamp: _regularTx.timestamp,

10
routes/shepherd/electrum/balance.js

@ -1,8 +1,10 @@
const Promise = require('bluebird');
module.exports = (shepherd) => {
shepherd.get('/electrum/getbalance', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const network = req.query.network || shepherd.findNetworkObj(req.query.coin);
const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
const ecl = shepherd.electrumServers[network].proto === 'insight' ? shepherd.insightJSCore(shepherd.electrumServers[network]) : new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
shepherd.log('electrum getbalance =>', true);
@ -35,8 +37,8 @@ module.exports = (shepherd) => {
_utxo.length) {
let interestTotal = 0;
shepherd.Promise.all(_utxo.map((_utxoItem, index) => {
return new shepherd.Promise((resolve, reject) => {
Promise.all(_utxo.map((_utxoItem, index) => {
return new Promise((resolve, reject) => {
shepherd.getTransaction(_utxoItem['tx_hash'], network, ecl)
.then((_rawtxJSON) => {
shepherd.log('electrum gettransaction ==>', true);
@ -45,7 +47,7 @@ module.exports = (shepherd) => {
// decode tx
const _network = shepherd.getNetworkData(network);
const decodedTx = shepherd.electrumJSTxDecoder(_rawtxJSON, network, _network);
const decodedTx = shepherd.electrumJSTxDecoder(_rawtxJSON, network, _network, shepherd.electrumServers[network].proto === 'insight');
if (decodedTx &&
decodedTx.format &&

6
routes/shepherd/electrum/block.js

@ -1,3 +1,5 @@
const Promise = require('bluebird');
module.exports = (shepherd) => {
shepherd.get('/electrum/getblockinfo', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
@ -21,7 +23,7 @@ module.exports = (shepherd) => {
});
shepherd.electrumGetBlockInfo = (height, network) => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
ecl.connect();
@ -58,7 +60,7 @@ module.exports = (shepherd) => {
});
shepherd.electrumGetCurrentBlock = (network) => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
ecl.connect();

115
routes/shepherd/electrum/btcFees.js

@ -0,0 +1,115 @@
const request = require('request');
const Promise = require('bluebird');
let btcFeeBlocks = [];
for (let i = 0; i < 25; i++) {
btcFeeBlocks.push(i);
}
const checkTimestamp = (dateToCheck) => {
const currentEpochTime = new Date(Date.now()) / 1000;
const secondsElapsed = Number(currentEpochTime) - Number(dateToCheck);
return Math.floor(secondsElapsed);
}
const getRandomIntInclusive = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min; // the maximum is inclusive and the minimum is inclusive
}
let btcFees = {
recommended: {},
all: {},
electrum: {},
lastUpdated: null,
};
const BTC_FEES_MIN_ELAPSED_TIME = 120;
module.exports = (shepherd) => {
shepherd.get('/electrum/btcfees', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
if (checkTimestamp(btcFees.lastUpdated) > BTC_FEES_MIN_ELAPSED_TIME) {
const _randomServer = shepherd.electrumServers.btc.serverList[getRandomIntInclusive(0, shepherd.electrumServers.btc.serverList.length - 1)].split(':');
const ecl = new shepherd.electrumJSCore(_randomServer[1], _randomServer[0], 'tcp');
let _btcFeeEstimates = [];
console.log(`btc fees server ${_randomServer.join(':')}`);
ecl.connect();
Promise.all(btcFeeBlocks.map((coin, index) => {
return new Promise((resolve, reject) => {
ecl.blockchainEstimatefee(index + 1)
.then((json) => {
resolve(true);
if (json > 0) {
_btcFeeEstimates.push(Math.floor((json / 1024) * 100000000));
}
});
});
}))
.then(result => {
ecl.close();
if (result &&
result.length) {
btcFees.electrum = _btcFeeEstimates;
} else {
btcFees.electrum = 'error';
}
let options = {
url: `https://bitcoinfees.earn.com/api/v1/fees/recommended`,
method: 'GET',
};
// send back body on both success and error
// this bit replicates iguana core's behaviour
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
try {
const _parsedBody = JSON.parse(body);
btcFees.lastUpdated = Math.floor(Date.now() / 1000);
btcFees.recommended = _parsedBody;
} catch (e) {
shepherd.log('unable to retrieve BTC fees / recommended', true);
}
} else {
shepherd.log('unable to retrieve BTC fees / recommended', true);
}
res.end(JSON.stringify({
msg: 'success',
result: btcFees,
}));
});
});
} else {
shepherd.log('btcfees, use cache', true);
const successObj = {
msg: 'success',
result: btcFees,
};
res.end(JSON.stringify(successObj));
}
} else {
const errorObj = {
msg: 'error',
result: 'unauthorized access',
};
res.end(JSON.stringify(errorObj));
}
});
return shepherd;
};

30
routes/shepherd/electrum/createtx-multi.js

@ -1,10 +1,14 @@
const bitcoinJS = require('bitcoinjs-lib');
const bitcoinJSForks = require('bitcoinforksjs-lib');
const bitcoinZcash = require('bitcoinjs-lib-zcash');
const bitcoinPos = require('bitcoinjs-lib-pos');
const coinSelect = require('coinselect');
// not prod ready, only for voting!
// needs a fix
// TODO: spread fee across targets
// current implementation subtracts fee from the fist target out
module.exports = (shepherd) => {
shepherd.post('/electrum/createrawtx-multiout', (req, res, next) => {
if (shepherd.checkToken(req.body.token)) {
@ -92,7 +96,7 @@ module.exports = (shepherd) => {
// default coin selection algo blackjack with fallback to accumulative
// make a first run, calc approx tx fee
// if ins and outs are empty reduce max spend by txfee
const firstRun = shepherd.coinSelect(utxoListFormatted, targets, btcFee ? btcFee : 0);
const firstRun = coinSelect(utxoListFormatted, targets, btcFee ? btcFee : 0);
let inputs = firstRun.inputs;
let outputs = firstRun.outputs;
@ -115,7 +119,7 @@ module.exports = (shepherd) => {
shepherd.log('coinselect adjusted targets =>', true);
shepherd.log(targets, true);
const secondRun = shepherd.coinSelect(utxoListFormatted, targets, 0);
const secondRun = coinSelect(utxoListFormatted, targets, 0);
inputs = secondRun.inputs;
outputs = secondRun.outputs;
fee = fee ? fee : secondRun.fee;
@ -131,10 +135,13 @@ module.exports = (shepherd) => {
let _change = 0;
if (outputs &&
outputs.length > 1) {
outputs.length > 1 &&
outputs.length > targets.length) {
_change = outputs[outputs.length - 1].value - fee;
}
shepherd.log(`change before adjustments ${_change}`, true);
if (!btcFee &&
_change === 0) {
outputs[0].value = outputs[0].value - fee;
@ -146,6 +153,9 @@ module.exports = (shepherd) => {
shepherd.log('init targets', true);
shepherd.log(initTargets, true);
shepherd.log('coinselect targets', true);
shepherd.log(targets, true);
if (initTargets[0].value < targets[0].value) {
targets[0].value = initTargets[0].value;
}
@ -238,13 +248,12 @@ module.exports = (shepherd) => {
res.end(JSON.stringify(successObj));
} else {
let vinSum = 0;
let voutSum = 0;
for (let i = 0; i < inputs.length; i++) {
vinSum += inputs[i].value;
}
let voutSum = 0;
for (let i = 0; i < outputs.length; i++) {
voutSum += outputs[i].value;
}
@ -272,7 +281,7 @@ module.exports = (shepherd) => {
outputAddress = outputs;
if (outputAddress.length > 1) {
if (!outputAddress[outputAddress.length - 1].address) {
outputAddress.pop();
}
@ -420,7 +429,7 @@ module.exports = (shepherd) => {
// single sig
shepherd.buildSignedTxMulti = (sendTo, changeAddress, wif, network, utxo, changeValue, spendValue, opreturn) => {
let key = shepherd.isZcash(network) ? bitcoinZcash.ECPair.fromWIF(wif, shepherd.getNetworkData(network)) : shepherd.bitcoinJS.ECPair.fromWIF(wif, shepherd.getNetworkData(network));
let key = shepherd.isZcash(network) ? bitcoinZcash.ECPair.fromWIF(wif, shepherd.getNetworkData(network)) : bitcoinJS.ECPair.fromWIF(wif, shepherd.getNetworkData(network));
let tx;
if (shepherd.isZcash(network)) {
@ -428,7 +437,7 @@ module.exports = (shepherd) => {
} else if (shepherd.isPos(network)) {
tx = new bitcoinPos.TransactionBuilder(shepherd.getNetworkData(network));
} else {
tx = new shepherd.bitcoinJS.TransactionBuilder(shepherd.getNetworkData(network));
tx = new bitcoinJS.TransactionBuilder(shepherd.getNetworkData(network));
}
shepherd.log('buildSignedTx', true);
@ -459,10 +468,11 @@ module.exports = (shepherd) => {
if (opreturn &&
opreturn.length) {
for (let i = 0; i < opreturn.length; i++) {
shepherd.log(`opreturn ${i} ${opreturn[i]}`);
const data = Buffer.from(opreturn[i], 'utf8');
const dataScript = shepherd.bitcoinJS.script.nullData.output.encode(data);
const dataScript = bitcoinJS.script.nullData.output.encode(data);
tx.addOutput(dataScript, 1000);
shepherd.log(`opreturn ${i} ${opreturn[i]}`);
}
}

5
routes/shepherd/electrum/createtx-split.js

@ -1,3 +1,4 @@
const bitcoinJS = require('bitcoinjs-lib');
const bitcoinJSForks = require('bitcoinforksjs-lib');
const bitcoinZcash = require('bitcoinjs-lib-zcash');
const bitcoinPos = require('bitcoinjs-lib-pos');
@ -14,7 +15,7 @@ module.exports = (shepherd) => {
const outputAddress = req.body.payload.outputAddress;
const changeAddress = req.body.payload.changeAddress;
let key = shepherd.isZcash(network) ? bitcoinZcash.ECPair.fromWIF(wif, shepherd.getNetworkData(network)) : shepherd.bitcoinJS.ECPair.fromWIF(wif, shepherd.getNetworkData(network));
let key = shepherd.isZcash(network) ? bitcoinZcash.ECPair.fromWIF(wif, shepherd.getNetworkData(network)) : bitcoinJS.ECPair.fromWIF(wif, shepherd.getNetworkData(network));
let tx;
if (shepherd.isZcash(network)) {
@ -22,7 +23,7 @@ module.exports = (shepherd) => {
} else if (shepherd.isPos(network)) {
tx = new bitcoinPos.TransactionBuilder(shepherd.getNetworkData(network));
} else {
tx = new shepherd.bitcoinJS.TransactionBuilder(shepherd.getNetworkData(network));
tx = new bitcoinJS.TransactionBuilder(shepherd.getNetworkData(network));
}
shepherd.log('buildSignedTx', true);

16
routes/shepherd/electrum/createtx.js

@ -1,6 +1,8 @@
const bitcoinJS = require('bitcoinjs-lib');
const bitcoinJSForks = require('bitcoinforksjs-lib');
const bitcoinZcash = require('bitcoinjs-lib-zcash');
const bitcoinPos = require('bitcoinjs-lib-pos');
const coinSelect = require('coinselect');
module.exports = (shepherd) => {
// unsigned tx
@ -9,11 +11,11 @@ module.exports = (shepherd) => {
// TODO: finish unsigned for zcash, btc forks and pos coins
if (network === 'btg') {
shepherd.log('enable btg', true);
tx = new bitcoinJSForks.TransactionBuilder(shepherd.getNetworkData(network));
tx.enableBitcoinGold(true);
shepherd.log('enable btg', true);
} else {
tx = new shepherd.bitcoinJS.TransactionBuilder(shepherd.getNetworkData(network));
tx = new bitcoinJS.TransactionBuilder(shepherd.getNetworkData(network));
}
shepherd.log('buildSignedTx', true);
@ -55,7 +57,7 @@ module.exports = (shepherd) => {
// single sig
shepherd.buildSignedTx = (sendTo, changeAddress, wif, network, utxo, changeValue, spendValue, opreturn) => {
let key = shepherd.isZcash(network) ? bitcoinZcash.ECPair.fromWIF(wif, shepherd.getNetworkData(network)) : shepherd.bitcoinJS.ECPair.fromWIF(wif, shepherd.getNetworkData(network));
let key = shepherd.isZcash(network) ? bitcoinZcash.ECPair.fromWIF(wif, shepherd.getNetworkData(network)) : bitcoinJS.ECPair.fromWIF(wif, shepherd.getNetworkData(network));
let tx;
if (shepherd.isZcash(network)) {
@ -63,7 +65,7 @@ module.exports = (shepherd) => {
} else if (shepherd.isPos(network)) {
tx = new bitcoinPos.TransactionBuilder(shepherd.getNetworkData(network));
} else {
tx = new shepherd.bitcoinJS.TransactionBuilder(shepherd.getNetworkData(network));
tx = new bitcoinJS.TransactionBuilder(shepherd.getNetworkData(network));
}
shepherd.log('buildSignedTx', true);
@ -90,10 +92,10 @@ module.exports = (shepherd) => {
}
if (opreturn) {
console.log(`opreturn ${opreturn}`);
const data = Buffer.from(opreturn, 'utf8');
const dataScript = shepherd.bitcoinJS.script.nullData.output.encode(data);
tx.addOutput(dataScript, 1000);
console.log(`opreturn ${opreturn}`);
}
if (network === 'komodo' ||
@ -279,7 +281,7 @@ module.exports = (shepherd) => {
// default coin selection algo blackjack with fallback to accumulative
// make a first run, calc approx tx fee
// if ins and outs are empty reduce max spend by txfee
const firstRun = shepherd.coinSelect(utxoListFormatted, targets, btcFee ? btcFee : 0);
const firstRun = coinSelect(utxoListFormatted, targets, btcFee ? btcFee : 0);
let inputs = firstRun.inputs;
let outputs = firstRun.outputs;
@ -302,7 +304,7 @@ module.exports = (shepherd) => {
shepherd.log('coinselect adjusted targets =>', true);
shepherd.log(targets, true);
const secondRun = shepherd.coinSelect(utxoListFormatted, targets, 0);
const secondRun = coinSelect(utxoListFormatted, targets, 0);
inputs = secondRun.inputs;
outputs = secondRun.outputs;
fee = fee ? fee : secondRun.fee;

235
routes/shepherd/electrum/insight.js

@ -0,0 +1,235 @@
const request = require('request');
const Promise = require('bluebird');
// abstraction layer to communicate with insight explorers
module.exports = (shepherd) => {
/*shepherd.httpReq = (url, type) => {
};*/
shepherd.insightJSCoreActiveCoin = {};
shepherd.insightJSCore = (electrumServer) => {
shepherd.log('insight =>');
shepherd.log(electrumServer, true);
if (electrumServer) {
shepherd.insightJSCoreActiveCoin = electrumServer;
}
const apiRoutes = (type, address) => {
if (shepherd.insightJSCoreActiveCoin.nonStdApi) {
switch (type) {
case 'transactions':
return shepherd.insightJSCoreActiveCoin.nonStdApi.transactions.replace('{address}', address);
break;
case 'utxo':
return shepherd.insightJSCoreActiveCoin.nonStdApi.transactions.replace('{utxo}', address);
break;
case 'push':
return shepherd.insightJSCoreActiveCoin.nonStdApi.push;
break;
}
} else {
switch (type) {
case 'transactions':
return `txs/?address=${address}`;
break;
case 'utxo':
return `addr/${address}/utxo`;
break;
case 'push':
return 'tx/send';
break;
}
}
};
return {
insight: true,
connect: () => {
shepherd.log('insight fake connect', true);
},
close: () => {
shepherd.log('insight fake close', true);
},
blockchainAddressGetBalance: (address) => {
shepherd.log('insight blockchainAddressGetBalance', true);
return new Promise((resolve, reject) => {
let options = {
url: `${shepherd.insightJSCoreActiveCoin.address}/${apiRoutes('utxo', address)}`,
method: 'GET',
};
console.log(`${shepherd.insightJSCoreActiveCoin.address}/${apiRoutes('utxo', address)}`);
// send back body on both success and error
// this bit replicates iguana core's behaviour
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
try {
const _parsedBody = JSON.parse(body);
console.log(_parsedBody);
if (_parsedBody) {
let _balance = 0;
for (let i = 0; i < _parsedBody.length; i++) {
_balance += Number(_parsedBody[i].amount);
}
resolve({
confirmed: _balance * 100000000,
unconfirmed: 0,
});
}
shepherd.log(`insight blockchainAddressGetBalance ${address}`);
} catch (e) {
shepherd.log(`parse error insight blockchainAddressGetBalance ${address}`, true);
}
} else {
shepherd.log(`req error insight blockchainAddressGetBalance ${address}`, true);
}
});
});
},
blockchainAddressListunspent: (address) => {
shepherd.log('insight blockchainAddressListunspent', true);
return new Promise((resolve, reject) => {
let options = {
url: `${shepherd.insightJSCoreActiveCoin.address}/${apiRoutes('utxo', address)}`,
method: 'GET',
};
console.log(`${shepherd.insightJSCoreActiveCoin.address}/${apiRoutes('utxo', address)}`);
// send back body on both success and error
// this bit replicates iguana core's behaviour
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
try {
const _parsedBody = JSON.parse(body);
console.log(_parsedBody);
if (_parsedBody) {
let _utxos = [];
if (_parsedBody.utxo) {
_parsedBody = _parsedBody.utxo;
}
for (let i = 0; i < _parsedBody.length; i++) {
_utxos.push({
txid: _parsedBody[i].txid,
vout: _parsedBody[i].vout,
address: _parsedBody[i].address,
amount: Number(_parsedBody[i].amount),
amountSats: Number(_parsedBody[i].amount) * 100000000,
confirmations: _parsedBody[i].confirmations,
spendable: true,
verified: false,
});
}
resolve(_utxos);
}
shepherd.log(`insight blockchainAddressListunspent ${address}`);
} catch (e) {
shepherd.log(`parse error insight blockchainAddressListunspent ${address}`, true);
}
} else {
shepherd.log(`req error insight blockchainAddressListunspent ${address}`, true);
}
});
});
},
blockchainAddressGetHistory: (address) => {
shepherd.log('insight blockchainAddressGetHistory', true);
return new shepherd.Promise((resolve, reject) => {
let options = {
url: `${shepherd.insightJSCoreActiveCoin.address}/${apiRoutes('transactions', address)}`,
method: 'GET',
};
console.log(`${shepherd.insightJSCoreActiveCoin.address}/${apiRoutes('transactions', address)}`);
// send back body on both success and error
// this bit replicates iguana core's behaviour
request(options, (error, response, body) => {
console.log(body);
if (response &&
response.statusCode &&
response.statusCode === 200) {
try {
const _parsedBody = JSON.parse(body);
console.log(_parsedBody.txs || _parsedBody.transactions);
if (_parsedBody &&
(_parsedBody.txs || _parsedBody.transactions)) {
const _txs = _parsedBody.txs || _parsedBody.transactions;
let txs = [];
for (let i = 0; i < _txs.length; i++) {
const _parsedTx = {
format: {
txid: _txs[i].txid,
version: _txs[i].version,
locktime: _txs[i].locktime,
},
inputs: _txs[i].vin,
outputs: _txs[i].vout,
timestamp: _txs[i].time,
confirmations: _txs[i].confirmations,
};
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, address, shepherd.insightJSCoreActiveCoin.abbr.toLowerCase());
if (formattedTx.type) {
formattedTx.blocktime = _parsedTx.timestamp;
formattedTx.timereceived = _parsedTx.timestamp;
formattedTx.hex = 'N/A';
formattedTx.inputs = _parsedTx.inputs;
formattedTx.outputs = _parsedTx.outputs;
formattedTx.locktime = _parsedTx.format.locktime;
txs.push(formattedTx);
} else {
formattedTx[0].blocktime = _parsedTx.timestamp;
formattedTx[0].timereceived = _parsedTx.timestamp;
formattedTx[0].hex = 'N/A';
formattedTx[0].inputs = _parsedTx.inputs;
formattedTx[0].outputs = _parsedTx.outputs;
formattedTx[0].locktime = _parsedTx.format.locktime;
formattedTx[1].blocktime = _parsedTx.timestamp;
formattedTx[1].timereceived = _parsedTx.timestamp;
formattedTx[1].hex = 'N/A';
formattedTx[1].inputs = _parsedTx.inputs;
formattedTx[1].outputs = _parsedTx.outputs;
formattedTx[1].locktime = _parsedTx.format.locktime;
txs.push(formattedTx[0]);
txs.push(formattedTx[1]);
}
}
resolve(txs);
}
shepherd.log(`insight blockchainAddressGetHistory ${address}`);
} catch (e) {
shepherd.log(`parse error insight blockchainAddressGetHistory ${address}`, true);
}
} else {
shepherd.log(`req error insight blockchainAddressGetHistory ${address}`, true);
}
});
});
},
};
};
return shepherd;
}

8
routes/shepherd/electrum/keys.js

@ -21,6 +21,7 @@ module.exports = (shepherd) => {
shepherd.seedToWif = (seed, network, iguana) => {
let bytes;
// legacy seed edge case
if (process.argv.indexOf('spvold=true') > -1) {
bytes = buggySha256(seed, { asBytes: true });
} else {
@ -142,7 +143,7 @@ module.exports = (shepherd) => {
} else {
return 'Unable to find matching coin version';
}
} catch(e) {
} catch (e) {
return 'Invalid pub address';
}
};
@ -153,12 +154,13 @@ module.exports = (shepherd) => {
try {
const _b58check = shepherd.isZcash(network.toLowerCase()) ? bitcoinZcash.address.fromBase58Check(address) : bitcoin.address.fromBase58Check(address);
if (_b58check.version === _network.pubKeyHash) {
if (_b58check.version === _network.pubKeyHash ||
(address[0] === 'b' && shepherd.getNetworkData(network.toLowerCase()).pubKeyHash === 60)) { // kmd multisig edge case
return true;
} else {
return false;
}
} catch(e) {
} catch (e) {
return 'Invalid pub address';
}
};

29
routes/shepherd/electrum/listunspent.js

@ -1,11 +1,14 @@
// TODO: watchonly spendable switch
const Promise = require('bluebird');
module.exports = (shepherd) => {
shepherd.listunspent = (ecl, address, network, full, verify) => {
let _atLeastOneDecodeTxFailed = false;
if (full) {
return new shepherd.Promise((resolve, reject) => {
if (full &&
!ecl.insight) {
return new Promise((resolve, reject) => {
ecl.connect();
ecl.blockchainAddressListunspent(address)
.then((_utxoJSON) => {
@ -29,12 +32,12 @@ module.exports = (shepherd) => {
ecl.close();
resolve('no valid utxo');
} else {
shepherd.Promise.all(_utxo.map((_utxoItem, index) => {
return new shepherd.Promise((resolve, reject) => {
Promise.all(_utxo.map((_utxoItem, index) => {
return new Promise((resolve, reject) => {
shepherd.getTransaction(_utxoItem['tx_hash'], network, ecl)
.then((_rawtxJSON) => {
shepherd.log('electrum gettransaction ==>', true);
shepherd.log(index + ' | ' + (_rawtxJSON.length - 1), true);
shepherd.log(`${index} | ${(_rawtxJSON.length - 1)}`, true);
shepherd.log(_rawtxJSON, true);
// decode tx
@ -72,7 +75,11 @@ module.exports = (shepherd) => {
// merkle root verification against another electrum server
if (verify) {
shepherd.verifyMerkleByCoin(shepherd.findCoinName(network), _utxoItem['tx_hash'], _utxoItem.height)
shepherd.verifyMerkleByCoin(
shepherd.findCoinName(network),
_utxoItem['tx_hash'],
_utxoItem.height
)
.then((verifyMerkleRes) => {
if (verifyMerkleRes &&
verifyMerkleRes === shepherd.CONNECTION_ERROR_OR_INCOMPLETE_DATA) {
@ -99,7 +106,11 @@ module.exports = (shepherd) => {
// merkle root verification against another electrum server
if (verify) {
shepherd.verifyMerkleByCoin(shepherd.findCoinName(network), _utxoItem['tx_hash'], _utxoItem.height)
shepherd.verifyMerkleByCoin(
shepherd.findCoinName(network),
_utxoItem['tx_hash'],
_utxoItem.height
)
.then((verifyMerkleRes) => {
if (verifyMerkleRes &&
verifyMerkleRes === shepherd.CONNECTION_ERROR_OR_INCOMPLETE_DATA) {
@ -141,7 +152,7 @@ module.exports = (shepherd) => {
});
});
} else {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
ecl.connect();
ecl.blockchainAddressListunspent(address)
.then((json) => {
@ -161,7 +172,7 @@ module.exports = (shepherd) => {
shepherd.get('/electrum/listunspent', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const network = req.query.network || shepherd.findNetworkObj(req.query.coin);
const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
const ecl = shepherd.electrumServers[network].proto === 'insight' ? shepherd.insightJSCore(shepherd.electrumServers[network]) : new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
if (req.query.full &&
req.query.full === 'true') {

21
routes/shepherd/electrum/merkle.js

@ -1,10 +1,13 @@
const Promise = require('bluebird');
const reverse = require('buffer-reverse');
const crypto = require('crypto');
const _sha256 = (data) => {
return crypto.createHash('sha256').update(data).digest();
};
module.exports = (shepherd) => {
// get merkle root
shepherd.getMerkleRoot = (txid, proof, pos) => {
const reverse = require('buffer-reverse');
const _sha256 = (data) => {
return shepherd.crypto.createHash('sha256').update(data).digest();
}
let hash = txid;
let serialized;
@ -46,7 +49,7 @@ module.exports = (shepherd) => {
let ecl = new shepherd.electrumJSCore(_mainServer[1], _mainServer[0], _mainServer[2]); // tcp or tls
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
shepherd.log(`main server: ${mainServer}`, true);
shepherd.log(`verification server: ${randomServer}`, true);
@ -106,7 +109,7 @@ module.exports = (shepherd) => {
shepherd.log(shepherd.electrumCoins[coin].server, true);
shepherd.log(shepherd.electrumCoins[coin].serverList, true);
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
if (_serverList !== 'none') {
let _filteredServerList = [];
@ -134,7 +137,11 @@ module.exports = (shepherd) => {
shepherd.get('/electrum/merkle/verify', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
shepherd.verifyMerkleByCoin(req.query.coin, req.query.txid, req.query.height)
const _coin = req.query.coin;
const _txid = req.query.txid;
const _height = req.query.height;
shepherd.verifyMerkleByCoin(_coin, _txid, _height)
.then((verifyMerkleRes) => {
const successObj = {
msg: 'success',

24
routes/shepherd/electrum/network.js

@ -10,12 +10,26 @@ module.exports = (shepherd) => {
network === 'zec' ||
network === 'zcash' ||
network === 'ZCASH' ||
network === 'sng' ||
network === 'SNG' ||
network === 'HUSH' ||
network === 'hush' ||
network === 'ZCL' ||
network === 'zcl' ||
network === 'BTCZ' ||
network === 'btcz') {
network === 'btcz' ||
network === 'VOT' ||
network === 'vot' ||
network === 'BTCP' ||
network === 'btcp' ||
network === 'XZC' ||
network === 'xzc' ||
network === 'ZEN' ||
network === 'zen' ||
network === 'SYS' ||
network === 'sys' ||
network === 'SMART' ||
network === 'smart') {
return true;
}
};
@ -24,16 +38,20 @@ module.exports = (shepherd) => {
if (network === 'BLK' ||
network === 'blk' ||
network === 'DNR' ||
network === 'dnr') {
network === 'dnr' ||
network === 'XWC' ||
network === 'xwc') {
return true;
}
};
shepherd.electrumJSTxDecoder = (rawtx, networkName, network) => {
shepherd.electrumJSTxDecoder = (rawtx, networkName, network, insight) => {
if (shepherd.isZcash(networkName)) {
return txDecoder.zcash(rawtx, network);
} else if (shepherd.isPos(networkName)) {
return txDecoder.pos(rawtx, network);
} else if (insight) {
console.log('insight decoder');
} else {
return txDecoder.default(rawtx, network);
}

36
routes/shepherd/electrum/transactions.js

@ -1,13 +1,14 @@
const async = require('async');
const Promise = require('bluebird');
module.exports = (shepherd) => {
shepherd.sortTransactions = (transactions) => {
shepherd.sortTransactions = (transactions, sortBy) => {
return transactions.sort((b, a) => {
if (a.height < b.height) {
if (a[sortBy ? sortBy : 'height'] < b[sortBy ? sortBy : 'height']) {
return -1;
}
if (a.height > b.height) {
if (a[sortBy ? sortBy : 'height'] > b[sortBy ? sortBy : 'height']) {
return 1;
}
@ -16,7 +17,7 @@ module.exports = (shepherd) => {
}
shepherd.getTransaction = (txid, network, ecl) => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
if (!shepherd.electrumCache[network]) {
shepherd.electrumCache[network] = {};
}
@ -40,7 +41,7 @@ module.exports = (shepherd) => {
}
shepherd.getBlockHeader = (height, network, ecl) => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
if (!shepherd.electrumCache[network]) {
shepherd.electrumCache[network] = {};
}
@ -66,18 +67,21 @@ module.exports = (shepherd) => {
shepherd.get('/electrum/listtransactions', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const network = req.query.network || shepherd.findNetworkObj(req.query.coin);
const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
const ecl = shepherd.electrumServers[network].proto === 'insight' ? shepherd.insightJSCore(shepherd.electrumServers[network]) : new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
const _address = req.query.address;
const _maxlength = req.query.maxlength;
shepherd.log('electrum listtransactions ==>', true);
if (!req.query.full) {
if (!req.query.full ||
ecl.insight) {
ecl.connect();
ecl.blockchainAddressGetHistory(req.query.address)
ecl.blockchainAddressGetHistory(_address)
.then((json) => {
ecl.close();
shepherd.log(json, true);
json = shepherd.sortTransactions(json);
json = shepherd.sortTransactions(json, 'timestamp');
const successObj = {
msg: 'success',
@ -89,14 +93,14 @@ module.exports = (shepherd) => {
} else {
// !expensive call!
// TODO: limit e.g. 1-10, 10-20 etc
const MAX_TX = req.query.maxlength || 10;
const MAX_TX = _maxlength || 10;
ecl.connect();
ecl.blockchainNumblocksSubscribe()
.then((currentHeight) => {
if (currentHeight &&
Number(currentHeight) > 0) {
ecl.blockchainAddressGetHistory(req.query.address)
ecl.blockchainAddressGetHistory(_address)
.then((json) => {
if (json &&
json.length) {
@ -108,6 +112,7 @@ module.exports = (shepherd) => {
shepherd.log(json.length, true);
let index = 0;
// callback hell, use await?
async.eachOfSeries(json, (transaction, ind, callback) => {
shepherd.getBlockHeader(transaction.height, network, ecl)
.then((blockInfo) => {
@ -130,11 +135,12 @@ module.exports = (shepherd) => {
// shepherd.log(decodedTx.outputs, true);
let index2 = 0;
if (decodedTx &&
decodedTx.inputs &&
decodedTx.inputs.length) {
async.eachOfSeries(decodedTx.inputs, (_decodedInput, ind2, callback2) => {
function checkLoop() {
const checkLoop = () => {
index2++;
if (index2 === decodedTx.inputs.length) {
@ -149,7 +155,7 @@ module.exports = (shepherd) => {
confirmations: Number(transaction.height) === 0 ? 0 : currentHeight - transaction.height,
};
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, req.query.address, network);
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, _address, network);
if (formattedTx.type) {
formattedTx.height = transaction.height;
@ -223,7 +229,7 @@ module.exports = (shepherd) => {
confirmations: Number(transaction.height) === 0 ? 0 : currentHeight - transaction.height,
};
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, req.query.address, network);
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, _address, network);
_rawtx.push(formattedTx);
index++;
@ -251,7 +257,7 @@ module.exports = (shepherd) => {
timestamp: 'cant get block info',
confirmations: Number(transaction.height) === 0 ? 0 : currentHeight - transaction.height,
};
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, req.query.address, network);
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, _address, network);
_rawtx.push(formattedTx);
index++;

2
routes/shepherd/init.js

@ -18,7 +18,7 @@ module.exports = (shepherd) => {
fs.readdir(rootLocation, (err, items) => {
for (let i = 0; i < items.length; i++) {
if (items[i].substr(0, 3) === 'gen') {
console.log(items[i]);
shepherd.log(`remove ${items[i]}`);
fs.unlinkSync(rootLocation + items[i]);
}
}

17
routes/shepherd/log.js

@ -1,3 +1,6 @@
const fs = require('fs-extra');
const Promise = require('bluebird');
module.exports = (shepherd) => {
shepherd.log = (msg, isSpvOut) => {
if (shepherd.appConfig.dev ||
@ -23,14 +26,14 @@ module.exports = (shepherd) => {
const timeFormatted = new Date(Date.now()).toLocaleString('en-US', { hour12: false });
if (shepherd.appConfig.debug) {
if (shepherd.fs.existsSync(`${logLocation}/agamalog.txt`)) {
shepherd.fs.appendFile(`${logLocation}/agamalog.txt`, `${timeFormatted} ${data}\r\n`, (err) => {
if (fs.existsSync(`${logLocation}/agamalog.txt`)) {
fs.appendFile(`${logLocation}/agamalog.txt`, `${timeFormatted} ${data}\r\n`, (err) => {
if (err) {
shepherd.log('error writing log file');
}
});
} else {
shepherd.fs.writeFile(`${logLocation}/agamalog.txt`, `${timeFormatted} ${data}\r\n`, (err) => {
fs.writeFile(`${logLocation}/agamalog.txt`, `${timeFormatted} ${data}\r\n`, (err) => {
if (err) {
shepherd.log('error writing log file');
}
@ -58,7 +61,7 @@ module.exports = (shepherd) => {
});
shepherd.getAppRuntimeLog = () => {
return new shepherd.Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
resolve(shepherd.appRuntimeLog);
});
};
@ -88,7 +91,7 @@ module.exports = (shepherd) => {
};
}
shepherd.fs.writeFile(`${logLocation}/agamalog.json`, JSON.stringify(shepherd.guiLog), (err) => {
fs.writeFile(`${logLocation}/agamalog.json`, JSON.stringify(shepherd.guiLog), (err) => {
if (err) {
shepherd.writeLog('error writing gui log file');
}
@ -118,8 +121,8 @@ module.exports = (shepherd) => {
if (shepherd.checkToken(req.query.token)) {
const logExt = req.query.type === 'txt' ? 'txt' : 'json';
if (shepherd.fs.existsSync(`${shepherd.agamaDir}/shepherd/agamalog.${logExt}`)) {
shepherd.fs.readFile(`${shepherd.agamaDir}/shepherd/agamalog.${logExt}`, 'utf8', (err, data) => {
if (fs.existsSync(`${shepherd.agamaDir}/shepherd/agamalog.${logExt}`)) {
fs.readFile(`${shepherd.agamaDir}/shepherd/agamalog.${logExt}`, 'utf8', (err, data) => {
if (err) {
const errorObj = {
msg: 'error',

1
routes/shepherd/quitDaemon.js

@ -23,6 +23,7 @@ module.exports = (shepherd) => {
const execCliStop = () => {
let _arg = [];
if (chain &&
!shepherd.nativeCoindList[key.toLowerCase()] && key !== 'CHIPS') {
_arg.push(`-ac_name=${chain}`);

15
routes/shepherd/rpc.js

@ -1,5 +1,8 @@
const fs = require('fs-extra');
const os = require('os');
const exec = require('child_process').exec;
const execFile = require('child_process').execFile;
const request = require('request');
module.exports = (shepherd) => {
shepherd.getConf = (chain) => {
@ -16,8 +19,8 @@ module.exports = (shepherd) => {
}
if (fs.existsSync(_confLocation)) {
let _port = shepherd.assetChainPorts[chain];
const _rpcConf = fs.readFileSync(_confLocation, 'utf8');
let _port = shepherd.assetChainPorts[chain];
// any coind
if (shepherd.nativeCoindList[chain.toLowerCase()]) {
@ -111,9 +114,9 @@ module.exports = (shepherd) => {
_arg = `${_arg} -datadir=${shepherd.appConfig.dataDir + (_chain ? '/' + key : '')}`;
}
shepherd.exec(`"${_coindCliBin}" ${_arg}`, (error, stdout, stderr) => {
//shepherd.log(`stdout: ${stdout}`);
//shepherd.log(`stderr: ${stderr}`);
exec(`"${_coindCliBin}" ${_arg}`, (error, stdout, stderr) => {
// shepherd.log(`stdout: ${stdout}`);
// shepherd.log(`stderr: ${stderr}`);
if (error !== null) {
shepherd.log(`exec error: ${error}`);
@ -265,7 +268,7 @@ module.exports = (shepherd) => {
// send back body on both success and error
// this bit replicates iguana core's behaviour
shepherd.request(options, (error, response, body) => {
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
@ -299,7 +302,7 @@ module.exports = (shepherd) => {
}
_arg = _arg.trim().split(' ');
shepherd.execFile(_coindCliBin, _arg, (error, stdout, stderr) => {
execFile(_coindCliBin, _arg, (error, stdout, stderr) => {
shepherd.log(`stdout: ${stdout}`);
shepherd.log(`stderr: ${stderr}`);

6
version

@ -1,3 +1,3 @@
version=0.2.0.30a
type=a-beta
minversion=0.2.0.30
version=0.2.31
type=beta
minversion=0.2.31

2
version_build

@ -1 +1 @@
0.2.0.30a-beta
0.2.31-beta
Loading…
Cancel
Save