├── version_build ├── assets ├── deps │ └── confs │ │ ├── .tmpmarker │ │ ├── TAZ_peers.txt │ │ ├── iguana.conf │ │ ├── ZEC_peers.txt │ │ ├── DGB_peers.txt │ │ ├── GAME_peers.txt │ │ ├── UNO_peers.txt │ │ ├── ZET_peers.txt │ │ ├── BLK_peers.txt │ │ ├── CARB_peers.txt │ │ ├── LTC_peers.txt │ │ ├── KMD_peers.txt │ │ ├── REVS_peers.txt │ │ ├── SXC_peers.txt │ │ ├── SYS_peers.txt │ │ ├── ANC_peers.txt │ │ ├── VIA_peers.txt │ │ ├── BTM_peers.txt │ │ ├── FRK_peers.txt │ │ ├── MZC_peers.txt │ │ ├── BTCD_peers.txt │ │ └── DOGE_peers.txt ├── js │ ├── startup.js │ └── iguana.js ├── .DS_Store └── icons │ ├── vrsc.icns │ ├── vrsc.ico │ ├── vrsc_256x256x32.png │ ├── vrsc_512x512x32.png │ ├── agama_icons │ ├── 16x16.png │ ├── 24x24.png │ ├── 32x32.png │ ├── 48x48.png │ ├── 64x64.png │ ├── 96x96.png │ ├── vrsc.icns │ ├── vrsc.ico │ ├── 128x128.png │ └── 256x256.png │ └── vrsc_1024x1024x32.png ├── .DS_Store ├── gui ├── .DS_Store ├── fetch-bootstrap │ └── fetch-bootstrap.html └── startup │ ├── agama-instance-error.html │ └── app-closing.html ├── routes ├── api │ ├── utils │ │ ├── constants │ │ │ ├── math.js │ │ │ ├── currency_flags.js │ │ │ ├── web3.js │ │ │ ├── index.js │ │ │ ├── supported_dls.js │ │ │ ├── dev_options.js │ │ │ ├── daemons.js │ │ │ ├── eth_networks.js │ │ │ ├── urls.js │ │ │ ├── allowed_paths.js │ │ │ └── file_descriptors.js │ │ ├── flags.js │ │ ├── standardization │ │ │ ├── standardization.js │ │ │ ├── standardizeMiningInfo.js │ │ │ └── standardizeInfo.js │ │ ├── web3 │ │ │ ├── provider.js │ │ │ ├── etherscan.js │ │ │ └── web3Interface.js │ │ ├── objectUtil │ │ │ ├── objectUtil.js │ │ │ ├── flattenObjectProps.js │ │ │ ├── useStringAsKey.js │ │ │ ├── removeElementByProperties.js │ │ │ ├── getBytes.js │ │ │ ├── addMerge.js │ │ │ └── deepmerge.js │ │ ├── cryptoConditions │ │ │ └── cryptoConditionTxUtil.js │ │ ├── dialog-shim.js │ │ ├── unzip.js │ │ ├── rpc │ │ │ ├── rpcError.js │ │ │ └── rpcStatusCodes.js │ │ ├── hashFile.js │ │ ├── auth │ │ │ ├── pluginAuth.js │ │ │ ├── rpcAuth.js │ │ │ └── scalar.js │ │ ├── verifySignature.js │ │ ├── plugin │ │ │ ├── builtin.js │ │ │ └── permissions.js │ │ ├── request │ │ │ └── request.js │ │ └── cache.js │ ├── native │ │ ├── verusid │ │ │ ├── verusid.js │ │ │ ├── login │ │ │ │ ├── verifyRequest.js │ │ │ │ └── signResponse.js │ │ │ └── provision │ │ │ │ ├── verifyIdProvisioningResponse.js │ │ │ │ └── signIdProvisioningRequest.js │ │ ├── closeoffers.js │ │ ├── importwallet.js │ │ ├── setidentitytimelock.js │ │ ├── exportwallet.js │ │ ├── makeoffer.js │ │ ├── takeoffer.js │ │ ├── currencyGraylist.js │ │ ├── zoperations.js │ │ ├── definedchains.js │ │ ├── estimateConversion.js │ │ ├── idRevocation.js │ │ ├── info.js │ │ ├── blockSubsidy.js │ │ ├── sendcurrency.js │ │ ├── getConversionPaths.js │ │ ├── getBlock.js │ │ ├── getVdxfId.js │ │ ├── estimateSendcurrencyFee.js │ │ ├── reservetransfers.js │ │ ├── restart.js │ │ ├── mininginfo.js │ │ ├── getCurrency.js │ │ ├── shieldcoinbase.js │ │ └── cryptoConditions.js │ ├── electrum │ │ ├── parseTxAddresses.js │ │ ├── remove.js │ │ ├── utils.js │ │ ├── info.js │ │ ├── block.js │ │ ├── proxy.js │ │ ├── interest.js │ │ └── addresses.js │ ├── utility_apis │ │ ├── alert.js │ │ ├── pbaas.js │ │ ├── cache.js │ │ └── csvExport.js │ ├── data_files │ │ ├── secrets.js │ │ ├── nameCommitments.js │ │ ├── updateLog.js │ │ └── backup.js │ ├── eth │ │ ├── keys.js │ │ ├── info.js │ │ ├── auth.js │ │ ├── coins.js │ │ ├── balances.js │ │ ├── addresses.js │ │ └── transactions.js │ ├── focus.js │ ├── network │ │ ├── supply │ │ │ ├── coinSupply.js │ │ │ ├── vrsc │ │ │ │ └── vrscCoinSupply.js │ │ │ └── zec │ │ │ │ └── zecCoinSupply.js │ │ └── fees │ │ │ ├── btc │ │ │ └── btcFees.js │ │ │ └── networkFees.js │ ├── paths.js │ ├── dlhandler.js │ ├── numbers.js │ ├── erc20 │ │ ├── auth.js │ │ ├── info.js │ │ ├── addresses.js │ │ ├── balances.js │ │ ├── transactions.js │ │ └── coins.js │ ├── explorer │ │ └── remoteExplorers.js │ ├── appInfo.js │ ├── getSignatureInfo.js │ ├── construct.js │ ├── plugin │ │ ├── builtin │ │ │ ├── authenticator.js │ │ │ └── pbaasvisualizer.js │ │ └── stop.js │ ├── downloadUtil.js │ ├── system.js │ ├── log.js │ ├── confMaxconnections.js │ └── binsUtils.js ├── ipc │ └── index.js ├── electrumjs │ ├── electrumjs.networks.js │ └── electrumServersConfig.js ├── shepherd │ ├── electrum │ │ └── csv.js │ └── deepmerge.js ├── deeplink │ ├── removelink.js │ ├── setuplink.js │ └── openurlhandler.js ├── preloads │ ├── keys.js │ └── plugin │ │ ├── preload-builtin.js │ │ └── preload-default.js ├── fiatList.js ├── children │ ├── fetch-bootstrap │ │ └── window.js │ └── userAgreement │ │ └── window.js ├── zcashParamsSources.js ├── ports.js ├── workers │ └── check_update.js └── nativeCoind.js ├── Brewfile ├── .gitmodules ├── tslint.json ├── version.json ├── keys ├── infura.js └── etherscan.js ├── check_submodule.sh ├── fetch-nspv-bins.sh ├── LICENSE ├── .gitignore ├── test ├── verusid-login.js ├── spec-kmd.js ├── spec-vrsc.js └── spec.js └── README.md /version_build: -------------------------------------------------------------------------------- 1 | 1.2.13 -------------------------------------------------------------------------------- /assets/deps/confs/.tmpmarker: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/js/startup.js: -------------------------------------------------------------------------------- 1 | //startup separator for superNET iguana 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/.DS_Store -------------------------------------------------------------------------------- /assets/deps/confs/TAZ_peers.txt: -------------------------------------------------------------------------------- 1 | 176.9.26.39 2 | 5.9.102.210 3 | 78.47.196.146 4 | -------------------------------------------------------------------------------- /assets/deps/confs/iguana.conf: -------------------------------------------------------------------------------- 1 | { "exchanges":[{"name":"poloniex"},{"name":"btc38"}] } -------------------------------------------------------------------------------- /gui/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/gui/.DS_Store -------------------------------------------------------------------------------- /assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/.DS_Store -------------------------------------------------------------------------------- /assets/icons/vrsc.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/vrsc.icns -------------------------------------------------------------------------------- /assets/icons/vrsc.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/vrsc.ico -------------------------------------------------------------------------------- /assets/deps/confs/ZEC_peers.txt: -------------------------------------------------------------------------------- 1 | 198.100.147.192 2 | 159.203.60.92 3 | 188.166.31.56 4 | 46.105.126.215 5 | -------------------------------------------------------------------------------- /routes/api/utils/constants/math.js: -------------------------------------------------------------------------------- 1 | const SATOSHIS = 100000000 2 | 3 | module.exports = { 4 | SATOSHIS 5 | } -------------------------------------------------------------------------------- /Brewfile: -------------------------------------------------------------------------------- 1 | tap "homebrew/bundle" 2 | tap "homebrew/cask" 3 | tap "homebrew/core" 4 | brew "gcc@5" 5 | brew "libidn2" 6 | -------------------------------------------------------------------------------- /assets/icons/vrsc_256x256x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/vrsc_256x256x32.png -------------------------------------------------------------------------------- /assets/icons/vrsc_512x512x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/vrsc_512x512x32.png -------------------------------------------------------------------------------- /routes/ipc/index.js: -------------------------------------------------------------------------------- 1 | const { startIPCHandlers } = require('./ipc') 2 | 3 | module.exports = { 4 | startIPCHandlers 5 | } -------------------------------------------------------------------------------- /assets/icons/agama_icons/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/agama_icons/16x16.png -------------------------------------------------------------------------------- /assets/icons/agama_icons/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/agama_icons/24x24.png -------------------------------------------------------------------------------- /assets/icons/agama_icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/agama_icons/32x32.png -------------------------------------------------------------------------------- /assets/icons/agama_icons/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/agama_icons/48x48.png -------------------------------------------------------------------------------- /assets/icons/agama_icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/agama_icons/64x64.png -------------------------------------------------------------------------------- /assets/icons/agama_icons/96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/agama_icons/96x96.png -------------------------------------------------------------------------------- /assets/icons/agama_icons/vrsc.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/agama_icons/vrsc.icns -------------------------------------------------------------------------------- /assets/icons/agama_icons/vrsc.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/agama_icons/vrsc.ico -------------------------------------------------------------------------------- /assets/icons/vrsc_1024x1024x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/vrsc_1024x1024x32.png -------------------------------------------------------------------------------- /assets/icons/agama_icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/agama_icons/128x128.png -------------------------------------------------------------------------------- /assets/icons/agama_icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/HEAD/assets/icons/agama_icons/256x256.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "gui/Verus-Desktop-GUI"] 2 | path = gui/Verus-Desktop-GUI 3 | url = https://github.com/VerusCoin/Verus-Desktop-GUI 4 | -------------------------------------------------------------------------------- /routes/electrumjs/electrumjs.networks.js: -------------------------------------------------------------------------------- 1 | let networks = require('agama-wallet-lib/src/bitcoinjs-networks'); 2 | 3 | module.exports = networks; -------------------------------------------------------------------------------- /assets/deps/confs/DGB_peers.txt: -------------------------------------------------------------------------------- 1 | 212.129.1.77 2 | 157.161.128.58 3 | 178.33.228.14 4 | 108.61.10.90 5 | 104.236.32.184 6 | 66.228.56.115 7 | 167.160.36.126 8 | -------------------------------------------------------------------------------- /assets/deps/confs/GAME_peers.txt: -------------------------------------------------------------------------------- 1 | 46.105.118.15 2 | 89.36.212.56 3 | 85.214.23.49 4 | 194.135.81.138 5 | 111.99.55.252 6 | 104.172.24.79 7 | 104.236.84.230 8 | 104.255.67.131 9 | -------------------------------------------------------------------------------- /assets/deps/confs/UNO_peers.txt: -------------------------------------------------------------------------------- 1 | 195.154.223.134 2 | 85.25.217.233 3 | 104.172.24.79 4 | 188.165.42.51 5 | 45.32.244.201 6 | 52.23.179.46 7 | 192.95.29.72 8 | 185.50.213.123 9 | -------------------------------------------------------------------------------- /assets/deps/confs/ZET_peers.txt: -------------------------------------------------------------------------------- 1 | 208.94.242.218 2 | 85.25.217.233 3 | 76.95.178.229 4 | 155.94.243.135 5 | 108.61.10.90 6 | 155.254.49.54 7 | 198.27.81.25 8 | 94.249.166.140 9 | -------------------------------------------------------------------------------- /routes/api/utils/constants/currency_flags.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | IS_TOKEN_FLAG: 0x20, 3 | IS_FRACTIONAL_FLAG: 0x01, 4 | IS_PBAAS_FLAG: 0x100, 5 | IS_GATEWAY_FLAG: 0x80 6 | } -------------------------------------------------------------------------------- /assets/deps/confs/BLK_peers.txt: -------------------------------------------------------------------------------- 1 | 188.112.70.36 2 | 1.34.180.245 3 | 104.131.248.191 4 | 104.174.97.3 5 | 104.204.109.11 6 | 106.68.86.178 7 | 108.174.171.46 8 | 108.219.100.78 9 | 112.198.64.34 10 | -------------------------------------------------------------------------------- /routes/api/native/verusid/verusid.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.verusid = {} 3 | api.native.verusid.login = {} 4 | api.native.verusid.provision = {} 5 | 6 | return api; 7 | }; 8 | -------------------------------------------------------------------------------- /routes/shepherd/electrum/csv.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | const { secondsToString } = require('agama-wallet-lib/src/time'); 3 | 4 | module.exports = (shepherd) => { 5 | return shepherd; 6 | }; -------------------------------------------------------------------------------- /routes/api/utils/flags.js: -------------------------------------------------------------------------------- 1 | // Takes in an integer and checks it against a flag, returns true/false 2 | function checkFlag(integer, flag) { 3 | return (flag & integer) == flag 4 | } 5 | 6 | module.exports = checkFlag -------------------------------------------------------------------------------- /assets/deps/confs/CARB_peers.txt: -------------------------------------------------------------------------------- 1 | 54.85.71.51 2 | 87.98.182.171 3 | 98.115.147.74 4 | 85.25.146.74 5 | 86.21.79.62 6 | 46.101.43.245 7 | 144.76.64.123 8 | 193.192.37.135 9 | 88.101.128.228 10 | 85.25.201.216 11 | 85.236.188.213 12 | -------------------------------------------------------------------------------- /routes/deeplink/removelink.js: -------------------------------------------------------------------------------- 1 | const { WALLET_VDXF_KEY } = require("verus-typescript-primitives") 2 | 3 | function removelink(app) { 4 | return app.removeAsDefaultProtocolClient(WALLET_VDXF_KEY.vdxfid) 5 | } 6 | 7 | module.exports = removelink -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "no-console": false 9 | }, 10 | "rulesDirectory": [] 11 | } -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.2.13", 3 | "minVersion": "1.2.9-2", 4 | "versionUrl": "https://raw.githubusercontent.com/VerusCoin/Verus-Desktop/master/version.json", 5 | "repository": "https://github.com/VerusCoin/Verus-Desktop/" 6 | } 7 | -------------------------------------------------------------------------------- /routes/api/electrum/parseTxAddresses.js: -------------------------------------------------------------------------------- 1 | const parseTransactionAddresses = require('agama-wallet-lib/src/transaction-type'); 2 | 3 | module.exports = (api) => { 4 | api.parseTransactionAddresses = parseTransactionAddresses; 5 | 6 | return api; 7 | }; -------------------------------------------------------------------------------- /routes/api/utils/constants/web3.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | TRANSFER_SKIP_CALLSTATIC_TOKENS: ['0xdac17f958d2ee523a2206206994597c13d831ec7'], 3 | CONTRACT_SYMBOLS: { 4 | ["0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2".toLowerCase()]: "MKR" 5 | } 6 | } -------------------------------------------------------------------------------- /routes/api/utils/constants/index.js: -------------------------------------------------------------------------------- 1 | const allowed_paths = require('./allowed_paths') 2 | const file_descriptors = require('./file_descriptors') 3 | const daemons = require('./daemons') 4 | 5 | module.exports = { 6 | ...allowed_paths, 7 | ...file_descriptors, 8 | ...daemons 9 | } -------------------------------------------------------------------------------- /assets/deps/confs/LTC_peers.txt: -------------------------------------------------------------------------------- 1 | 37.97.159.116 2 | 5.9.67.48 3 | 86.107.207.194 4 | 46.28.206.204 5 | 91.232.188.3 6 | 209.180.247.49 7 | 61.150.109.231 8 | 24.217.216.92 9 | 219.117.248.55 10 | 131.161.120.110 11 | 122.224.51.104 12 | 78.25.32.206 13 | 46.63.26.63 14 | 200.79.231.62 15 | -------------------------------------------------------------------------------- /keys/infura.js: -------------------------------------------------------------------------------- 1 | // THIS IS SENSITIVE DATA, DO NOT PUSH TO GIT! 2 | 3 | // API Keys for infura are stored here, if you fork Verus-Desktop, you need to use your 4 | // own here or ETH/ERC20 coins will not work 5 | 6 | module.exports = { 7 | INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID 8 | } -------------------------------------------------------------------------------- /keys/etherscan.js: -------------------------------------------------------------------------------- 1 | // THIS IS SENSITIVE DATA, DO NOT PUSH TO GIT! 2 | 3 | // API Keys for etherscan are stored here, if you fork Verus-Desktop, you need to use your 4 | // own here or ETH/ERC20 coins will not work 5 | 6 | module.exports = { 7 | ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY 8 | } -------------------------------------------------------------------------------- /routes/api/utility_apis/alert.js: -------------------------------------------------------------------------------- 1 | const { dialog } = require("../utils/dialog-shim"); 2 | 3 | module.exports = (api, mainWindow) => { 4 | api.alertMainWindow = (messageBoxParams, callback) => { 5 | return dialog.showMessageBox(mainWindow, messageBoxParams, callback) 6 | } 7 | 8 | return api; 9 | }; -------------------------------------------------------------------------------- /assets/deps/confs/KMD_peers.txt: -------------------------------------------------------------------------------- 1 | 148.251.57.148 2 | 149.56.28.84 3 | 176.9.26.39 4 | 94.102.63.199 5 | 5.9.102.210 6 | 88.198.65.74 7 | 94.102.63.200 8 | 78.47.196.146 9 | 104.255.64.3 10 | 221.121.144.140 11 | 103.18.58.150 12 | 103.18.58.146 13 | 213.202.253.10 14 | 185.106.121.32 15 | 27.100.36.201 16 | -------------------------------------------------------------------------------- /assets/deps/confs/REVS_peers.txt: -------------------------------------------------------------------------------- 1 | 148.251.57.148 2 | 149.56.28.84 3 | 176.9.26.39 4 | 94.102.63.199 5 | 5.9.102.210 6 | 88.198.65.74 7 | 94.102.63.200 8 | 78.47.196.146 9 | 104.255.64.3 10 | 221.121.144.140 11 | 103.18.58.150 12 | 103.18.58.146 13 | 213.202.253.10 14 | 185.106.121.32 15 | 27.100.36.201 16 | -------------------------------------------------------------------------------- /assets/deps/confs/SXC_peers.txt: -------------------------------------------------------------------------------- 1 | 104.238.221.17:16814 2 | 148.163.102.28:16814 3 | 167.160.36.152:16814 4 | 192.227.158.136:16814 5 | 213.46.197.237:16814 6 | 87.204.149.94:16814 7 | 45.43.26.103:16814 8 | 172.110.18.177:16814 9 | 172.110.18.178:16814 10 | 185.116.238.204:16814 11 | 84.242.207.225:16814 12 | -------------------------------------------------------------------------------- /routes/api/utils/constants/supported_dls.js: -------------------------------------------------------------------------------- 1 | const { LOGIN_CONSENT_REQUEST_VDXF_KEY } = require("verus-typescript-primitives") 2 | 3 | const CALLBACK_HOST = 'x-callback-url' 4 | 5 | const SUPPORTED_DLS = [LOGIN_CONSENT_REQUEST_VDXF_KEY.vdxfid] 6 | 7 | module.exports = { 8 | SUPPORTED_DLS, 9 | CALLBACK_HOST 10 | } -------------------------------------------------------------------------------- /routes/api/utils/constants/dev_options.js: -------------------------------------------------------------------------------- 1 | const IS_TESTNET = false; 2 | const ROOT_SYSTEM_ID = IS_TESTNET ? "iJhCezBExJHvtyH3fGhNnt2NhU4Ztkf2yq" : "i5w5MuNik5NtLcYmNzcvaoixooEebB6MGV"; 3 | const ROOT_SYSTEM_NAME = IS_TESTNET ? "VRSCTEST" : "VRSC"; 4 | 5 | module.exports = { 6 | IS_TESTNET, 7 | ROOT_SYSTEM_ID, 8 | ROOT_SYSTEM_NAME 9 | } -------------------------------------------------------------------------------- /routes/preloads/keys.js: -------------------------------------------------------------------------------- 1 | const { randomBytes } = require('crypto'); 2 | 3 | const MasterSecret = randomBytes(32).toString('hex') 4 | const BuiltinSecret = randomBytes(32).toString('hex') 5 | const apiShieldKey = randomBytes(32).toString('hex') 6 | 7 | module.exports = { 8 | MasterSecret, 9 | apiShieldKey, 10 | BuiltinSecret 11 | } -------------------------------------------------------------------------------- /routes/api/utils/standardization/standardization.js: -------------------------------------------------------------------------------- 1 | const standardizeMiningInfo = require('./standardizeMiningInfo') 2 | const standardizeInfo = require('./standardizeInfo') 3 | const standardizeEthTxObj = require('./standardizeEthTxObj') 4 | 5 | module.exports = { 6 | standardizeMiningInfo, 7 | standardizeInfo, 8 | standardizeEthTxObj 9 | } -------------------------------------------------------------------------------- /routes/api/utils/constants/daemons.js: -------------------------------------------------------------------------------- 1 | const VERUS_DAEMON = 'verusd'; 2 | const KOMODO_DAEMON = 'komodod'; 3 | const PIRATE_DAEMON = 'pirated'; 4 | 5 | const DAEMON_NAMES = [ 6 | VERUS_DAEMON, 7 | KOMODO_DAEMON, 8 | PIRATE_DAEMON 9 | ]; 10 | 11 | module.exports = { 12 | VERUS_DAEMON, 13 | KOMODO_DAEMON, 14 | PIRATE_DAEMON, 15 | DAEMON_NAMES 16 | } -------------------------------------------------------------------------------- /routes/api/data_files/secrets.js: -------------------------------------------------------------------------------- 1 | const { BUILTIN_SECRET, BUILTIN_SECRET_DESC } = require('../utils/constants/index') 2 | 3 | module.exports = (api) => { 4 | api.loadBuiltinSecret = () => api.loadJsonFile(BUILTIN_SECRET, BUILTIN_SECRET_DESC, 0o600); 5 | api.saveBuiltinSecret = (secrets) => api.saveJsonFile(secrets, BUILTIN_SECRET, BUILTIN_SECRET_DESC, 0o600); 6 | 7 | return api; 8 | }; -------------------------------------------------------------------------------- /routes/api/utils/constants/eth_networks.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ETH_HOMESTEAD: { 3 | key: "homestead", 4 | id: 1 5 | }, 6 | ETH_ROPSTEN: { 7 | key: "ropsten", 8 | id: 3 9 | }, 10 | ETH_RINKEBY: { 11 | key: "rinkeby", 12 | id: 4 13 | }, 14 | ETH_GOERLI: { 15 | key: "goerli", 16 | id: 5 17 | }, 18 | ETH_KOVAN: { 19 | key: "kovan", 20 | id: 42 21 | } 22 | } -------------------------------------------------------------------------------- /routes/api/data_files/nameCommitments.js: -------------------------------------------------------------------------------- 1 | const { NAME_COMMITMENTS, NAME_COMMITMENTS_DESC } = require('../utils/constants/index') 2 | 3 | module.exports = (api) => { 4 | api.loadLocalCommitments = () => 5 | api.loadJsonFile(NAME_COMMITMENTS, NAME_COMMITMENTS_DESC); 6 | api.saveLocalCommitments = (commitments) => 7 | api.saveJsonFile(commitments, NAME_COMMITMENTS, NAME_COMMITMENTS_DESC); 8 | 9 | return api; 10 | }; -------------------------------------------------------------------------------- /routes/api/utils/web3/provider.js: -------------------------------------------------------------------------------- 1 | const Web3Interface = require('./web3Interface') 2 | const { ETHERSCAN_API_KEY } = require('../../../../keys/etherscan') 3 | const { INFURA_PROJECT_ID } = require('../../../../keys/infura') 4 | 5 | const createInterface = (network) => { 6 | return new Web3Interface(network, { 7 | etherscan: ETHERSCAN_API_KEY, 8 | infura: INFURA_PROJECT_ID 9 | }) 10 | } 11 | 12 | module.exports = createInterface -------------------------------------------------------------------------------- /assets/js/iguana.js: -------------------------------------------------------------------------------- 1 | //SuperNET iguana app launcher 2 | 3 | //var exec = require('child_process').exec 4 | //exec does not return obj with stream but instead the whole buffer output from proc 5 | //spawn returns objects with stderr and out streams 6 | //for question contact ca333@keemail.me 7 | 8 | const spawn = require('child_process').spawn; 9 | var iguana = path.join(__dirname, '/assets/iguana/iguana'); 10 | //var os = require('os'); 11 | -------------------------------------------------------------------------------- /routes/api/eth/keys.js: -------------------------------------------------------------------------------- 1 | const { 2 | etherKeys, 3 | seedToPriv, 4 | } = require('agama-wallet-lib/src/keys'); 5 | 6 | module.exports = (api) => { 7 | api.eth._keys = (seed) => { 8 | seed = seedToPriv(seed, 'eth'); 9 | const signer = etherKeys(seed, true) 10 | 11 | return { 12 | address: signer.signingKey.address, 13 | pub: signer.signingKey.publicKey, 14 | signer 15 | } 16 | }; 17 | 18 | return api; 19 | }; -------------------------------------------------------------------------------- /routes/api/utils/constants/urls.js: -------------------------------------------------------------------------------- 1 | const VERUS_WIKI_WALLET_BACKUPS = "https://wiki.verus.io/#!how-to/how-to_backup_my_wallet.md" 2 | const VERUS_DISCORD = 'https://discord.gg/VRKMP2S' 3 | const VERUS_WIKI = 'https://wiki.verus.io/#!index.md' 4 | const VERUS_DESKTOP_UPDATE_DL = "https://verus.io/wallet/desktop-wallet" 5 | 6 | module.exports = { 7 | VERUS_DESKTOP_UPDATE_DL, 8 | VERUS_WIKI, 9 | VERUS_DISCORD, 10 | VERUS_WIKI_WALLET_BACKUPS 11 | } -------------------------------------------------------------------------------- /routes/api/utils/objectUtil/objectUtil.js: -------------------------------------------------------------------------------- 1 | const addMerge = require('./addMerge') 2 | const deepmerge = require('./deepmerge') 3 | const flattenObjectProps = require('./flattenObjectProps') 4 | const removeElementByProperties = require('./removeElementByProperties') 5 | const useStringAsKey = require('./useStringAsKey') 6 | 7 | module.exports = { 8 | addMerge, 9 | deepmerge, 10 | flattenObjectProps, 11 | removeElementByProperties, 12 | useStringAsKey 13 | } -------------------------------------------------------------------------------- /assets/deps/confs/SYS_peers.txt: -------------------------------------------------------------------------------- 1 | 176.9.13.13 2 | 162.210.92.46 3 | 146.0.32.101 4 | 144.76.94.38 5 | 50.157.173.168 6 | 188.165.3.6 7 | 88.198.15.19 8 | 192.95.29.72 9 | 108.61.10.90 10 | 71.97.31.194 11 | 40.86.87.8 12 | 45.79.215.60 13 | 97.124.163.6 14 | 192.241.200.33 15 | 184.164.147.82 16 | 162.243.59.178 17 | 107.178.109.224 18 | 198.15.127.242 19 | 98.115.147.74 20 | 194.135.90.38 21 | 86.131.170.245 22 | 107.170.185.5 23 | 216.14.119.170 24 | 108.170.26.210 25 | 183.131.213.30 26 | -------------------------------------------------------------------------------- /assets/deps/confs/ANC_peers.txt: -------------------------------------------------------------------------------- 1 | 84.73.4.183 2 | 98.115.147.74 3 | 192.241.187.222 4 | 159.203.208.102 5 | 85.25.44.119 6 | 178.32.251.114 7 | 109.155.227.178 8 | 146.0.32.101 9 | 108.61.10.90 10 | 198.27.82.134 11 | 80.74.157.31 12 | 192.241.183.16 13 | 164.132.25.194 14 | 128.199.47.200 15 | 173.255.197.64 16 | 46.101.136.168 17 | 207.192.70.250 18 | 54.201.183.106 19 | 211.149.175.37 20 | 128.199.192.241 21 | 216.146.143.177 22 | 82.164.213.27 23 | 107.170.167.218 24 | 195.154.223.134 25 | -------------------------------------------------------------------------------- /assets/deps/confs/VIA_peers.txt: -------------------------------------------------------------------------------- 1 | 84.73.4.183 2 | 98.115.147.74 3 | 192.241.187.222 4 | 159.203.208.102 5 | 85.25.44.119 6 | 178.32.251.114 7 | 109.155.227.178 8 | 146.0.32.101 9 | 108.61.10.90 10 | 198.27.82.134 11 | 80.74.157.31 12 | 192.241.183.16 13 | 164.132.25.194 14 | 128.199.47.200 15 | 173.255.197.64 16 | 46.101.136.168 17 | 207.192.70.250 18 | 54.201.183.106 19 | 211.149.175.37 20 | 128.199.192.241 21 | 216.146.143.177 22 | 82.164.213.27 23 | 107.170.167.218 24 | 195.154.223.134 25 | -------------------------------------------------------------------------------- /check_submodule.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ### Script will check Verus-Desktop-GUI submodule in gui folder. 3 | ### If you used git clone without --recursive option this is way to go. 4 | 5 | PWD=`pwd` 6 | SIZE=`du -sk gui/Verus-Desktop-GUI` 7 | 8 | echo "Checking Verus-Desktop-GUI folder." 9 | cd gui/Verus-Desktop-GUI && \ 10 | git submodule update --recursive && \ 11 | cd ../.. && \ 12 | echo "Folder looks fine." || \ 13 | echo "Some problem with cloning submodule Verus-Desktop-GUI." 14 | echo 15 | -------------------------------------------------------------------------------- /assets/deps/confs/BTM_peers.txt: -------------------------------------------------------------------------------- 1 | 70.168.53.153:9265 2 | 146.0.32.101:9265 3 | 24.143.47.161:9265 4 | 139.162.128.92:9265 5 | 85.24.169.215:9265 6 | 98.115.147.74:9265 7 | 192.124.224.254:9265 8 | 45.33.65.161:9265 9 | 184.166.27.254:9265 10 | 139.59.160.118:9265 11 | 98.127.109.96:9265 12 | 101.173.200.202:9265 13 | 157.161.128.55:9265 14 | 104.172.24.79:9265 15 | 158.69.216.182:9265 16 | 72.209.139.213:9265 17 | 198.205.118.181:9265 18 | 101.173.197.85:9265 19 | 174.36.9.130:9265 20 | 84.24.208.22:9265 21 | -------------------------------------------------------------------------------- /routes/api/utils/cryptoConditions/cryptoConditionTxUtil.js: -------------------------------------------------------------------------------- 1 | // TODO: Fix and move to cryptoConditions native file 2 | 3 | const extractReserveTransfers = (txJson) => { 4 | let transfers = [] 5 | 6 | txJson.vout.map(output => { 7 | if (output.scriptPubKey.type === 'cryptocondition' && output.scriptPubKey["reservetransfer"] != null) { 8 | transfers.push(output.scriptPubKey.reservetransfer) 9 | } 10 | }) 11 | 12 | return transfers; 13 | } 14 | 15 | module.exports = { extractReserveTransfers } -------------------------------------------------------------------------------- /routes/fiatList.js: -------------------------------------------------------------------------------- 1 | const fiatList = [ 2 | 'usd', 3 | 'eur', 4 | 'aud', 5 | 'brl', 6 | 'gbp', 7 | 'bgn', 8 | 'cad', 9 | 'hrk', 10 | 'czk', 11 | 'cny', 12 | 'dkk', 13 | 'hkd', 14 | 'huf', 15 | 'inr', 16 | 'idr', 17 | 'ils', 18 | 'jpy', 19 | 'krw', 20 | 'myr', 21 | 'mxn', 22 | 'nzd', 23 | 'nok', 24 | 'php', 25 | 'pln', 26 | 'ron', 27 | 'rub', 28 | 'sgd', 29 | 'zar', 30 | 'sek', 31 | 'chf', 32 | 'thb', 33 | 'try' 34 | ]; 35 | 36 | module.exports = fiatList; -------------------------------------------------------------------------------- /routes/api/focus.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.setupFocusApis = (focusFunction) => { 3 | api.focusApp = focusFunction 4 | 5 | api.setPost('/plugin/focus', async (req, res, next) => { 6 | try { 7 | api.focusApp() 8 | 9 | res.send(JSON.stringify({ 10 | msg: 'success' 11 | })) 12 | } catch(e) { 13 | res.send(JSON.stringify({ 14 | msg: 'error', 15 | error: e.message 16 | })) 17 | } 18 | }); 19 | } 20 | 21 | return api; 22 | }; -------------------------------------------------------------------------------- /routes/deeplink/setuplink.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { WALLET_VDXF_KEY } = require('verus-typescript-primitives'); 3 | 4 | function setuplink(app) { 5 | let res; 6 | 7 | if (process.defaultApp) { 8 | if (process.argv.length >= 2) { 9 | res = app.setAsDefaultProtocolClient(WALLET_VDXF_KEY.vdxfid, process.execPath, [path.resolve(process.argv[1])]) 10 | } 11 | } else { 12 | res = app.setAsDefaultProtocolClient(WALLET_VDXF_KEY.vdxfid) 13 | } 14 | 15 | return res 16 | } 17 | 18 | module.exports = setuplink -------------------------------------------------------------------------------- /fetch-nspv-bins.sh: -------------------------------------------------------------------------------- 1 | mkdir assets/bin 2 | mkdir assets/bin/win64 3 | mkdir assets/bin/linux64 4 | mkdir assets/bin/osx 5 | cd assets/bin/win64 6 | wget https://github.com/pbca26/libnspv/releases/download/v0.3/nspv-win.tar 7 | tar -xvf nspv-win.tar 8 | rm nspv-win.tar 9 | cd ../linux64 10 | wget https://github.com/pbca26/libnspv/releases/download/v0.3/nspv-linux.tar 11 | tar -xvf nspv-linux.tar 12 | rm nspv-linux.tar 13 | cd ../osx 14 | wget https://github.com/pbca26/libnspv/releases/download/v0.3/nspv-osx.tar 15 | tar -xvf nspv-osx.tar 16 | rm nspv-osx.tar -------------------------------------------------------------------------------- /routes/api/network/supply/coinSupply.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = (api) => { 3 | api.get_coinsupply = (chainTicker) => { 4 | if (api.coinSupply[chainTicker] != null) { 5 | return new Promise(async (resolve, reject) => { 6 | api.coinSupply[chainTicker]() 7 | .then(coinSupply => resolve(coinSupply)) 8 | .catch(e => reject(e)) 9 | }) 10 | } else { 11 | return new Promise((resolve, reject) => reject(new Error(`HTTP/HTTPS coin supply function not found for ${chainTicker}`))) 12 | } 13 | } 14 | 15 | return api; 16 | }; -------------------------------------------------------------------------------- /routes/api/electrum/remove.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.setPost('/electrum/remove_coin', (req, res) => { 3 | const _chain = req.body.chainTicker; 4 | delete api.electrum.coinData[_chain.toLowerCase()]; 5 | 6 | if (Object.keys(api.electrum.coinData).length === 0) { 7 | api.electrumKeys = {}; 8 | } 9 | 10 | api.eclManagerClear(_chain.toLowerCase()); 11 | 12 | const retObj = { 13 | msg: 'success', 14 | result: true, 15 | }; 16 | 17 | res.send(JSON.stringify(retObj)); 18 | }); 19 | 20 | return api; 21 | }; 22 | -------------------------------------------------------------------------------- /routes/api/utility_apis/pbaas.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | // TODO: Expand to work beyond just native mode 3 | api.is_pbaas = (chainTicker) => { 4 | return ( 5 | chainTicker !== "VRSC" && 6 | (api.native.launchConfigs[chainTicker] != null 7 | ? api.native.launchConfigs[chainTicker].daemon != null && 8 | api.native.launchConfigs[chainTicker].daemon === "verusd" 9 | : false) 10 | ); 11 | }; 12 | 13 | api.is_vrsc = (chainTicker) => { 14 | return (chainTicker === "VRSC"); 15 | }; 16 | 17 | return api; 18 | }; 19 | -------------------------------------------------------------------------------- /routes/api/utils/dialog-shim.js: -------------------------------------------------------------------------------- 1 | // Shim for using old electron dialog format with new electron 2 | const { dialog } = require('electron'); 3 | 4 | async function showMessageBox(browserWindow, options, callback) { 5 | const res = await dialog.showMessageBox(browserWindow, options) 6 | 7 | if (callback) callback(res.response, res.checkboxChecked) 8 | } 9 | 10 | async function showOpenDialog(browserWindow, options, callback) { 11 | const res = await dialog.showOpenDialog(browserWindow, options) 12 | 13 | if (callback) callback(res.filePaths) 14 | } 15 | 16 | module.exports = { 17 | dialog: { 18 | showOpenDialog, 19 | showMessageBox 20 | } 21 | } -------------------------------------------------------------------------------- /routes/api/utils/unzip.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const unzip = require('unzipper') 3 | 4 | function unzipFile(input, output) { 5 | return new Promise((resolve, reject) => { 6 | try { 7 | const s = fs.createReadStream(input) 8 | 9 | const pipe = s.pipe(unzip.Extract({ path: output })) 10 | 11 | pipe.on('close', function () { 12 | return resolve(); 13 | }) 14 | 15 | pipe.on('error', function(error) { 16 | s.destroy(error) 17 | return reject(error) 18 | }); 19 | } catch (error) { 20 | return reject(error); 21 | } 22 | }); 23 | } 24 | 25 | module.exports = { 26 | unzipFile 27 | } -------------------------------------------------------------------------------- /routes/api/utils/objectUtil/flattenObjectProps.js: -------------------------------------------------------------------------------- 1 | const flattenObjectProps = (obj) => { 2 | const isNonEmptyObject = val => typeof val === "object" && !Array.isArray(val) && Object.values(val).length > 0; 3 | 4 | const addDelimiter = (a, b) => (a ? `${a}.${b}` : b); 5 | 6 | const paths = (obj = {}, head = "") => { 7 | return Object.entries(obj).reduce((product, [key, value]) => { 8 | let fullPath = addDelimiter(head, key); 9 | return isNonEmptyObject(value) 10 | ? product.concat(paths(value, fullPath)) 11 | : product.concat(fullPath); 12 | }, []); 13 | }; 14 | 15 | return paths(obj); 16 | } 17 | 18 | module.exports = flattenObjectProps -------------------------------------------------------------------------------- /routes/api/utils/rpc/rpcError.js: -------------------------------------------------------------------------------- 1 | const { RPC_ERROR_UNKNOWN } = require("./rpcStatusCodes") 2 | 3 | class RpcError extends Error { 4 | constructor(code = RPC_ERROR_UNKNOWN, ...params) { 5 | // Pass remaining arguments (including vendor specific ones) to parent constructor 6 | super(...params) 7 | 8 | // Maintains proper stack trace for where our error was thrown (only available on V8) 9 | if (Error.captureStackTrace) { 10 | Error.captureStackTrace(this, RpcError) 11 | } 12 | 13 | this.name = 'RpcError' 14 | // Custom debugging information 15 | this.code = code 16 | this.timestamp = (new Date()).getTime() 17 | } 18 | } 19 | 20 | module.exports = RpcError -------------------------------------------------------------------------------- /routes/api/utils/hashFile.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'), fs = require('fs') 2 | 3 | function hashFile(filename, algorithm = 'sha256') { 4 | return new Promise((resolve, reject) => { 5 | let crypto_hash = crypto.createHash(algorithm); 6 | 7 | try { 8 | let stream = fs.ReadStream(filename) 9 | 10 | stream.on('data', function (data) { 11 | crypto_hash.update(data) 12 | }) 13 | 14 | stream.on('end', function () { 15 | const hash = crypto_hash.digest('hex') 16 | return resolve(hash); 17 | }) 18 | 19 | } catch (error) { 20 | return reject(error); 21 | } 22 | }); 23 | } 24 | 25 | module.exports = { 26 | hashFile 27 | } -------------------------------------------------------------------------------- /routes/api/native/closeoffers.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.closeoffers = async (chain, offers = []) => { 3 | return await api.native.callDaemon(chain, "closeoffers", [offers]); 4 | }; 5 | 6 | api.setPost("/native/closeoffers", async (req, res, next) => { 7 | try { 8 | res.send( 9 | JSON.stringify({ 10 | msg: "success", 11 | result: await api.native.closeoffers(req.body.chain, req.body.offers), 12 | }) 13 | ); 14 | } catch (e) { 15 | res.send( 16 | JSON.stringify({ 17 | msg: "error", 18 | result: e.message, 19 | }) 20 | ); 21 | } 22 | }); 23 | 24 | return api; 25 | }; 26 | -------------------------------------------------------------------------------- /routes/api/paths.js: -------------------------------------------------------------------------------- 1 | const { 2 | pathsAgama, 3 | pathsDaemons, 4 | setDaemonPath, 5 | setCoinDir 6 | } = require('./pathsUtil'); 7 | const path = require('path'); 8 | const fixPath = require('fix-path'); 9 | const os = require('os'); 10 | 11 | module.exports = (api) => { 12 | api.pathsAgama = () => { 13 | api = pathsAgama(api, global.HOME); 14 | } 15 | 16 | api.pathsDaemons = () => { 17 | api = pathsDaemons(api); 18 | } 19 | 20 | api.setDaemonPath = (daemonName) => { 21 | api = setDaemonPath(api, daemonName); 22 | } 23 | 24 | api.setCoinDir = (coin, dirNames, absolute = false) => { 25 | api = setCoinDir(api, coin, dirNames, absolute) 26 | } 27 | 28 | return api; 29 | }; -------------------------------------------------------------------------------- /routes/api/native/importwallet.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.importwallet = async (chain, filename) => { 3 | return await api.native.callDaemon(chain, "z_importwallet", [filename]); 4 | } 5 | 6 | api.setPost('/native/importwallet', async (req, res, next) => { 7 | const { chain, filename } = req.body; 8 | 9 | try { 10 | res.send( 11 | JSON.stringify({ 12 | msg: "success", 13 | result: await api.native.importwallet(chain, filename), 14 | }) 15 | ); 16 | } catch (e) { 17 | res.send(JSON.stringify({ 18 | msg: "error", 19 | result: e.message 20 | })); 21 | } 22 | }); 23 | 24 | return api; 25 | }; -------------------------------------------------------------------------------- /routes/api/utils/auth/pluginAuth.js: -------------------------------------------------------------------------------- 1 | var blake2b = require('blake2b') 2 | const crypto = require('crypto') 3 | 4 | function generateAppSecret (permissions, masterSecret, appId) { 5 | let permissionsHashable = [...permissions] 6 | permissionsHashable.sort() 7 | 8 | var appSecret = blake2b(64) 9 | const handler = crypto.randomBytes(32) 10 | 11 | permissionsHashable.forEach(value => appSecret.update(Buffer.from(value))) 12 | appSecret.update(Buffer.from(masterSecret)) 13 | appSecret.update(Buffer.from(appId)) 14 | appSecret.update(Buffer.from(handler)) 15 | 16 | return { 17 | secret: appSecret.digest('hex'), 18 | handler 19 | } 20 | } 21 | 22 | module.exports = { 23 | generateAppSecret 24 | } -------------------------------------------------------------------------------- /routes/children/fetch-bootstrap/window.js: -------------------------------------------------------------------------------- 1 | const { dialog } = require('electron') 2 | 3 | async function canFetchBootstrap(chainTicker) { 4 | const supportedChains = [ 5 | 'VRSC', 6 | 'VRSCTEST', 7 | 'VARRR', 8 | 'VDEX', 9 | 'CHIPS' 10 | ]; 11 | return supportedChains.includes(chainTicker) 12 | ? ( 13 | await dialog.showMessageBox({ 14 | type: "question", 15 | title: `Bootstrap ${chainTicker}?`, 16 | message: `Would you like to speed up syncing to the ${chainTicker} blockchain by downloading blockchain data from the internet?`, 17 | buttons: ["Yes", "No"], 18 | }) 19 | ).response === 0 20 | : false; 21 | } 22 | 23 | module.exports = { 24 | canFetchBootstrap, 25 | } -------------------------------------------------------------------------------- /routes/api/native/setidentitytimelock.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.setidentitytimelock = async (chain, identity, lock) => { 3 | return await api.native.callDaemon(chain, "setidentitytimelock", [identity, lock]); 4 | } 5 | 6 | api.setPost('/native/setidentitytimelock', async (req, res, next) => { 7 | const { chain, identity, lock } = req.body; 8 | 9 | try { 10 | res.send( 11 | JSON.stringify({ 12 | msg: "success", 13 | result: await api.native.setidentitytimelock(chain, identity, lock), 14 | }) 15 | ); 16 | } catch (e) { 17 | res.send(JSON.stringify({ 18 | msg: "error", 19 | result: e.message 20 | })); 21 | } 22 | }); 23 | 24 | return api; 25 | }; -------------------------------------------------------------------------------- /routes/api/utils/standardization/standardizeMiningInfo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Standardizes the behaviour of the mining info object when passed in from 3 | * the KMD or VRSC daemon, so GUI can expect standard behaviour. 4 | * 5 | * @param {Object} mininginfo The mining info result object to standardize 6 | */ 7 | const standardizeMiningInfo = (mininginfo) => { 8 | if (mininginfo.localsolps != null && mininginfo.localhashps == null) 9 | mininginfo.localhashps = mininginfo.localsolps; 10 | 11 | if (mininginfo.numthreads == null && mininginfo.genproclimit != null) { 12 | mininginfo.numthreads = mininginfo.genproclimit 13 | } 14 | 15 | if (mininginfo.numthreads === -1) mininginfo.numthreads = 0 16 | 17 | return mininginfo 18 | } 19 | 20 | module.exports = standardizeMiningInfo -------------------------------------------------------------------------------- /routes/api/native/exportwallet.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.exportwallet = async (chain, filename, omitemptyaddresses) => { 3 | return await api.native.callDaemon(chain, "z_exportwallet", [filename, omitemptyaddresses]); 4 | } 5 | 6 | api.setPost('/native/exportwallet', async (req, res, next) => { 7 | const { chain, filename, omitemptyaddresses } = req.body; 8 | 9 | try { 10 | res.send( 11 | JSON.stringify({ 12 | msg: "success", 13 | result: await api.native.exportwallet(chain, filename, omitemptyaddresses), 14 | }) 15 | ); 16 | } catch (e) { 17 | res.send(JSON.stringify({ 18 | msg: "error", 19 | result: e.message 20 | })); 21 | } 22 | }); 23 | 24 | return api; 25 | }; -------------------------------------------------------------------------------- /routes/api/native/makeoffer.js: -------------------------------------------------------------------------------- 1 | const { MakeOfferRequest, MakeOfferResponse } = require("verus-typescript-primitives"); 2 | 3 | module.exports = (api) => { 4 | api.native.makeoffer = async (offer) => { 5 | return await api.native.callDaemon(...(offer.prepare())); 6 | } 7 | 8 | api.setPost('/native/makeoffer', async (req, res, next) => { 9 | const offer = MakeOfferRequest.fromJson(req.body) 10 | 11 | try { 12 | res.send( 13 | JSON.stringify({ 14 | msg: "success", 15 | result: new MakeOfferResponse(await api.native.makeoffer(offer)).toJson(), 16 | }) 17 | ); 18 | } catch (e) { 19 | res.send(JSON.stringify({ 20 | msg: "error", 21 | result: e.message 22 | })); 23 | } 24 | }); 25 | 26 | return api; 27 | }; -------------------------------------------------------------------------------- /routes/api/eth/info.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.setGet('/eth/get_info', (req, res, next) => { 3 | let retObj = {} 4 | 5 | try { 6 | const { network } = api.eth.get_info() 7 | 8 | retObj = { 9 | msg: 'success', 10 | result: { 11 | network: network.key, 12 | chainId: network.id 13 | } 14 | } 15 | } catch (e) { 16 | retObj = { 17 | msg: 'error', 18 | result: e.message 19 | } 20 | } 21 | 22 | res.send(JSON.stringify(retObj)); 23 | }); 24 | 25 | api.eth.get_info = () => { 26 | if (api.eth.interface != null) { 27 | return api.eth.interface.getInfo() 28 | } else { 29 | throw new Error('No interface to connect to ETH for getinfo call') 30 | } 31 | } 32 | 33 | return api; 34 | }; -------------------------------------------------------------------------------- /routes/api/utils/constants/allowed_paths.js: -------------------------------------------------------------------------------- 1 | // Identities 2 | const NAME_COMMITMENTS = 'nameCommits.json' 3 | 4 | // API Secrets 5 | const BUILTIN_SECRET = 'builtinsecret.json' 6 | 7 | // Currencies 8 | const CURRENCY_BLACKLIST = 'shepherd/currencies/blacklist.json' 9 | const CURRENCY_WHITELIST = 'shepherd/currencies/whitelist.json' 10 | const CURRENCY_GRAYLIST = 'shepherd/currencies/graylist.json' 11 | 12 | // Updates 13 | const UPDATE_LOG = 'updatelog.json' 14 | 15 | const ALLOWED_PATHS_ARR = [ 16 | NAME_COMMITMENTS, 17 | CURRENCY_BLACKLIST, 18 | CURRENCY_GRAYLIST, 19 | CURRENCY_WHITELIST, 20 | UPDATE_LOG, 21 | BUILTIN_SECRET 22 | ]; 23 | 24 | module.exports = { 25 | NAME_COMMITMENTS, 26 | CURRENCY_BLACKLIST, 27 | CURRENCY_GRAYLIST, 28 | CURRENCY_WHITELIST, 29 | ALLOWED_PATHS_ARR, 30 | UPDATE_LOG, 31 | BUILTIN_SECRET 32 | } -------------------------------------------------------------------------------- /routes/api/utils/objectUtil/useStringAsKey.js: -------------------------------------------------------------------------------- 1 | //ref: https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key 2 | /** 3 | * Uses a string as a key to search through an object and find a property. 4 | * E.g. the string "animalNoises.cat" would return "meow" on { animalNoises: { cat: "meow" }} 5 | * @param {Object} o The object to search through 6 | * @param {String} s The string to use as a key 7 | */ 8 | const useStringAsKey = (o, s) => { 9 | s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties 10 | s = s.replace(/^\./, ''); // strip a leading dot 11 | var a = s.split('.'); 12 | for (var i = 0, n = a.length; i < n; ++i) { 13 | var k = a[i]; 14 | if (k in o) { 15 | o = o[k]; 16 | } else { 17 | return; 18 | } 19 | } 20 | return o; 21 | } 22 | 23 | module.exports = useStringAsKey -------------------------------------------------------------------------------- /routes/zcashParamsSources.js: -------------------------------------------------------------------------------- 1 | const zcashParamsSources = { 2 | 'agama.komodoplatform.com': { 3 | spend: 'https://agama.komodoplatform.com/file/komodo/sapling-params/sapling-spend.params', 4 | output: 'https://agama.komodoplatform.com/file/komodo/sapling-params/sapling-output.params', 5 | groth16: 'https://agama.komodoplatform.com/file/komodo/sapling-params/sprout-groth16.params', 6 | }, 7 | 'z.cash': { 8 | spend: 'https://z.cash/downloads/sapling-spend.params', 9 | output: 'https://z.cash/downloads/sapling-output.params', 10 | groth16: 'https://z.cash/downloads/sprout-groth16.params', 11 | }, 12 | 'verus.io': { 13 | spend: 'https://verus.io/zcparams/sapling-spend.params', 14 | output: 'https://verus.io/zcparams/sapling-output.params', 15 | groth16: 'https://verus.io/zcparams/sprout-groth16.params', 16 | }, 17 | } 18 | 19 | module.exports = zcashParamsSources; 20 | -------------------------------------------------------------------------------- /routes/deeplink/openurlhandler.js: -------------------------------------------------------------------------------- 1 | const { dialog } = require('electron') 2 | const { URL } = require('url'); 3 | const { SUPPORTED_DLS, CALLBACK_HOST } = require('../api/utils/constants/supported_dls'); 4 | 5 | function openurlhandler(event, urlstring, apihandler) { 6 | try { 7 | const url = new URL(urlstring); 8 | 9 | if (url.host !== CALLBACK_HOST) throw new Error("Unsupported host url."); 10 | if (!SUPPORTED_DLS.includes(url.pathname.replace(/\//g, ""))) 11 | throw new Error("Unsupported url path."); 12 | 13 | return apihandler(url); 14 | } catch (e) { 15 | setTimeout(() => { 16 | // This avoids crashing 20 seconds after the error box has been left open. 17 | dialog.showErrorBox( 18 | "Something went wrong?", 19 | `Error: "${e.message}". For url string: "${urlstring}".` 20 | ); 21 | }, 0); 22 | } 23 | } 24 | 25 | module.exports = openurlhandler -------------------------------------------------------------------------------- /routes/api/utils/objectUtil/removeElementByProperties.js: -------------------------------------------------------------------------------- 1 | //ref: https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key 2 | /** 3 | * Uses an array of properties (in parent -> child order) 4 | * as a key to search through an object and remove an 5 | * element, assuming the property list correctly maps the object. 6 | * Returns the modified object. 7 | * 8 | * @param {Object} o The object to search through 9 | * @param {String[]} propList The property list 10 | */ 11 | const removeElementByProperties = (o, propList) => { 12 | if (propList.length === 1) { 13 | let newO = { ...o } 14 | delete newO[propList[0]] 15 | return newO 16 | } else { 17 | let newProps = propList.slice() 18 | const newProp = newProps.shift() 19 | 20 | return {...o, [newProp]: removeElementByProperties(o[newProp], newProps)} 21 | } 22 | } 23 | 24 | module.exports = removeElementByProperties -------------------------------------------------------------------------------- /routes/api/utils/verifySignature.js: -------------------------------------------------------------------------------- 1 | const request = require('request'); 2 | 3 | // TODO: Implement when endpoint is complete 4 | function verifyHash(hash, id, signature) { 5 | return new Promise((resolve, reject) => { 6 | const options = { 7 | url: '', 8 | method: "POST", 9 | body: JSON.stringify({ 10 | Hash: hash, 11 | Signature: signature, 12 | Identity: id 13 | }) 14 | }; 15 | 16 | request(options, (error, response, body) => { 17 | if (response && 18 | response.statusCode && 19 | response.statusCode === 200) { 20 | try { 21 | const _json = JSON.parse(body); 22 | 23 | resolve(true) 24 | } catch (e) { 25 | reject(e) 26 | } 27 | } else { 28 | reject(new Error(`Unable to request ${options.url}`)) 29 | } 30 | }); 31 | }); 32 | } 33 | 34 | module.exports = { 35 | verifyHash 36 | } -------------------------------------------------------------------------------- /assets/deps/confs/FRK_peers.txt: -------------------------------------------------------------------------------- 1 | 193.227.134.111:7912 2 | 85.24.169.215:7912 3 | 195.154.223.134:7912 4 | 175.33.51.90:7912 5 | 91.153.109.149:7912 6 | 84.242.139.4:7912 7 | 73.211.90.130:7912 8 | 123.56.194.66:7912 9 | 157.161.128.55:7912 10 | 91.134.120.210:7912 11 | 80.219.59.25:7912 12 | 173.65.129.85:7912 13 | 198.27.97.180:7912 14 | 178.140.25.85:7912 15 | 104.172.24.79:7912 16 | 198.27.81.114:7912 17 | 104.236.163.203:7912 18 | 98.115.147.74:7912 19 | 155.254.32.17:7912 20 | 198.27.97.172:7912 21 | 108.61.10.90:7912 22 | 104.236.26.26:7912 23 | 144.76.91.109:7912 24 | 158.69.238.230:7912 25 | 86.174.4.251:7912 26 | 151.80.9.33:7912 27 | 198.50.217.13:7912 28 | 193.192.37.135:7912 29 | 80.219.59.42:7912 30 | 68.117.4.111:7912 31 | 109.145.33.45:7912 32 | 74.196.59.103:7912 33 | 84.107.181.197:7912 34 | 80.219.59.98:7912 35 | 104.236.59.76:7912 36 | 81.89.56.170:7912 37 | 157.161.128.58:7912 38 | 158.69.27.82:7912 39 | 209.126.119.209:7912 40 | 104.238.171.32:7912 41 | -------------------------------------------------------------------------------- /routes/api/network/fees/btc/btcFees.js: -------------------------------------------------------------------------------- 1 | const { checkTimestamp } = require('agama-wallet-lib/src/time'); 2 | const { requestJson } = require('../../../utils/request/request'); 3 | 4 | let btcFees = { 5 | recommended: {}, 6 | lastUpdated: null, 7 | }; 8 | 9 | const BTC_FEES_MIN_ELAPSED_TIME = 120; 10 | 11 | module.exports = (api) => { 12 | api.networkFees['BTC'] = () => { 13 | return new Promise(async (resolve, reject) => { 14 | if (checkTimestamp(btcFees.lastUpdated) > BTC_FEES_MIN_ELAPSED_TIME) { 15 | try { 16 | const res = await requestJson( 17 | "GET", 18 | "https://api.blockchain.com/mempool/fees" 19 | ); 20 | 21 | const { priority, regular } = res; 22 | resolve({low: regular, mid: regular, max: priority}); 23 | } catch(e) { 24 | reject(e) 25 | } 26 | } else { 27 | resolve(btcFees) 28 | } 29 | }); 30 | } 31 | 32 | return api; 33 | }; -------------------------------------------------------------------------------- /routes/api/native/takeoffer.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.takeoffer = async ({ 3 | chain, 4 | fromaddress, 5 | offer: { txid, changeaddress, deliver, accept }, 6 | }) => { 7 | return await api.native.callDaemon(chain, "takeoffer", [ 8 | fromaddress, 9 | { txid, changeaddress, deliver, accept }, 10 | ]); 11 | }; 12 | 13 | api.setPost("/native/takeoffer", async (req, res, next) => { 14 | try { 15 | res.send( 16 | JSON.stringify({ 17 | msg: "success", 18 | result: await api.native.takeoffer({ 19 | chain: req.body.chain, 20 | fromaddress: req.body.fromaddress, 21 | offer: req.body.offer, 22 | }), 23 | }) 24 | ); 25 | } catch (e) { 26 | res.send( 27 | JSON.stringify({ 28 | msg: "error", 29 | result: e.message, 30 | }) 31 | ); 32 | } 33 | }); 34 | 35 | return api; 36 | }; 37 | -------------------------------------------------------------------------------- /routes/api/dlhandler.js: -------------------------------------------------------------------------------- 1 | const { LOGIN_CONSENT_REQUEST_VDXF_KEY, LoginConsentRequest } = require('verus-typescript-primitives'); 2 | const base64url = require("base64url"); 3 | const { ROOT_SYSTEM_NAME } = require('./utils/constants/dev_options'); 4 | 5 | module.exports = (api) => { 6 | api.dlhandler = (url) => { 7 | const handlers = { 8 | [LOGIN_CONSENT_REQUEST_VDXF_KEY.vdxfid]: (url) => { 9 | const value = url.searchParams.get(LOGIN_CONSENT_REQUEST_VDXF_KEY.vdxfid) 10 | const req = new LoginConsentRequest(); 11 | req.fromBuffer(base64url.toBuffer(value)); 12 | 13 | return api.loginConsentUi.request( 14 | req.toJson(), 15 | { 16 | id: "VERUS_DESKTOP_MAIN", 17 | search_builtin: true, 18 | main_chain_ticker: ROOT_SYSTEM_NAME 19 | } 20 | ) 21 | } 22 | } 23 | 24 | return handlers[url.pathname.replace(/\//g, "")](url) 25 | } 26 | 27 | return api; 28 | }; -------------------------------------------------------------------------------- /routes/api/utils/objectUtil/getBytes.js: -------------------------------------------------------------------------------- 1 | 2 | const getObjBytes = (obj) => { 3 | let bytes = 0; 4 | 5 | function sizeOf(obj) { 6 | if (obj !== null && obj !== undefined) { 7 | switch (typeof obj) { 8 | case "number": 9 | bytes += 8; 10 | break; 11 | case "string": 12 | bytes += obj.length * 2; 13 | break; 14 | case "boolean": 15 | bytes += 4; 16 | break; 17 | case "object": 18 | let objClass = Object.prototype.toString.call(obj).slice(8, -1); 19 | if (objClass === "Array" || objClass === "Object") { 20 | for (let key in obj) { 21 | if (!obj.hasOwnProperty(key)) continue; 22 | sizeOf(obj[key]); 23 | } 24 | } else bytes += obj.toString().length * 2; 25 | break; 26 | } 27 | } 28 | return bytes; 29 | } 30 | 31 | return sizeOf(obj); 32 | } 33 | 34 | module.exports = getObjBytes -------------------------------------------------------------------------------- /routes/api/native/currencyGraylist.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | // api.setGet('/native/get_currency_graylist', (req, res, next) => { 3 | // const { token } = req.body 4 | 5 | // if (api.checkToken(token)) { 6 | // api.native.loadCurrencyGraylist() 7 | // .then((graylist) => { 8 | // const retObj = { 9 | // msg: 'success', 10 | // result: graylist, 11 | // }; 12 | 13 | // res.send(JSON.stringify(retObj)); 14 | // }) 15 | // .catch(error => { 16 | // const retObj = { 17 | // msg: 'error', 18 | // result: error.message, 19 | // }; 20 | 21 | // res.send(JSON.stringify(retObj)); 22 | // }) 23 | // } else { 24 | // const retObj = { 25 | // msg: 'error', 26 | // result: 'unauthorized access', 27 | // }; 28 | 29 | // res.send(JSON.stringify(retObj)); 30 | // } 31 | // }); 32 | 33 | return api; 34 | }; -------------------------------------------------------------------------------- /routes/api/numbers.js: -------------------------------------------------------------------------------- 1 | const scientificToDecimal = function(number) { 2 | let numberHasSign = number.startsWith("-") || number.startsWith("+"); 3 | let sign = numberHasSign ? number[0] : ""; 4 | number = numberHasSign ? number.replace(sign, "") : number; 5 | 6 | 7 | if (/\d+\.?\d*e[\+\-]*\d+/i.test(number)) { 8 | let zero = '0'; 9 | let parts = String(number).toLowerCase().split('e'); 10 | let e = parts.pop(); 11 | let l = Math.abs(e); 12 | let sign = e / l; 13 | let coeff_array = parts[0].split('.'); 14 | 15 | if (sign === -1) { 16 | coeff_array[0] = Math.abs(coeff_array[0]); 17 | number = zero + '.' + new Array(l).join(zero) + coeff_array.join(''); 18 | } else { 19 | let dec = coeff_array[1]; 20 | if (dec) l = l - dec.length; 21 | number = coeff_array.join('') + new Array(l + 1).join(zero); 22 | } 23 | } 24 | 25 | return `${sign}${number}`; 26 | }; 27 | 28 | module.exports = { 29 | scientificToDecimal 30 | } -------------------------------------------------------------------------------- /routes/api/network/supply/vrsc/vrscCoinSupply.js: -------------------------------------------------------------------------------- 1 | const { checkTimestamp } = require('agama-wallet-lib/src/time'); 2 | const { requestJson } = require('../../../utils/request/request'); 3 | 4 | let coinSupply = { 5 | result: null, 6 | lastUpdated: null, 7 | }; 8 | 9 | const COIN_SUPPLY_MIN_ELAPSED_TIME = 60; 10 | 11 | module.exports = (api) => { 12 | api.coinSupply['VRSC'] = () => { 13 | return new Promise(async (resolve, reject) => { 14 | if (checkTimestamp(coinSupply.lastUpdated) > COIN_SUPPLY_MIN_ELAPSED_TIME) { 15 | try { 16 | const res = await requestJson( 17 | "GET", 18 | 'https://explorer.verus.io/api/coinsupply' 19 | ); 20 | 21 | resolve(res); 22 | } catch(e) { 23 | reject(e) 24 | } 25 | } else { 26 | api.log('vrsc coinsupply, use cache', 'network.coinSupply'); 27 | 28 | resolve(coinSupply.result) 29 | } 30 | }); 31 | } 32 | 33 | return api; 34 | }; 35 | -------------------------------------------------------------------------------- /routes/api/native/zoperations.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = (api) => { 3 | api.native.get_zoperations = (coin) => { 4 | return new Promise((resolve, reject) => { 5 | api.native.callDaemon(coin, 'z_getoperationstatus', []) 6 | .then((zoperations) => { 7 | resolve(zoperations) 8 | }) 9 | .catch(err => { 10 | reject(err) 11 | }) 12 | }); 13 | }; 14 | 15 | api.setPost('/native/get_zoperations', (req, res, next) => { 16 | const coin = req.body.chainTicker; 17 | 18 | api.native.get_zoperations(coin) 19 | .then((zoperations) => { 20 | const retObj = { 21 | msg: 'success', 22 | result: zoperations, 23 | }; 24 | 25 | res.send(JSON.stringify(retObj)); 26 | }) 27 | .catch(error => { 28 | const retObj = { 29 | msg: 'error', 30 | result: error.message, 31 | }; 32 | 33 | res.send(JSON.stringify(retObj)); 34 | }) 35 | }); 36 | 37 | return api; 38 | }; -------------------------------------------------------------------------------- /routes/api/eth/auth.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.setPost('/eth/auth', (req, res, next) => { 3 | let seed = req.body.seed; 4 | 5 | if (!api.seed) { 6 | api.seed = seed; 7 | } 8 | 9 | api.eth.wallet = api.eth._keys(seed, true); 10 | 11 | const retObj = { 12 | msg: 'success', 13 | result: 'success', 14 | }; 15 | 16 | res.send(JSON.stringify(retObj)); 17 | }, true); 18 | 19 | api.setGet('/eth/check_auth', (req, res, next) => { 20 | res.send(JSON.stringify({ 21 | msg: 'success', 22 | result: api.eth.wallet != null && api.eth.wallet.signer != null && api.eth.wallet.signer.signingKey != null, 23 | })); 24 | }); 25 | 26 | api.setPost('/eth/logout', (req, res, next) => { 27 | api.eth.wallet = null 28 | api.eth.interface = null 29 | 30 | const retObj = { 31 | msg: 'success', 32 | result: 'success', 33 | }; 34 | 35 | res.send(JSON.stringify(retObj)); 36 | }); 37 | 38 | return api; 39 | }; 40 | -------------------------------------------------------------------------------- /routes/api/native/definedchains.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = (api) => { 3 | api.native.get_definedchains = (coin) => { 4 | return new Promise((resolve, reject) => { 5 | api.native.callDaemon(coin, 'getdefinedchains', []) 6 | .then((definedchains) => { 7 | resolve(definedchains) 8 | }) 9 | .catch(err => { 10 | reject(err) 11 | }) 12 | }); 13 | }; 14 | 15 | api.setPost('/native/get_definedchains', (req, res, next) => { 16 | const coin = req.body.chainTicker; 17 | 18 | api.native.get_definedchains(coin) 19 | .then((definedchains) => { 20 | const retObj = { 21 | msg: 'success', 22 | result: definedchains, 23 | }; 24 | 25 | res.send(JSON.stringify(retObj)); 26 | }) 27 | .catch(error => { 28 | const retObj = { 29 | msg: 'error', 30 | result: error.message, 31 | }; 32 | 33 | res.send(JSON.stringify(retObj)); 34 | }) 35 | }); 36 | 37 | return api; 38 | }; -------------------------------------------------------------------------------- /routes/api/erc20/auth.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.setPost('/erc20/auth', (req, res, next) => { 3 | let seed = req.body.seed; 4 | 5 | if (!api.seed) { 6 | api.seed = seed; 7 | } 8 | 9 | api.erc20.wallet = api.eth._keys(seed, true); 10 | 11 | const retObj = { 12 | msg: 'success', 13 | result: 'success', 14 | }; 15 | 16 | res.send(JSON.stringify(retObj)); 17 | }, true); 18 | 19 | api.setGet('/erc20/check_auth', (req, res, next) => { 20 | res.send(JSON.stringify({ 21 | msg: 'success', 22 | result: api.erc20.wallet != null && api.erc20.wallet.signer != null && api.erc20.wallet.signer.signingKey != null, 23 | })); 24 | }); 25 | 26 | api.setPost('/erc20/logout', (req, res, next) => { 27 | api.erc20.wallet = null 28 | api.erc20.interface = null 29 | 30 | const retObj = { 31 | msg: 'success', 32 | result: 'success', 33 | }; 34 | 35 | res.send(JSON.stringify(retObj)); 36 | }); 37 | 38 | return api; 39 | }; 40 | -------------------------------------------------------------------------------- /routes/api/native/estimateConversion.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | /** 3 | * @param {string} chain 4 | * @param {{currency: string, amount: number, convertto: string, preconvert: boolean, via: string}} params 5 | */ 6 | api.native.estimate_conversion = async (chain, params) => { 7 | try { 8 | return await api.native.callDaemon(chain, 'estimateconversion', [params]); 9 | } catch(e) { 10 | throw e 11 | } 12 | }; 13 | 14 | api.setPost('/native/estimate_conversion', async (req, res, next) => { 15 | const { chainTicker, params } = req.body 16 | 17 | try { 18 | const retObj = { 19 | msg: 'success', 20 | result: await api.native.estimate_conversion(chainTicker, params), 21 | }; 22 | 23 | res.send(JSON.stringify(retObj)); 24 | } catch(e) { 25 | const retObj = { 26 | msg: 'error', 27 | result: e.message, 28 | }; 29 | 30 | res.send(JSON.stringify(retObj)); 31 | } 32 | }); 33 | 34 | return api; 35 | }; -------------------------------------------------------------------------------- /routes/api/native/idRevocation.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = (api) => { 3 | api.native.revoke_id = (coin, name) => { 4 | return new Promise((resolve, reject) => { 5 | api.native.callDaemon(coin, 'revokeidentity', [name]) 6 | .then((txid) => { 7 | resolve({ 8 | name, 9 | txid 10 | }) 11 | }) 12 | .catch(err => { 13 | reject(err) 14 | }) 15 | }); 16 | }; 17 | 18 | api.setPost('/native/revoke_id', (req, res, next) => { 19 | const { chainTicker, name } = req.body 20 | 21 | api.native.revoke_id(chainTicker, name) 22 | .then((revocationResult) => { 23 | const retObj = { 24 | msg: 'success', 25 | result: revocationResult, 26 | }; 27 | 28 | res.send(JSON.stringify(retObj)); 29 | }) 30 | .catch(error => { 31 | const retObj = { 32 | msg: 'error', 33 | result: error.message, 34 | }; 35 | 36 | res.send(JSON.stringify(retObj)); 37 | }) 38 | }); 39 | 40 | return api 41 | }; -------------------------------------------------------------------------------- /routes/api/network/supply/zec/zecCoinSupply.js: -------------------------------------------------------------------------------- 1 | const { checkTimestamp } = require('agama-wallet-lib/src/time'); 2 | const { requestJson } = require('../../../utils/request/request'); 3 | 4 | let coinSupply = { 5 | result: null, 6 | lastUpdated: null, 7 | }; 8 | 9 | const COIN_SUPPLY_MIN_ELAPSED_TIME = 60; 10 | 11 | module.exports = (api) => { 12 | api.coinSupply['ZEC'] = () => { 13 | return new Promise(async (resolve, reject) => { 14 | if (checkTimestamp(coinSupply.lastUpdated) > COIN_SUPPLY_MIN_ELAPSED_TIME) { 15 | try { 16 | const res = await requestJson( 17 | "GET", 18 | 'https://api.zcha.in/v2/mainnet/network' 19 | ); 20 | 21 | resolve({ total: res.totalAmount, private: res.sproutPool + res.saplingPool }); 22 | } catch(e) { 23 | reject(e) 24 | } 25 | } else { 26 | api.log('zec coinsupply, use cache', 'network.coinSupply'); 27 | 28 | resolve(coinSupply.result) 29 | } 30 | }); 31 | } 32 | 33 | return api; 34 | }; -------------------------------------------------------------------------------- /routes/api/explorer/remoteExplorers.js: -------------------------------------------------------------------------------- 1 | const remoteExplorers = { 2 | KMD: 'http://kmd.komodochainz.info', 3 | MSHARK: 'http://MSHARK.explorer.supernet.org', 4 | REVS: 'http://revs.explorer.supernet.org', 5 | SUPERNET: 'http://SUPERNET.explorer.supernet.org', 6 | DEX: 'http://DEX.explorer.supernet.org', 7 | PANGEA: 'http://PANGEA.explorer.supernet.org', 8 | JUMBLR: 'http://JUMBLR.explorer.supernet.org', 9 | BET: 'http://BET.explorer.supernet.org', 10 | CRYPTO: 'http://CRYPTO.explorer.supernet.org', 11 | HODL: 'http://HODL.explorer.supernet.org', 12 | SHARK: 'http://SHARK.explorer.supernet.org', 13 | BOTS: 'http://BOTS.explorer.supernet.org', 14 | MGW: 'http://MGW.explorer.supernet.org', 15 | WLC: 'http://WIRELESS.explorer.supernet.org', 16 | COQUI: 'https://explorer.coqui.cash', 17 | MNZ: 'https://www.mnzexplorer.com', 18 | VRSC: 'https://explorer.verus.io/', 19 | PIRATE: 'https://pirate.kmdexplorer.io', 20 | VRSCTEST: 'https://testex.verus.io' 21 | }; 22 | // TODO Our landing page gets added to this list 23 | module.exports = remoteExplorers; 24 | -------------------------------------------------------------------------------- /routes/api/native/info.js: -------------------------------------------------------------------------------- 1 | const { standardizeInfo } = require('../utils/standardization/standardization') 2 | 3 | module.exports = (api) => { 4 | api.native.get_info = (coin) => { 5 | return new Promise((resolve, reject) => { 6 | api.native.callDaemon(coin, 'getinfo', []) 7 | .then((info) => { 8 | return standardizeInfo(info, coin, api) 9 | }) 10 | .then(info => resolve(info)) 11 | .catch(err => { 12 | reject(err) 13 | }) 14 | }); 15 | }; 16 | 17 | api.setPost('/native/get_info', (req, res, next) => { 18 | const coin = req.body.chainTicker; 19 | 20 | api.native.get_info(coin) 21 | .then((info) => { 22 | const retObj = { 23 | msg: 'success', 24 | result: info, 25 | }; 26 | 27 | res.send(JSON.stringify(retObj)); 28 | }) 29 | .catch(error => { 30 | const retObj = { 31 | msg: 'error', 32 | result: error.message, 33 | }; 34 | 35 | res.send(JSON.stringify(retObj)); 36 | }) 37 | }); 38 | 39 | return api; 40 | }; -------------------------------------------------------------------------------- /routes/api/native/blockSubsidy.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = (api) => { 3 | api.native.get_blocksubsidy = (coin, height) => { 4 | return new Promise((resolve, reject) => { 5 | api.native.callDaemon(coin, 'getblocksubsidy', height == null ? [] : [height]) 6 | .then((blocksubsidy) => { 7 | resolve(blocksubsidy) 8 | }) 9 | .catch(err => { 10 | reject(err) 11 | }) 12 | }); 13 | }; 14 | 15 | api.setPost('/native/get_blocksubsidy', (req, res, next) => { 16 | const { height } = req.body 17 | const coin = req.body.chainTicker; 18 | 19 | api.native.get_blocksubsidy(coin, height) 20 | .then((blocksubsidy) => { 21 | const retObj = { 22 | msg: 'success', 23 | result: blocksubsidy, 24 | }; 25 | 26 | res.send(JSON.stringify(retObj)); 27 | }) 28 | .catch(error => { 29 | const retObj = { 30 | msg: 'error', 31 | result: error.message, 32 | }; 33 | 34 | res.send(JSON.stringify(retObj)); 35 | }) 36 | }); 37 | 38 | return api; 39 | }; -------------------------------------------------------------------------------- /routes/api/electrum/utils.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.sortTransactions = (transactions, sortBy) => { 3 | if (transactions && typeof transactions === 'object' && transactions[0]) { 4 | return transactions.sort((b, a) => { 5 | if (a[sortBy ? sortBy : 'height'] < b[sortBy ? sortBy : 'height'] && 6 | a[sortBy ? sortBy : 'height'] && 7 | b[sortBy ? sortBy : 'height']) { 8 | return -1; 9 | } 10 | 11 | if (a[sortBy ? sortBy : 'height'] > b[sortBy ? sortBy : 'height'] && 12 | a[sortBy ? sortBy : 'height'] && 13 | b[sortBy ? sortBy : 'height']) { 14 | return 1; 15 | } 16 | 17 | if (!a[sortBy ? sortBy : 'height'] && 18 | b[sortBy ? sortBy : 'height']) { 19 | return 1; 20 | } 21 | 22 | if (!b[sortBy ? sortBy : 'height'] && 23 | a[sortBy ? sortBy : 'height']) { 24 | return -1; 25 | } 26 | 27 | return 0; 28 | }); 29 | } else { 30 | return transactions; 31 | } 32 | } 33 | 34 | return api; 35 | }; -------------------------------------------------------------------------------- /gui/fetch-bootstrap/fetch-bootstrap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | Loading bootstrap script... 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /routes/api/native/sendcurrency.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.sendcurrency = async (chainTicker, from = "*", outputs = [], feeamount = null) => { 3 | try { 4 | return await api.native.callDaemon( 5 | chainTicker, 6 | "sendcurrency", 7 | feeamount === null ? [from, outputs] : [from, outputs, feeamount] 8 | ); 9 | } catch(e) { 10 | throw e 11 | } 12 | } 13 | 14 | api.setPost('/native/sendcurrency', async (req, res, next) => { 15 | const { from, outputs, feeamount, chainTicker } = req.body; 16 | 17 | try { 18 | res.send(JSON.stringify({ 19 | msg: "success", 20 | result: await api.native.sendcurrency(chainTicker, from, outputs.map(x => { 21 | Object.keys(x).map(y => { 22 | if (x[y] == null || x[y].length === 0) delete x[y] 23 | }) 24 | 25 | return x 26 | }), feeamount) 27 | })); 28 | } catch (e) { 29 | res.send( 30 | JSON.stringify({ 31 | msg: "error", 32 | result: e.message, 33 | }) 34 | ); 35 | } 36 | }); 37 | 38 | return api; 39 | }; -------------------------------------------------------------------------------- /routes/api/electrum/info.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.setGet('/electrum/get_info', (req, res, next) => { 3 | if (!req.query.chainTicker) { 4 | res.send(JSON.stringify({ 5 | msg: 'error', 6 | result: 'No coin passed to electrum get_info' 7 | })); 8 | } 9 | const coinLc = req.query.chainTicker.toLowerCase(); 10 | 11 | if (!api.electrum.coinData[coinLc]) { 12 | res.send(JSON.stringify({ 13 | msg: 'error', 14 | result: `No coin data found for ${req.query.chainTicker}` 15 | })); 16 | } 17 | 18 | const { name, txfee, server, serverList, nspv } = api.electrum.coinData[coinLc]; 19 | 20 | res.send(JSON.stringify({msg: 'success', result: nspv ? { 21 | protocol: "nSPV", 22 | name, 23 | txfee, 24 | server: `${server.ip}:${server.port}:${server.proto}`, 25 | serverList: serverList.toString(), 26 | } : { 27 | protocol: "Electrum", 28 | name, 29 | txfee, 30 | server: `${server.ip}:${server.port}:${server.proto}`, 31 | serverList: serverList.toString(), 32 | nspv, 33 | }})); 34 | }); 35 | 36 | return api; 37 | }; -------------------------------------------------------------------------------- /routes/ports.js: -------------------------------------------------------------------------------- 1 | // default daemon ports 2 | 3 | const assetChainPorts = { 4 | KMD: 7771, 5 | //marketmaker: 7783, 6 | OOT: 12467, 7 | PIZZA: 11608, 8 | BEER: 8923, 9 | SUPERNET: 11341, 10 | REVS: 10196, 11 | WLC: 12167, 12 | WLC21: 38808, 13 | PANGEA: 14068, 14 | DEX: 11890, 15 | JUMBLR: 15106, 16 | BET: 14250, 17 | CRYPTO: 8516, 18 | HODL: 14431, 19 | MSHARK: 8846, 20 | BOTS: 11964, 21 | MGW: 12386, 22 | COQUI: 14276, 23 | CHAIN: 15587, 24 | KMDICE: 30177, 25 | GLXT: 13109, 26 | MVP: 11676, 27 | KV: 8299, 28 | CEAL: 11116, 29 | MESH: 9455, 30 | AXO: 12927, 31 | ETOMIC: 10271, 32 | NINJA: 8427, 33 | BNTN: 14358, 34 | EQL: 10306, 35 | PRLPAY: 9679, 36 | PGT: 46705, 37 | ZILLA: 10041, 38 | DSEC: 11557, 39 | MGNX: 20731, 40 | PIRATE: 45453, 41 | CCL: 20849, 42 | KOIN: 10702, 43 | DION: 23895, 44 | PTX: 61939, 45 | KSB: 21066, 46 | OUR: 45672, 47 | RICK: 28223, 48 | MORTY: 63812, 49 | MTST3: 56141, 50 | ZEXO: 33970, 51 | LABS: 40265, 52 | DP: 28388, 53 | VRSCTEST: 18843, 54 | VRSC: 27486, 55 | VOTE2020: 44249, 56 | VOTE2021: 55638 57 | }; 58 | 59 | module.exports = assetChainPorts; 60 | -------------------------------------------------------------------------------- /routes/api/network/fees/networkFees.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = (api) => { 3 | api.setGet('/get_networkfees', (req, res, next) => { 4 | if (!req.query.chainTicker) { 5 | res.send(JSON.stringify({msg: 'error', result: "No coin passed to get_networkfees"})); 6 | } 7 | 8 | api.electrum.get_networkfees(req.query.chainTicker) 9 | .then(feesObj => { 10 | const retObj = { 11 | msg: 'success', 12 | result: feesObj 13 | }; 14 | 15 | res.send(JSON.stringify(retObj)); 16 | }) 17 | .catch(e => { 18 | const retObj = { 19 | msg: 'error', 20 | result: e.message 21 | }; 22 | 23 | res.send(JSON.stringify(retObj)); 24 | }) 25 | }); 26 | 27 | api.electrum.get_networkfees = (chainTicker) => { 28 | if (api.networkFees[chainTicker] != null) { 29 | return new Promise(async (resolve, reject) => { 30 | api.networkFees[chainTicker]() 31 | .then(fees => resolve(fees)) 32 | .catch(e => reject(e)) 33 | }) 34 | } else { 35 | return new Promise((resolve, reject) => {reject(new Error(`Network fee function not found`))}) 36 | } 37 | } 38 | 39 | return api; 40 | }; -------------------------------------------------------------------------------- /routes/api/utils/objectUtil/addMerge.js: -------------------------------------------------------------------------------- 1 | const deepmerge = require('./deepmerge') 2 | const flattenObjectProps = require('./flattenObjectProps') 3 | 4 | /** 5 | * Adds properties object 2 includes that object 1 may be missing into 6 | * object 1 and returns the modified object 7 | * @param {Object} obj1 Object 1 8 | * @param {Object} obj2 Object 2 9 | */ 10 | const addMerge = (obj1, obj2) => { 11 | const flatObj1 = flattenObjectProps(obj1); 12 | const flatObj2 = flattenObjectProps(obj2); 13 | let resObj = obj1; 14 | 15 | flatObj2.forEach(propertyList => { 16 | if (!flatObj1.includes(propertyList)) { 17 | const propertyArr = propertyList.split("."); 18 | let updateObj = propertyArr.reduce(function( 19 | accumulator, 20 | currentValue 21 | ) { 22 | return accumulator[currentValue]; 23 | }, 24 | obj2); 25 | 26 | propertyArr 27 | .slice() 28 | .reverse() 29 | .forEach((property, index) => { 30 | updateObj = { [property]: updateObj }; 31 | }); 32 | 33 | resObj = deepmerge(updateObj, resObj); 34 | } 35 | }); 36 | 37 | return resObj; 38 | } 39 | 40 | module.exports = addMerge -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 - 2018 SuperNET 4 | Copyright (c) 2019 - 2020 Verus Coin Foundation 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /routes/api/utils/constants/file_descriptors.js: -------------------------------------------------------------------------------- 1 | // Identities 2 | const NAME_COMMITMENTS_DESC = "DO NOT EDIT. This file contains the saved name commitments that you can use to create VerusIDs. Editing it will most likely cause your VerusID creation to fail." 3 | 4 | // Secrets 5 | const BUILTIN_SECRET_DESC = "DO NOT EDIT" 6 | 7 | // Currencies 8 | const BLACKLIST_DESC = "This file contains currencies you have chosen to blacklist, i.e. never see again. They will not appear in any part of your wallet, on the chains they are children of here." 9 | 10 | const WHITELIST_DESC = "This file contains currencies you have chosen to whitelist, i.e. always track. They will always appear in your coin wallet screen in the currency dropdown." 11 | 12 | const GRAYLIST_DESC = "This file contains a list of curated currencies that will appear in your wallet if they aren't blacklisted, and you have a balance above 0 of them." 13 | 14 | // Update Log 15 | const UPDATE_LOG_DESC = "This file contains a history of all version-required updates performed on data in the Verus Desktop folder." 16 | 17 | module.exports = { 18 | NAME_COMMITMENTS_DESC, 19 | UPDATE_LOG_DESC, 20 | BLACKLIST_DESC, 21 | WHITELIST_DESC, 22 | GRAYLIST_DESC, 23 | BUILTIN_SECRET_DESC 24 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Builtin Plugins 7 | assets/plugins/builtin/* 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | 14 | #ide 15 | /.idea 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | assets/bin/* 35 | 36 | # Dependency directories 37 | node_modules 38 | jspm_packages 39 | 40 | # Optional npm cache directory 41 | .npm 42 | 43 | # electron cache directory 44 | .electron 45 | 46 | # Optional REPL history 47 | .node_repl_history 48 | 49 | # Ignore node.js modules folder 50 | node_modules 51 | 52 | # Ignore any igauna made directories or files in repo folder 53 | tmp 54 | help 55 | debug.log 56 | genesis 57 | DB 58 | 59 | # Electron-builder related folders 60 | build 61 | 62 | #MacOSX hidden cache files 63 | __MACOSX 64 | react/package.json 65 | 66 | # Build files 67 | dist/* -------------------------------------------------------------------------------- /routes/api/erc20/info.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.setGet('/erc20/get_info', (req, res, next) => { 3 | let retObj = {} 4 | 5 | try { 6 | const { network, address, decimals } = api.erc20.get_info( 7 | req.query.chainTicker 8 | ); 9 | 10 | retObj = { 11 | msg: 'success', 12 | result: { 13 | network: network.key, 14 | chainId: network.id, 15 | contract: address, 16 | decimals, 17 | } 18 | } 19 | } catch (e) { 20 | retObj = { 21 | msg: 'error', 22 | result: e.message 23 | } 24 | } 25 | 26 | res.send(JSON.stringify(retObj)); 27 | }); 28 | 29 | api.erc20.get_info = (contractId) => { 30 | if (api.erc20.contracts[contractId] != null) { 31 | return { 32 | ...api.erc20.contracts[contractId].interface.getInfo(), 33 | address: contractId, 34 | decimals: 35 | api.erc20.contracts[contractId].decimals != null 36 | ? api.erc20.contracts[contractId].decimals.toString() 37 | : "18", 38 | }; 39 | } else { 40 | throw new Error(`No interface to connect to ${contractId} for getinfo call`) 41 | } 42 | } 43 | 44 | return api; 45 | }; -------------------------------------------------------------------------------- /routes/electrumjs/electrumServersConfig.js: -------------------------------------------------------------------------------- 1 | const disableCoins = [ 2 | 'aby', 3 | 'vot', 4 | 'mac', 5 | 'bdl', 6 | 'mzc', // no servers 7 | 'zet', // no servers 8 | 'jbs', // no servers 9 | 'grs', 10 | 'wc', // needs kv edit 11 | 'xwc', // needs kv edit 12 | 'put', // needs kv edit 13 | 'ecn', // needs kv edit 14 | 'ac', 15 | //'btcp', // sort out kv 16 | 'blk', 17 | // untested coins 18 | 'smart', 19 | 'usc', 20 | 'bca', 21 | 'mnx', 22 | 'xvc', 23 | 'nro', 24 | 'uno', 25 | 'bela', 26 | 'ldcn', 27 | 'hnc', 28 | 'nrg', 29 | 'smly', 30 | 'nsr', 31 | 'defc', 32 | 'brit', 33 | 'lynx', 34 | 'vpn', 35 | 'sdc', 36 | 'club', 37 | 'posw', 38 | 'psb', 39 | 'gcr', 40 | 'nyc', 41 | 'frst', 42 | // decode error coins 43 | 'omni', 44 | 'strat', 45 | 'clam', 46 | 'excl', 47 | 'nav', 48 | 'neos', 49 | 'ok', 50 | 'rdd', 51 | 'xvg', 52 | 'zen', 53 | 'slr', 54 | 'rby', 55 | 'pot', 56 | 'usnbt', 57 | 'ppc', 58 | 'thc', 59 | 'grc', 60 | 'pink', 61 | 'toa', 62 | 'wc', 63 | 'nvc', 64 | 'kobo', 65 | 'insn', 66 | 'edrc', 67 | 'ccn', 68 | 'cmp', 69 | // temp disable 70 | 'mue', 71 | 'xbc', 72 | 'pac', 73 | 'lcc', 74 | 'axe', 75 | ]; 76 | 77 | module.exports = disableCoins; -------------------------------------------------------------------------------- /routes/api/appInfo.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | const os = require('os'); 3 | const { formatBytes } = require('agama-wallet-lib/src/utils'); 4 | 5 | module.exports = (api) => { 6 | api.SystemInfo = () => { 7 | const os_data = { 8 | totalmem_bytes: os.totalmem(), 9 | totalmem_readable: formatBytes(os.totalmem()), 10 | arch: os.arch(), 11 | cpu: os.cpus()[0].model, 12 | cpu_cores: os.cpus().length, 13 | platform: os.platform(), 14 | os_release: os.release(), 15 | os_type: os.type(), 16 | }; 17 | 18 | return os_data; 19 | } 20 | 21 | api.appInfo = () => { 22 | const sysInfo = api.SystemInfo(); 23 | const releaseInfo = api.appBasicInfo; 24 | const dirs = { 25 | agamaDir: api.paths.agamaDir, 26 | kmdDataDir: api.paths.kmdDataDir, 27 | komododBin: api.komododBin, 28 | configLocation: `${api.paths.agamaDir}/config.json`, 29 | cacheLocation: `${api.paths.agamaDir}/spv-cache.json`, 30 | }; 31 | let spvCacheSize = '2 Bytes'; 32 | 33 | try { 34 | spvCacheSize = formatBytes(fs.lstatSync(`${api.paths.agamaDir}/spv-cache.json`).size); 35 | } catch (e) {} 36 | 37 | return { 38 | sysInfo, 39 | releaseInfo, 40 | dirs, 41 | cacheSize: spvCacheSize, 42 | }; 43 | } 44 | 45 | return api; 46 | }; -------------------------------------------------------------------------------- /routes/api/native/verusid/login/verifyRequest.js: -------------------------------------------------------------------------------- 1 | const { LoginConsentRequest } = require("verus-typescript-primitives") 2 | 3 | module.exports = (api) => { 4 | /** 5 | * Verifies a login request 6 | * @param {LoginConsentRequest} Request 7 | */ 8 | api.native.verusid.login.verify_request = async (request) => { 9 | const loginConsentRequest = new LoginConsentRequest(request); 10 | const chainTicker = request.chainTicker 11 | 12 | const verified = await api.native.verify_hash( 13 | chainTicker, 14 | loginConsentRequest.signing_id, 15 | loginConsentRequest.challenge.toSha256().toString('hex'), 16 | loginConsentRequest.signature.signature 17 | ); 18 | 19 | return verified ? { verified } : { verified, message: "Failed to verify signature" }; 20 | }; 21 | 22 | api.setPost("/native/verusid/login/verify_request", async (req, res, next) => { 23 | const { request } = req.body; 24 | 25 | try { 26 | res.send( 27 | JSON.stringify({ 28 | msg: "success", 29 | result: await api.native.verusid.login.verify_request(request), 30 | }) 31 | ); 32 | } catch (e) { 33 | res.send( 34 | JSON.stringify({ 35 | msg: "error", 36 | result: e.message, 37 | }) 38 | ); 39 | } 40 | }); 41 | 42 | return api; 43 | }; 44 | -------------------------------------------------------------------------------- /routes/api/utils/web3/etherscan.js: -------------------------------------------------------------------------------- 1 | const { EtherscanProvider, Networkish, BlockTag } = require('ethers'); 2 | 3 | class HistorySupportingEtherscanProvider extends EtherscanProvider { 4 | /** 5 | * Creates an etherscan provider that supports getting tx history 6 | * @param {Networkish} networkish 7 | * @param {string} apiKey 8 | * @returns {HistorySupportingEtherscanProvider} 9 | */ 10 | constructor(networkish, apiKey) { 11 | super(networkish, apiKey); 12 | } 13 | 14 | /** 15 | * Gets the transaction history for a given address from startBlock to endBlock 16 | * @param {string} address 17 | * @param {BlockTag} startBlock 18 | * @param {BlockTag} endBlock 19 | * @param {string} contractAddress 20 | * @returns {Promise>} 21 | */ 22 | async getHistory(address, startBlock, endBlock, contractAddress) { 23 | const params = { 24 | action: contractAddress != null ? "tokentx" : "txlist", 25 | address, 26 | startblock: ((startBlock == null) ? 0 : startBlock), 27 | endblock: ((endBlock == null) ? 99999999 : endBlock), 28 | sort: "asc" 29 | }; 30 | 31 | if (contractAddress != null) params.contractAddress = contractAddress; 32 | 33 | return this.fetch("account", params); 34 | } 35 | } 36 | 37 | module.exports = { 38 | HistorySupportingEtherscanProvider 39 | } -------------------------------------------------------------------------------- /routes/api/native/getConversionPaths.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.get_conversion_paths = ( 3 | chain, 4 | src 5 | ) => { 6 | return new Promise(async (resolve, reject) => { 7 | try { 8 | const chainCurrency = await api.native.get_currency(chain, chain); 9 | 10 | const interface = await api.native.getRpcInterface(chain, chainCurrency.currencyid); 11 | const source = typeof src === "string" ? await api.native.get_currency(chain, src) : src; 12 | 13 | const paths = await interface.getCurrencyConversionPaths(source); 14 | 15 | delete paths[source.currencyid] 16 | 17 | resolve(paths); 18 | } catch(e) { 19 | reject(e) 20 | } 21 | }); 22 | }; 23 | 24 | api.setPost('/native/get_conversion_paths', (req, res, next) => { 25 | const coin = req.body.chainTicker; 26 | const src = req.body.src; 27 | 28 | api.native.get_conversion_paths(coin, src) 29 | .then((paths) => { 30 | res.send(JSON.stringify({ 31 | msg: 'success', 32 | result: paths, 33 | })); 34 | }) 35 | .catch(error => { 36 | const retObj = { 37 | msg: 'error', 38 | result: error.message, 39 | }; 40 | 41 | res.send(JSON.stringify(retObj)); 42 | }) 43 | }); 44 | 45 | return api; 46 | }; -------------------------------------------------------------------------------- /routes/children/userAgreement/window.js: -------------------------------------------------------------------------------- 1 | const { dialog } = require('electron') 2 | 3 | async function userAgreesToTerms(window) { 4 | const result = await dialog.showMessageBox(window, { 5 | message: '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 enclosed copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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.', 6 | buttons: ["I Understand", "Cancel"], 7 | textWidth: 600 8 | }) 9 | 10 | return result.response === 0 11 | } 12 | 13 | module.exports = { 14 | userAgreesToTerms, 15 | } -------------------------------------------------------------------------------- /routes/workers/check_update.js: -------------------------------------------------------------------------------- 1 | const version_json = require('../../version.json') 2 | const versionCompare = require('../api/utils/version/versionCompare'); 3 | const { requestJson } = require('../api/utils/request/request'); 4 | 5 | function updateAvailable() { 6 | return new Promise(async (resolve, reject) => { 7 | try { 8 | const res = await requestJson("GET", version_json.versionUrl); 9 | 10 | if (versionCompare.compare(res.version, version_json.version, ">")) { 11 | const mandatory = 12 | res.minVersion != null && 13 | versionCompare.compare(res.minVersion, version_json.version, ">"); 14 | 15 | const newRes = await requestJson( 16 | "GET", 17 | version_json.repository + `releases/tag/v${res.version}`, 18 | {}, 19 | {}, 20 | true 21 | ); 22 | 23 | if (newRes.status === 200) { 24 | resolve({ update_available: true, version: res.version, mandatory }); 25 | } else if (newRes.status === 404) { 26 | resolve({ update_available: false, version: res.version, mandatory }); 27 | } else reject(new Error("Error fetching update data, status " + res.status)); 28 | } else resolve({ update_available: false, version: res.version, mandatory: false }); 29 | } catch (e) { 30 | reject(e); 31 | } 32 | }) 33 | } 34 | 35 | module.exports = updateAvailable -------------------------------------------------------------------------------- /routes/api/data_files/updateLog.js: -------------------------------------------------------------------------------- 1 | const { 2 | UPDATE_LOG, 3 | UPDATE_LOG_DESC 4 | } = require("../utils/constants/index"); 5 | 6 | module.exports = (api) => { 7 | // Blacklist 8 | api.loadUpdateLog = () => 9 | api.loadJsonFile(UPDATE_LOG, UPDATE_LOG_DESC); 10 | api.saveUpdateLog = (history) => 11 | api.saveJsonFile({ time: (new Date()).getTime(), history }, UPDATE_LOG, UPDATE_LOG_DESC); 12 | 13 | api.setGet('/load_update_log', async (req, res, next) => { 14 | api.loadUpdateLog() 15 | .then((log) => { 16 | const retObj = { 17 | msg: 'success', 18 | result: log, 19 | }; 20 | 21 | res.send(JSON.stringify(retObj)); 22 | }) 23 | .catch(error => { 24 | const retObj = { 25 | msg: 'error', 26 | result: error.message, 27 | }; 28 | 29 | res.send(JSON.stringify(retObj)); 30 | }) 31 | }); 32 | 33 | api.setPost('/save_update_log', async (req, res, next) => { 34 | const { history } = req.body 35 | 36 | try { 37 | const retObj = { 38 | msg: 'success', 39 | result: await api.saveUpdateLog(history), 40 | }; 41 | 42 | res.send(JSON.stringify(retObj)); 43 | } catch (e) { 44 | const retObj = { 45 | msg: 'error', 46 | result: e.message, 47 | }; 48 | 49 | res.send(JSON.stringify(retObj)); 50 | } 51 | }); 52 | 53 | return api; 54 | }; -------------------------------------------------------------------------------- /assets/deps/confs/MZC_peers.txt: -------------------------------------------------------------------------------- 1 | 188.226.195.226 2 | 72.49.184.206 3 | 84.22.108.241 4 | 75.128.211.140 5 | 176.31.53.252 6 | 212.5.143.185 7 | 205.197.252.41 8 | 195.154.223.134 9 | 142.4.218.174 10 | 72.46.152.250 11 | 45.63.65.112 12 | 104.236.167.70 13 | 142.4.218.175 14 | 108.61.164.199 15 | 107.170.173.232 16 | 98.117.92.108 17 | 192.95.29.153 18 | 97.88.116.115 19 | 24.206.113.66 20 | 173.239.208.6 21 | 24.107.101.162 22 | 88.198.49.154 23 | 193.107.94.202 24 | 86.26.119.177 25 | 198.27.97.172 26 | 73.240.243.108 27 | 98.127.109.96 28 | 27.109.250.186 29 | 79.64.13.216 30 | 81.102.95.39 31 | 92.14.74.221 32 | 68.42.79.115 33 | 85.169.119.123 34 | 24.107.102.70 35 | 151.80.206.101 36 | 107.170.167.218 37 | 151.80.9.33 38 | 82.46.79.119 39 | 63.247.147.166 40 | 95.145.252.94 41 | 113.52.87.159 42 | 192.99.35.133 43 | 12.35.68.211 44 | 46.105.158.205 45 | 72.84.241.101 46 | 37.59.18.108 47 | 104.172.24.79 48 | 174.107.118.81 49 | 76.106.178.145 50 | 75.128.193.117 51 | 158.69.27.82 52 | 45.32.233.30 53 | 84.22.106.192 54 | 74.132.6.75 55 | 45.55.153.77 56 | 89.156.223.223 57 | 94.23.32.109 58 | 180.94.191.62 59 | 45.55.220.222 60 | 73.192.202.185 61 | 186.90.15.65 62 | 108.224.49.4 63 | 84.237.85.210 64 | 76.19.242.156 65 | 73.157.167.155 66 | 68.117.4.111 67 | 98.18.22.32 68 | 69.59.214.109 69 | 198.84.218.9 70 | 98.115.147.74 71 | 71.7.124.80 72 | 65.15.37.140 73 | 217.44.16.102 74 | 73.240.162.49 75 | 23.80.94.149 76 | 151.80.206.110 77 | 50.254.73.158 78 | 92.14.75.139 79 | 188.124.91.76 80 | 66.189.11.251 81 | 184.17.228.71 82 | -------------------------------------------------------------------------------- /gui/startup/agama-instance-error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 22 |
Another Verus Desktop instance is already running!
23 |
Please close all other instances and restart the app.
24 |
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /routes/api/utils/auth/rpcAuth.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019, Amalie Due Jensen 3 | 4 | Permission to use, copy, modify, and/or distribute this software for any 5 | purpose with or without fee is hereby granted, provided that the above 6 | copyright notice and this permission notice appear in all copies. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | const crypto = require('crypto') 18 | 19 | function generateSalt (size) { 20 | const buf = crypto.randomBytes(size) 21 | const salt = buf.toString('hex') 22 | return salt 23 | } 24 | 25 | function generateRpcPassword () { 26 | const buf = crypto.randomBytes(32) 27 | const password = Buffer.from(buf).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '') 28 | return password 29 | } 30 | 31 | function passwordToHmac (salt, password) { 32 | const hmac = crypto.createHmac('sha256', salt) 33 | hmac.update(password) 34 | return hmac.digest('hex') 35 | } 36 | 37 | module.exports = { 38 | generateSalt, 39 | generateRpcPassword, 40 | passwordToHmac 41 | } -------------------------------------------------------------------------------- /routes/api/getSignatureInfo.js: -------------------------------------------------------------------------------- 1 | const { 2 | IdentitySignature, 3 | networks, 4 | } = require("@bitgo/utxo-lib"); 5 | 6 | module.exports = (api) => { 7 | /** 8 | * Gets the version, hashtype and height from a signature. 9 | * 10 | * @param {String} coin The chainTicker of the coin to make the call on 11 | * @param {String} systemId The iaddress of the system 12 | * @param {String} signature The signature to process 13 | * @param {String} iaddress The iaddress associated with the signature 14 | */ 15 | api.getSignatureInfo = (coin, systemId, signature, iaddress) => { 16 | const network = networks.verus; 17 | 18 | const sig = new IdentitySignature(network); 19 | 20 | sig.fromBuffer(Buffer.from(signature, "base64"), 0, systemId, iaddress); 21 | 22 | return { 23 | version: sig.version, 24 | hashtype: sig.hashType, 25 | height: sig.blockHeight, 26 | }; 27 | } 28 | 29 | api.setPost('/lite/get_signature_info', (req, res, next) => { 30 | const { 31 | chainTicker, 32 | systemId, 33 | signature, 34 | iaddress 35 | } = req.body; 36 | 37 | try { 38 | res.send( 39 | JSON.stringify({ 40 | msg: "success", 41 | result: api.getSignatureInfo(chainTicker, systemId, signature, iaddress), 42 | }) 43 | ); 44 | } catch (e) { 45 | res.send( 46 | JSON.stringify({ 47 | msg: "error", 48 | result: e.message, 49 | }) 50 | ); 51 | } 52 | }); 53 | 54 | return api; 55 | } -------------------------------------------------------------------------------- /routes/api/utils/auth/scalar.js: -------------------------------------------------------------------------------- 1 | const { secp256k1 } = require('@noble/curves/secp256k1'); 2 | const crypto = require('crypto'); 3 | const bigi = require('bigi'); 4 | 5 | // Derive 32-byte hash, optional clamp, and validate scalar range. 6 | // - Throws on zero scalar 7 | // - Warns but continues on scalar >= n (for legacy compatibility) 8 | // Returns: { bytes: Buffer, dBigi: bigi.BigInteger } 9 | function deriveScalarFromSeed(input, { iguana = false, logWarn } = {}) { 10 | const bytes = crypto.createHash('sha256').update(input).digest(); 11 | if (bytes.length !== 32) { 12 | throw new Error('sha256 must return 32 bytes'); 13 | } 14 | 15 | if (iguana) { // kept for legacy compatibility 16 | bytes[0] &= 248; 17 | bytes[31] &= 127; 18 | bytes[31] |= 64; 19 | } 20 | 21 | const dBig = BigInt('0x' + bytes.toString('hex')); 22 | const n = secp256k1.CURVE.n; 23 | 24 | if (dBig === BigInt(0)) { 25 | throw new Error('derived private key scalar is out of range (zero)'); 26 | } 27 | if (dBig >= n) { 28 | // compatibility: warn but do not alter bytes/scalar 29 | const warn = 'Warning: derived private key scalar is ≥ secp256k1 order; some wallets may behave inconsistently when importing it, and it is less secure. Consider generating a new seed.'; 30 | if (typeof logWarn === 'function') { 31 | logWarn(warn); 32 | } else { 33 | console.warn(warn); 34 | } 35 | } 36 | 37 | return { 38 | bytes, 39 | dBigi: bigi.fromBuffer(bytes), 40 | }; 41 | } 42 | 43 | module.exports = deriveScalarFromSeed -------------------------------------------------------------------------------- /routes/api/construct.js: -------------------------------------------------------------------------------- 1 | const { BuiltinPlugins } = require('./utils/plugin/builtin.js'); 2 | 3 | module.exports = (api) => { 4 | api.construct = function () { 5 | api.appConfig = api._appConfig.config; 6 | api.pathsAgama(); 7 | api.pathsDaemons(); 8 | 9 | api.initMainCache(); 10 | 11 | api.firstRun = api.createAgamaDirs(); 12 | api.appConfig = api.loadLocalConfig(); 13 | api.plugins = { 14 | registry: api.loadLocalPluginRegistry(), 15 | builtin: BuiltinPlugins, 16 | }; 17 | 18 | api.appConfigSchema = api._appConfig.schema; 19 | api.defaultAppConfig = Object.assign({}, api.appConfig); 20 | api.kmdMainPassiveMode = false; 21 | 22 | api.native.cache.currency_definition_cache = api.create_sub_cache( 23 | "native.cache.currency_definition_cache" 24 | ); 25 | 26 | api.seed = null; 27 | 28 | // init electrum connection manager loop 29 | api.initElectrumManager(); 30 | 31 | api.printDirs(); 32 | 33 | // default route 34 | api.setGet("/", (req, res, next) => { 35 | res.send("Agama app server2"); 36 | }); 37 | 38 | // expose sockets obj 39 | api.setIO = (io) => { 40 | api.io = io; 41 | }; 42 | 43 | api.setVar = (_name, _body) => { 44 | api[_name] = _body; 45 | }; 46 | 47 | if (api.appConfig.general.electrum && api.appConfig.general.electrum.customServers) { 48 | api.loadElectrumServersList(); 49 | } else { 50 | api.mergeLocalKvElectrumServers(); 51 | } 52 | 53 | api.checkCoinConfigIntegrity(); 54 | }; 55 | 56 | return api; 57 | }; 58 | -------------------------------------------------------------------------------- /gui/startup/app-closing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
18 | 24 |
25 | App is closing. Please wait...

26 | This may take a while depending on your system resources and current state of daemon applications. 27 |
28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /routes/api/eth/coins.js: -------------------------------------------------------------------------------- 1 | const { ETH_HOMESTEAD } = require('../utils/constants/eth_networks'); 2 | const createInterface = require('../utils/web3/provider'); 3 | 4 | module.exports = (api) => { 5 | api.setPost('/eth/coins/activate', (req, res, next) => { 6 | const { chainTicker, network } = req.body; 7 | 8 | try { 9 | if (chainTicker && chainTicker === 'ETH') { 10 | if (api.eth.interface == null) { 11 | api.eth.interface = createInterface( 12 | network == null ? ETH_HOMESTEAD : network 13 | ); 14 | 15 | const retObj = { 16 | msg: 'success', 17 | result: 'true', 18 | }; 19 | res.send(JSON.stringify(retObj)); 20 | } else { 21 | const retObj = { 22 | msg: 'error', 23 | result: 'ETH already active!', 24 | }; 25 | res.send(JSON.stringify(retObj)); 26 | } 27 | } else { 28 | const retObj = { 29 | msg: 'error', 30 | result: 'cannot activate non-eth coin on ETH network', 31 | }; 32 | res.send(JSON.stringify(retObj)); 33 | } 34 | } catch(e) { 35 | const retObj = { 36 | msg: 'error', 37 | result: e.message, 38 | }; 39 | res.send(JSON.stringify(retObj)); 40 | } 41 | }); 42 | 43 | api.setPost('/eth/remove_coin', (req, res) => { 44 | api.eth.interface = null 45 | 46 | const retObj = { 47 | msg: 'success', 48 | result: true, 49 | }; 50 | 51 | res.send(JSON.stringify(retObj)); 52 | }); 53 | 54 | return api; 55 | }; -------------------------------------------------------------------------------- /routes/api/eth/balances.js: -------------------------------------------------------------------------------- 1 | const ethers = require('ethers'); 2 | 3 | module.exports = (api) => { 4 | api.setGet("/eth/get_balances", async (req, res, next) => { 5 | try { 6 | res.send( 7 | JSON.stringify({ 8 | msg: "success", 9 | result: { 10 | native: { 11 | public: { 12 | //TODO: Return string instead 13 | confirmed: Number(ethers.formatEther( 14 | await api.eth.get_wallet_balance() 15 | )), 16 | unconfirmed: null, 17 | immature: null, 18 | interest: null, 19 | }, 20 | private: { 21 | confirmed: null, 22 | }, 23 | }, 24 | reserve: {}, 25 | }, 26 | }) 27 | ); 28 | } catch (e) { 29 | res.send( 30 | JSON.stringify({ 31 | msg: "error", 32 | result: e.message, 33 | }) 34 | ); 35 | } 36 | }); 37 | 38 | api.eth.get_address_balance = async (address) => { 39 | if (api.eth.interface != null) { 40 | return api.eth.interface.DefaultProvider.getBalance(address) 41 | } else { 42 | throw new Error("Cannot get balance for inactive coin ETH") 43 | } 44 | } 45 | 46 | api.eth.get_wallet_balance = async () => { 47 | if (api.eth.wallet != null) { 48 | return await api.eth.get_address_balance(api.eth.wallet.address) 49 | } else { 50 | throw new Error("No wallet authenticated, cannot get wallet balance for ETH") 51 | } 52 | } 53 | 54 | return api; 55 | }; -------------------------------------------------------------------------------- /routes/preloads/plugin/preload-builtin.js: -------------------------------------------------------------------------------- 1 | const { 2 | contextBridge, 3 | shell, 4 | ipcRenderer 5 | } = require("electron"); 6 | const fs = require('fs') 7 | const os = require('os') 8 | const url = require('url') 9 | 10 | const generateOpenExternalSafe = require('../../workers/openExternalSafe') 11 | const arch = require('arch'); 12 | const chainParams = require("../../chainParams") 13 | const assetChainPorts = require("../../ports") 14 | const version = require('../../../version.json'); 15 | const { pathsAgama } = require("../../api/pathsUtil"); 16 | const appConfig = require("../../appConfig").config 17 | 18 | let apiShell = {} 19 | pathsAgama(apiShell, os.platform() === "win32" ? process.env.APPDATA : process.env.HOME) 20 | 21 | contextBridge.exposeInMainWorld("bridge", { 22 | getConfigSync: () => 23 | JSON.parse( 24 | fs.readFileSync(`${apiShell.paths.agamaDir}/config.json`, "utf8") 25 | ), 26 | getSecretSync: () => JSON.parse(fs.readFileSync(`${apiShell.paths.agamaDir}/builtinsecret.json`, "utf8")).data, 27 | defaultConfig: appConfig, 28 | shell: { 29 | openExternal: generateOpenExternalSafe(shell, url), 30 | }, 31 | assetChainPorts, 32 | appBasicInfo: { 33 | name: "Verus Desktop", 34 | mode: global.USB_MODE ? "usb" : "standard", 35 | version: version.version, 36 | }, 37 | arch: arch(), 38 | chainParams 39 | }); 40 | 41 | ipcRenderer.on('ipc', (_, msg) => { 42 | try { 43 | if (msg.type === 'response' || msg.type === 'push'|| msg.type === 'init') { 44 | window.postMessage(JSON.stringify(msg), '*'); 45 | } 46 | } catch (err) { 47 | console.error(err); 48 | } 49 | }); -------------------------------------------------------------------------------- /routes/api/eth/addresses.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("ethers"); 2 | 3 | module.exports = (api) => { 4 | api.eth.get_address = () => { 5 | if (api.eth.wallet != null) { 6 | return api.eth.wallet.address 7 | } else { 8 | throw new Error("No wallet authenticated, cannot get wallet address for ETH") 9 | } 10 | }; 11 | 12 | api.eth.get_addresses = async () => { 13 | return { 14 | public: [{ 15 | address: api.eth.get_address(), 16 | tag: "eth", 17 | balances: { 18 | native: ethers.formatEther(await api.eth.get_wallet_balance()), 19 | reserve: {} 20 | } 21 | }], 22 | private: [] 23 | } 24 | }; 25 | 26 | api.setGet('/eth/get_addresses', (req, res, next) => { 27 | api.eth.get_addresses() 28 | .then((addresses) => { 29 | const retObj = { 30 | msg: 'success', 31 | result: addresses, 32 | }; 33 | 34 | res.send(JSON.stringify(retObj)); 35 | }) 36 | .catch(error => { 37 | const retObj = { 38 | msg: 'error', 39 | result: error.message, 40 | }; 41 | 42 | res.send(JSON.stringify(retObj)); 43 | }) 44 | }); 45 | 46 | api.setPost('/eth/get_privkey', (req, res, next) => { 47 | if (api.eth.wallet != null) { 48 | res.send(JSON.stringify({ 49 | msg: 'success', 50 | result: api.eth.wallet.signer.signingKey.privateKey, 51 | })); 52 | } else { 53 | res.send(JSON.stringify({ 54 | msg: 'error', 55 | result: `No ETH privkey found` 56 | })); 57 | } 58 | }, true); 59 | 60 | return api; 61 | }; -------------------------------------------------------------------------------- /routes/api/plugin/builtin/authenticator.js: -------------------------------------------------------------------------------- 1 | const { pushMessage } = require('../../../ipc/ipc'); 2 | const { ReservedPluginTypes } = require('../../utils/plugin/builtin'); 3 | 4 | module.exports = (api) => { 5 | api.authenticator = {} 6 | 7 | api.authenticator.authenticate = async (chainTicker, mode, originAppId, originBuiltin) => { 8 | return new Promise((resolve, reject) => { 9 | try { 10 | api.startPlugin(ReservedPluginTypes.VERUS_DESKTOP_AUTHENTICATOR, true, (data = {authorized: false}) => { 11 | resolve(data) 12 | }, (pluginWindow) => { 13 | pushMessage(pluginWindow, { 14 | ticker: chainTicker, 15 | mode: mode, 16 | origin_app_info: { 17 | id: originAppId, 18 | search_builtin: originBuiltin 19 | }, 20 | launch_config: {} 21 | }, "VERUS_DESKTOP_AUTHENTICATOR_COIN_REQUEST") 22 | }, 630, 350, false) 23 | } catch(e) {reject(e)} 24 | }) 25 | } 26 | 27 | api.setPost('/plugin/builtin/authenticator/authenticate', async (req, res, next) => { 28 | const { chainTicker, mode } = req.body 29 | const { app_id, builtin } = req.api_header 30 | 31 | try { 32 | const retObj = { 33 | msg: 'success', 34 | result: await api.authenticator.authenticate(chainTicker, mode, app_id, builtin), 35 | }; 36 | 37 | res.send(JSON.stringify(retObj)); 38 | } catch (e) { 39 | const retObj = { 40 | msg: 'error', 41 | result: e.message, 42 | }; 43 | 44 | res.send(JSON.stringify(retObj)); 45 | } 46 | }); 47 | 48 | return api; 49 | }; -------------------------------------------------------------------------------- /routes/api/utils/plugin/builtin.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const ReservedPluginTypes = { 4 | VERUS_DESKTOP_MAIN: "VERUS_DESKTOP_MAIN", 5 | VERUS_DESKTOP_AUTHENTICATOR: "VERUS_DESKTOP_AUTHENTICATOR", 6 | VERUS_LOGIN_CONSENT_UI: "VERUS_LOGIN_CONSENT_UI", 7 | VERUS_PBAAS_VISUALIZER: "VERUS_PBAAS_VISUALIZER" 8 | } 9 | 10 | // Builtin plugins have access to all permissions by default 11 | const BuiltinPlugins = { 12 | [ReservedPluginTypes.VERUS_DESKTOP_MAIN]: { 13 | name: "Verus Desktop", 14 | devPort: 3000 15 | }, 16 | [ReservedPluginTypes.VERUS_DESKTOP_AUTHENTICATOR]: { 17 | name: "Authenticator", 18 | path: path.join( 19 | __dirname, 20 | "../", 21 | "../", 22 | "../", 23 | "../", 24 | "assets", 25 | "plugins", 26 | "builtin", 27 | "verus-desktop-authenticator" 28 | ), 29 | devPort: 3001 30 | }, 31 | [ReservedPluginTypes.VERUS_LOGIN_CONSENT_UI]: { 32 | name: "VerusID Authentication", 33 | path: path.join( 34 | __dirname, 35 | "../", 36 | "../", 37 | "../", 38 | "../", 39 | "assets", 40 | "plugins", 41 | "builtin", 42 | "verus-login-consent-client" 43 | ), 44 | devPort: 3001 45 | }, 46 | [ReservedPluginTypes.VERUS_PBAAS_VISUALIZER]: { 47 | name: "Visualizer", 48 | path: path.join( 49 | __dirname, 50 | "../", 51 | "../", 52 | "../", 53 | "../", 54 | "assets", 55 | "plugins", 56 | "builtin", 57 | "verus-pbaas-visualizer" 58 | ), 59 | devPort: 3003 60 | } 61 | }; 62 | 63 | module.exports = { 64 | BuiltinPlugins, 65 | ReservedPluginTypes 66 | } -------------------------------------------------------------------------------- /routes/api/native/getBlock.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | /** 3 | * Gets a block given a height. 4 | * 5 | * @param {String} coin The chainTicker of the coin to make the call on 6 | * @param {String} hashorheight The block hash or height 7 | * @param {String} verbosity The verbosity of the result. 0 for hex encoded data, 1 for a json object, and 2 for json object with transaction data 8 | */ 9 | api.native.get_block = ( 10 | coin, 11 | hashorheight, 12 | verbosity = 1, 13 | ) => { 14 | return new Promise((resolve, reject) => { 15 | api.native 16 | .callDaemon( 17 | coin, 18 | "getblock", 19 | [ 20 | hashorheight, 21 | verbosity 22 | ] 23 | ) 24 | .then(resultObj => { 25 | resolve(resultObj) 26 | }) 27 | .catch(err => { 28 | reject(err); 29 | }); 30 | }); 31 | }; 32 | 33 | api.setPost('/native/get_block', (req, res, next) => { 34 | const { 35 | chainTicker, 36 | hashorheight, 37 | verbosity 38 | } = req.body; 39 | 40 | api.native 41 | .get_block( 42 | chainTicker, 43 | hashorheight, 44 | verbosity 45 | ) 46 | .then(resultObj => { 47 | const retObj = { 48 | msg: "success", 49 | result: resultObj 50 | }; 51 | 52 | res.send(JSON.stringify(retObj)); 53 | }) 54 | .catch(error => { 55 | const retObj = { 56 | msg: "error", 57 | result: error.message 58 | }; 59 | 60 | res.send(JSON.stringify(retObj)); 61 | }); 62 | }); 63 | 64 | return api; 65 | } -------------------------------------------------------------------------------- /routes/api/native/getVdxfId.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | /** 3 | * Returns the VDXF key of the URI string. 4 | * 5 | * @param {String} coin The chainTicker of the coin to make the call on 6 | * @param {String} vdxfuri This message is converted from hex, the data is hashed, then returned 7 | * @param {Object} initialvdxfdata The optional data of (vdxfkey, uint256, indexnum) that is combined. 8 | */ 9 | api.native.get_vdxf_id = ( 10 | coin, 11 | vdxfuri, 12 | initialvdxfdata = {}, 13 | ) => { 14 | return new Promise((resolve, reject) => { 15 | api.native 16 | .callDaemon( 17 | coin, 18 | "getvdxfid", 19 | [ 20 | vdxfuri, 21 | initialvdxfdata 22 | ] 23 | ) 24 | .then(resultObj => { 25 | resolve(resultObj) 26 | }) 27 | .catch(err => { 28 | reject(err); 29 | }); 30 | }); 31 | }; 32 | 33 | api.setPost('/native/get_vdxf_id', (req, res, next) => { 34 | const { 35 | chainTicker, 36 | vdxfuri, 37 | initialvdxfdata 38 | } = req.body; 39 | 40 | api.native 41 | .get_vdxf_id( 42 | chainTicker, 43 | vdxfuri, 44 | initialvdxfdata 45 | ) 46 | .then(resultObj => { 47 | const retObj = { 48 | msg: "success", 49 | result: resultObj 50 | }; 51 | 52 | res.send(JSON.stringify(retObj)); 53 | }) 54 | .catch(error => { 55 | const retObj = { 56 | msg: "error", 57 | result: error.message 58 | }; 59 | 60 | res.send(JSON.stringify(retObj)); 61 | }); 62 | }); 63 | 64 | return api; 65 | } -------------------------------------------------------------------------------- /routes/api/utils/request/request.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | 3 | function parseError(error) { 4 | return error.response ? error.response.data.message : error.toString() 5 | } 6 | 7 | async function formatResponse(call, returnFull) { 8 | try { 9 | const res = await call(); 10 | return returnFull ? res : res.data; 11 | } catch (error) { 12 | throw new Error(parseError(error)); 13 | } 14 | }; 15 | 16 | function requestContentType(contentType, method, url, body = {}, options = {}, returnFull = false) { 17 | return formatResponse(() => { 18 | switch (method) { 19 | case "GET": 20 | return axios.get(url, { 21 | ...options, 22 | headers: 23 | options.headers != null 24 | ? { ...options.headers, "Content-Type": contentType } 25 | : { "Content-Type": contentType }, 26 | }); 27 | case "POST": 28 | return axios.post(url, body, { 29 | ...options, 30 | headers: 31 | options.headers != null 32 | ? { ...options.headers, "Content-Type": contentType } 33 | : { "Content-Type": contentType }, 34 | }); 35 | default: 36 | throw new Error(method + " is not a valid method type."); 37 | } 38 | }, returnFull); 39 | } 40 | 41 | function requestJson(method, url, body = {}, options = {}, returnFull = false) { 42 | return requestContentType("application/json", method, url, body, options, returnFull) 43 | } 44 | 45 | function requestXml(method, url, body = {}, options = {}, returnFull = false) { 46 | return requestContentType("application/xml", method, url, body, options, returnFull) 47 | } 48 | 49 | module.exports = { 50 | requestJson, 51 | requestXml 52 | } -------------------------------------------------------------------------------- /routes/api/utils/standardization/standardizeInfo.js: -------------------------------------------------------------------------------- 1 | const { requestJson } = require('../request/request'); 2 | 3 | const standardizeZecInfo = (info) => { 4 | return new Promise(async (resolve, reject) => { 5 | try { 6 | const res = await requestJson( 7 | "GET", 8 | "https://api.zcha.in/v2/mainnet/network" 9 | ); 10 | 11 | resolve({...info, longestchain: res.blockNumber}) 12 | } catch(e) { 13 | reject(e) 14 | } 15 | }) 16 | } 17 | 18 | const standardizationFns = { 19 | ['ZEC']: standardizeZecInfo 20 | } 21 | 22 | /** 23 | * Standardizes the behaviour of the get_info call to always include 24 | * utilized important values like 'longestchain' when they may not be 25 | * present, e.g., in ZEC. Returns a promise resolving to the standardized 26 | * info object. 27 | * 28 | * @param {Object} info The info result object to standardize 29 | * @param {String} coin The coin ticker to standardize 30 | * @param {Object} api The api object (for logging purposes) 31 | */ 32 | const standardizeInfo = (info, coin, api) => { 33 | let standardizationPromises = [] 34 | 35 | if (standardizationFns[coin] != null) { 36 | standardizationPromises.push( 37 | standardizationFns[coin](info) 38 | ); 39 | } else { 40 | standardizationPromises = [info] 41 | } 42 | 43 | return new Promise((resolve, reject) => { 44 | Promise.all(standardizationPromises) 45 | .then(infoArr => resolve(infoArr[0])) 46 | .catch(e => { 47 | api.log(`info standardization failed for ${coin}, returning regular info object:`, 'standardizeInfo'); 48 | api.log(e, 'standardizeInfo') 49 | resolve(info); 50 | }); 51 | }); 52 | } 53 | 54 | module.exports = standardizeInfo -------------------------------------------------------------------------------- /routes/api/native/verusid/provision/verifyIdProvisioningResponse.js: -------------------------------------------------------------------------------- 1 | const { LoginConsentProvisioningResponse } = require("verus-typescript-primitives"); 2 | const { ROOT_SYSTEM_NAME } = require("../../../utils/constants/dev_options"); 3 | 4 | module.exports = (api) => { 5 | /** 6 | * Verifies a provisioning response 7 | * @param {LoginConsentProvisioningResponse} Response 8 | */ 9 | api.native.verusid.provision.verify_id_provisioning_response = async (response) => { 10 | const provisioningResponse = new LoginConsentProvisioningResponse(response); 11 | 12 | // Convert the system id to the chain name. 13 | const currencyObject = await api.native.get_currency( 14 | ROOT_SYSTEM_NAME, 15 | response.system_id 16 | ); 17 | const chainTicker = currencyObject.name.toUpperCase(); 18 | 19 | const verified = await api.native.verify_hash( 20 | chainTicker, 21 | provisioningResponse.signing_id, 22 | provisioningResponse.decision.toSha256().toString('hex'), 23 | provisioningResponse.signature.signature 24 | ); 25 | 26 | return verified ? { verified } : { verified, message: "Failed to verify signature" }; 27 | }; 28 | 29 | api.setPost("/native/verusid/provision/verify_id_provisioning_response", async (req, res, next) => { 30 | const { response } = req.body; 31 | 32 | try { 33 | res.send( 34 | JSON.stringify({ 35 | msg: "success", 36 | result: await api.native.verusid.provision.verify_id_provisioning_response(response), 37 | }) 38 | ); 39 | } catch (e) { 40 | res.send( 41 | JSON.stringify({ 42 | msg: "error", 43 | result: e.message, 44 | }) 45 | ); 46 | } 47 | }); 48 | 49 | return api; 50 | }; 51 | -------------------------------------------------------------------------------- /routes/preloads/plugin/preload-default.js: -------------------------------------------------------------------------------- 1 | /* 2 | Reasonably Secure Electron 3 | Copyright (C) 2019 Bishop Fox 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program; if not, write to the Free Software 14 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 15 | ------------------------------------------------------------------------- 16 | This preload script is callable from within the sandbox via postMessage, 17 | but should not be directly accessible since it itself is not sandboxed. 18 | */ 19 | 20 | const { ipcRenderer } = require('electron'); 21 | 22 | 23 | window.addEventListener('message', (event) => { 24 | try { 25 | const msg = JSON.parse(event.data); 26 | if (msg.type === 'request') { 27 | if (['fs_'].some(prefix => msg.method.startsWith(prefix))) { 28 | ipcRenderer.send('ipc', msg); 29 | } 30 | } 31 | } catch (err) { 32 | console.error(err); 33 | } 34 | }); 35 | 36 | ipcRenderer.on('ipc', (_, msg) => { 37 | try { 38 | if (msg.type === 'response' || msg.type === 'push' || msg.type === 'init') { 39 | console.log(JSON.parse(msg.data)) 40 | 41 | window.postMessage(JSON.stringify(msg), '*'); 42 | } 43 | } catch (err) { 44 | console.error(err); 45 | } 46 | }); -------------------------------------------------------------------------------- /routes/api/plugin/builtin/pbaasvisualizer.js: -------------------------------------------------------------------------------- 1 | const { pushMessage } = require('../../../ipc/ipc'); 2 | const { ReservedPluginTypes } = require('../../utils/plugin/builtin'); 3 | 4 | module.exports = (api) => { 5 | api.pbaasVisualizer = {} 6 | 7 | api.pbaasVisualizer.visualize = async ( 8 | request, 9 | originInfo 10 | ) => { 11 | return new Promise((resolve, reject) => { 12 | try { 13 | api.startPlugin( 14 | ReservedPluginTypes.VERUS_PBAAS_VISUALIZER, 15 | true, 16 | () => {}, 17 | (pluginWindow) => { 18 | pushMessage( 19 | pluginWindow, 20 | { 21 | request: request, 22 | origin_app_info: originInfo, 23 | }, 24 | "VERUS_PBAAS_VISUALIZER_REQUEST" 25 | ); 26 | }, 27 | 1280, 28 | 850 29 | ); 30 | 31 | // No need to wait for any data to be returned, visualization is static 32 | resolve() 33 | } catch (e) { 34 | reject(e); 35 | } 36 | }); 37 | }; 38 | 39 | api.setPost('/plugin/builtin/verus_pbaas_visualizer/visualize', async (req, res, next) => { 40 | const { request } = req.body; 41 | const { app_id, builtin } = req.api_header 42 | 43 | try { 44 | const retObj = { 45 | msg: "success", 46 | result: await api.pbaasVisualizer.visualize( 47 | request, 48 | { 49 | id: app_id, 50 | search_builtin: builtin, 51 | } 52 | ), 53 | }; 54 | 55 | res.send(JSON.stringify(retObj)); 56 | } catch (e) { 57 | const retObj = { 58 | msg: 'error', 59 | result: e.message, 60 | }; 61 | 62 | res.send(JSON.stringify(retObj)); 63 | } 64 | }); 65 | 66 | return api; 67 | }; -------------------------------------------------------------------------------- /routes/api/erc20/addresses.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("ethers"); 2 | 3 | module.exports = (api) => { 4 | api.erc20.get_address = () => { 5 | if (api.erc20.wallet != null) { 6 | return api.erc20.wallet.address 7 | } else { 8 | throw new Error("No wallet authenticated, cannot get wallet address for ERC20") 9 | } 10 | }; 11 | 12 | api.erc20.get_addresses = async (contractId) => { 13 | return { 14 | public: [ 15 | { 16 | address: api.erc20.get_address(), 17 | tag: "eth", 18 | balances: { 19 | native: ethers.formatUnits( 20 | await api.erc20.get_wallet_balance(contractId), 21 | api.erc20.contracts[contractId].decimals 22 | ), 23 | reserve: {}, 24 | }, 25 | }, 26 | ], 27 | private: [], 28 | }; 29 | }; 30 | 31 | api.setGet('/erc20/get_addresses', (req, res, next) => { 32 | api.erc20.get_addresses(req.query.chainTicker) 33 | .then((addresses) => { 34 | const retObj = { 35 | msg: 'success', 36 | result: addresses, 37 | }; 38 | 39 | res.send(JSON.stringify(retObj)); 40 | }) 41 | .catch(error => { 42 | const retObj = { 43 | msg: 'error', 44 | result: error.message, 45 | }; 46 | 47 | res.send(JSON.stringify(retObj)); 48 | }) 49 | }); 50 | 51 | api.setPost('/erc20/get_privkey', (req, res, next) => { 52 | if (api.erc20.wallet != null) { 53 | res.send(JSON.stringify({ 54 | msg: 'success', 55 | result: api.erc20.wallet.signer.signingKey.privateKey, 56 | })); 57 | } else { 58 | res.send(JSON.stringify({ 59 | msg: 'error', 60 | result: `No ETH privkey found` 61 | })); 62 | } 63 | }, true); 64 | 65 | return api; 66 | }; -------------------------------------------------------------------------------- /routes/api/native/estimateSendcurrencyFee.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.estimate_sendcurrency_fee = async (chain, _params, minconfs = 1, sendfee = 0.0001) => { 3 | try { 4 | let feecurrency; 5 | 6 | const vETH = await api.native.get_currency(chain, 'vETH'); 7 | 8 | // These are throwaway addresses, without any funds, to ensure this 9 | // tx would fail if it were to be broadcasted, or at least not spend 10 | // any user funds in the absolute worst case scenario. 11 | const raddr = "RGM3raQ1McqQYZpFyuBrqUpLnmgK7h8k4A" 12 | const address = _params.exportto === vETH.currencyid ? 13 | "0xd62971620094e8244F1ed3B12a8D31bC969081fA" 14 | : 15 | raddr; 16 | 17 | const params = {..._params, amount: 0, address}; 18 | 19 | const res = await api.native.callDaemon(chain, 'sendcurrency', [raddr, [params], minconfs, sendfee, true]); 20 | 21 | if (params.feecurrency == null) { 22 | const chainCurrency = await api.native.get_currency(chain, chain); 23 | feecurrency = chainCurrency.currencyid; 24 | } else feecurrency = params.feecurrency; 25 | 26 | return res.outputtotals[feecurrency]; 27 | } catch(e) { 28 | throw e 29 | } 30 | }; 31 | 32 | api.setPost('/native/estimate_sendcurrency_fee', async (req, res, next) => { 33 | const { chainTicker, params, minconfs, sendfee } = req.body; 34 | 35 | try { 36 | const retObj = { 37 | msg: 'success', 38 | result: await api.native.estimate_sendcurrency_fee(chainTicker, params, minconfs, sendfee), 39 | }; 40 | 41 | res.send(JSON.stringify(retObj)); 42 | } catch(e) { 43 | const retObj = { 44 | msg: 'error', 45 | result: e.message, 46 | }; 47 | 48 | res.send(JSON.stringify(retObj)); 49 | } 50 | }); 51 | 52 | return api; 53 | }; -------------------------------------------------------------------------------- /routes/api/downloadUtil.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | const http = require('http') 3 | const https = require('https') 4 | const axios = require('axios') 5 | 6 | module.exports = (api) => { 7 | /** 8 | * Promise based download file method 9 | */ 10 | api.downloadFile = (configuration) => { 11 | return new Promise(async (resolve, reject) => { 12 | try { 13 | // Save variable to know progress 14 | let receivedBytes = 0; 15 | let totalBytes = 0; 16 | const httpAgent = new http.Agent({ keepAlive: true }); 17 | const httpsAgent = new https.Agent({ keepAlive: true }); 18 | 19 | const req = await axios({ 20 | method: 'get', 21 | url: configuration.remoteFile, 22 | responseType: 'stream', 23 | httpAgent, 24 | httpsAgent, 25 | }) 26 | 27 | let out = fs.createWriteStream(configuration.localFile); 28 | req.data.pipe(out); 29 | 30 | req.data.on("response", (data) => { 31 | // Change the total bytes value to get progress later. 32 | totalBytes = parseInt(data.headers["content-length"]); 33 | }); 34 | 35 | // Get progress if callback exists 36 | if (configuration.hasOwnProperty("onProgress")) { 37 | req.data.on("data", (chunk) => { 38 | // Update the received bytes 39 | receivedBytes += chunk.length; 40 | configuration.onProgress(receivedBytes, totalBytes); 41 | }); 42 | } else { 43 | req.data.on("data", (chunk) => { 44 | // Update the received bytes 45 | receivedBytes += chunk.length; 46 | }); 47 | } 48 | 49 | req.data.on("end", () => { 50 | resolve(); 51 | }); 52 | } catch (e) { 53 | reject(e); 54 | } 55 | 56 | }); 57 | } 58 | 59 | return api; 60 | }; -------------------------------------------------------------------------------- /routes/api/native/verusid/provision/signIdProvisioningRequest.js: -------------------------------------------------------------------------------- 1 | const { VerusIDSignature, IDENTITY_AUTH_SIG_VDXF_KEY } = require("verus-typescript-primitives"); 2 | const { ProvisioningRequest } = require("verus-typescript-primitives/dist/vdxf/classes/provisioning/ProvisioningRequest"); 3 | 4 | module.exports = (api) => { 5 | /** 6 | * Signs a provisioning request using an r-address. 7 | * 8 | * @param {String} coin The chainTicker of the coin to make the call on 9 | * @param {String} request The provisioning request to sign 10 | * @param {String} raddress The raddress to sign the provioning requset with 11 | */ 12 | api.native.verusid.provision.sign_id_provisioning_request = async (coin, request, raddress) => { 13 | 14 | const provisioningRequest = new ProvisioningRequest(request); 15 | 16 | const signdataResult = await api.native.sign_data(coin, 17 | { 18 | "address": raddress, 19 | "datahash": provisioningRequest.challenge.toSha256().toString("hex") 20 | } 21 | ) 22 | 23 | provisioningRequest.signature = new VerusIDSignature( 24 | { signature: signdataResult.signature }, 25 | IDENTITY_AUTH_SIG_VDXF_KEY 26 | ); 27 | 28 | return provisioningRequest; 29 | } 30 | 31 | api.setPost('/native/verusid/provision/sign_id_provisioning_request', async (req, res, next) => { 32 | const { 33 | chainTicker, 34 | request, 35 | raddress 36 | } = req.body; 37 | 38 | try { 39 | res.send( 40 | JSON.stringify({ 41 | msg: "success", 42 | result: await api.native.verusid.provision.sign_id_provisioning_request(chainTicker, request, raddress), 43 | }) 44 | ); 45 | } catch (e) { 46 | res.send( 47 | JSON.stringify({ 48 | msg: "error", 49 | result: e.message, 50 | }) 51 | ); 52 | } 53 | }); 54 | 55 | return api; 56 | } -------------------------------------------------------------------------------- /routes/api/electrum/block.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = (api) => { 3 | api.setGet('/electrum/getblockinfo', (req, res, next) => { 4 | api.electrumGetBlockInfo(req.query.height, req.query.network) 5 | .then((json) => { 6 | const retObj = { 7 | msg: 'success', 8 | result: json, 9 | }; 10 | 11 | res.send(JSON.stringify(retObj)); 12 | }); 13 | }); 14 | 15 | api.electrumGetBlockInfo = (height, network) => { 16 | return new Promise((resolve, reject) => { 17 | async function _electrumGetBlockInfo() { 18 | const ecl = await api.ecl(network); 19 | 20 | ecl.blockchainBlockGetHeader(height).then((json) => { 21 | api.log("electrum getblockinfo ==>", "spv.getblockinfo"); 22 | api.log(json, "spv.getblockinfo"); 23 | 24 | resolve(json); 25 | }); 26 | } 27 | _electrumGetBlockInfo(); 28 | }); 29 | } 30 | 31 | api.setGet('/electrum/getcurrentblock', (req, res, next) => { 32 | api.electrumGetCurrentBlock(req.query.network) 33 | .then((json) => { 34 | const retObj = { 35 | msg: 'success', 36 | result: json, 37 | }; 38 | 39 | res.send(JSON.stringify(retObj)); 40 | }); 41 | }); 42 | 43 | api.electrumGetCurrentBlock = (network, returnNspvReq) => { 44 | return new Promise((resolve, reject) => { 45 | async function _electrumGetCurrentBlock() { 46 | const ecl = await api.ecl(network); 47 | 48 | ecl.blockchainHeadersSubscribe().then((json) => { 49 | if (json && json.hasOwnProperty("block_height")) { 50 | resolve(json.block_height); 51 | } else if (json && json.hasOwnProperty("height")) { 52 | resolve(json.height); 53 | } else { 54 | resolve(json); 55 | } 56 | }); 57 | }; 58 | _electrumGetCurrentBlock(); 59 | }); 60 | } 61 | 62 | return api; 63 | }; -------------------------------------------------------------------------------- /routes/api/system.js: -------------------------------------------------------------------------------- 1 | const si = require('systeminformation') 2 | 3 | module.exports = (api) => { 4 | /* 5 | * type: GET 6 | */ 7 | api.setGet('/get_static_system_data', (req, res, next) => { 8 | si.getStaticData() 9 | .then(data => { 10 | res.send(JSON.stringify({ 11 | msg: 'success', 12 | result: data 13 | })); 14 | }) 15 | .catch(e => { 16 | res.send(JSON.stringify({ 17 | msg: 'error', 18 | result: e.message 19 | })); 20 | }) 21 | }); 22 | 23 | /* 24 | * type: GET 25 | */ 26 | api.setGet('/get_cpu_temp', (req, res, next) => { 27 | const CPU_TEMP_UNSUPPORTED = null 28 | 29 | si.cpuTemperature() 30 | .then(data => { 31 | if (data.main && data.main === CPU_TEMP_UNSUPPORTED) throw new Error('unsupported_operation') 32 | 33 | res.send(JSON.stringify({ 34 | msg: 'success', 35 | result: data 36 | })); 37 | }) 38 | .catch(e => { 39 | res.send(JSON.stringify({ 40 | msg: 'error', 41 | result: e.message 42 | })); 43 | }) 44 | }); 45 | 46 | /* 47 | * type: GET 48 | */ 49 | api.setGet('/get_cpu_load', (req, res, next) => { 50 | si.currentLoad() 51 | .then(data => { 52 | res.send(JSON.stringify({ 53 | msg: 'success', 54 | result: data 55 | })); 56 | }) 57 | .catch(e => { 58 | res.send(JSON.stringify({ 59 | msg: 'error', 60 | result: e.message 61 | })); 62 | }) 63 | }); 64 | 65 | /* 66 | * type: GET 67 | */ 68 | api.setGet('/get_sys_time', (req, res, next) => { 69 | try { 70 | res.send(JSON.stringify({ 71 | msg: 'success', 72 | result: si.time() 73 | })); 74 | } catch (e) { 75 | res.send(JSON.stringify({ 76 | msg: 'error', 77 | result: e.message 78 | })); 79 | } 80 | }); 81 | 82 | return api; 83 | }; 84 | -------------------------------------------------------------------------------- /test/verusid-login.js: -------------------------------------------------------------------------------- 1 | const test_request = { 2 | chain_id: "VRSCTEST", 3 | signing_id: "login-consent-server@", 4 | signature: { 5 | signature: 6 | "AaYuAAABQSD/UR9NIeimLYyUrkJ7kfjXJz0QiuVsFIt+lEu+KSELCX5zxAlIiciuIHLIzKLsuqMFL3XDapg/1TnV0b6hXoSX", 7 | }, 8 | challenge: { 9 | uuid: "7bb518c4eec2454dbb289f5fdb4c0ee2", 10 | requested_scope: ["vrsc::system.identity.authentication.scope.read-id-name"], 11 | requested_access_token_audience: null, 12 | skip: false, 13 | oidc_context: {}, 14 | request_url: "http://127.0.0.1:4444/oauth2?full=request&url=", 15 | client: { 16 | client_id: "auth-code-client", 17 | name: "Online Service", 18 | redirect_uris: ["http://127.0.0.1:5555/callback"], 19 | grant_types: ["authorization_code", "refresh_token"], 20 | response_types: ["code", "id_token"], 21 | scope: "vrsc::system.identity.authentication.scope.read-id-name", 22 | audience: null, 23 | owner: "", 24 | policy_uri: "https://verus.io/privacy-policy", 25 | allowed_cors_origins: null, 26 | tos_uri: "https://en.wikipedia.org/wiki/Lorem_ipsum", 27 | client_uri: "https://verus.io/", 28 | logo_uri: 29 | "https://github.com/VerusCoin/Media-Assets/blob/master/Logos/PNG%20(pixel)/Logo/verus-icon-blue-500px.png", 30 | contacts: null, 31 | client_secret_expires_at: 0, 32 | subject_type: "public", 33 | token_endpoint_auth_method: "client_secret_basic", 34 | userinfo_signed_response_alg: "none", 35 | created_at: "2020-07-08T12:31:47Z", 36 | updated_at: "2020-07-08T12:31:47Z", 37 | }, 38 | }, 39 | }; 40 | 41 | const test_response_no_sig = { 42 | chain_id: "VRSCTEST", 43 | signing_id: "login-consent-server@", 44 | decision: { 45 | subject: "Client@", 46 | remember: true, 47 | remember_for: 7200, 48 | force_subject_identifier: "string", 49 | request: test_request, 50 | }, 51 | }; 52 | -------------------------------------------------------------------------------- /routes/api/data_files/backup.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | 3 | module.exports = (api) => { 4 | /** 5 | * Backs up all necessary app data stored for Verus Desktop 6 | */ 7 | api.backupAppData = async (backupName) => { 8 | if ( 9 | backupName.includes(".") || 10 | backupName.includes("/") || 11 | backupName.includes("\\") || 12 | backupName.includes("*") || 13 | backupName.includes("~") || 14 | backupName == null 15 | ) { 16 | throw new Error(`Backup data name (${backupName}) cannot include any of the following: ./\\*~`) 17 | } 18 | 19 | try { 20 | await fs.access(api.paths.agamaDir, fs.constants.R_OK); 21 | } catch (e) { 22 | if (e.code == "EACCES") { 23 | await fs.chmod(path, "0666"); 24 | } else if (e.code === "ENOENT") { 25 | api.handleFileProblem(`Verus Desktop directory not found`, !handleErrors) 26 | return 27 | } 28 | } 29 | 30 | try { 31 | const backupPath = `${api.paths.backupDir}/${backupName}` 32 | 33 | if (await fs.exists(backupPath)) { 34 | throw new Error(`Backup at ${backupPath} already exists!`) 35 | } 36 | 37 | await fs.copy(api.paths.agamaDir, backupPath); 38 | 39 | api.log( 40 | `appdata backup created at ${backupPath}`, 41 | "backup" 42 | ); 43 | return 44 | } catch (e) { 45 | api.log(e, 'backup'); 46 | throw e 47 | } 48 | }; 49 | 50 | api.setPost('/backup_appdata', async (req, res, next) => { 51 | const { dirName } = req.body 52 | 53 | try { 54 | const retObj = { 55 | msg: 'success', 56 | result: await api.backupAppData(dirName), 57 | }; 58 | 59 | res.send(JSON.stringify(retObj)); 60 | } catch (e) { 61 | const retObj = { 62 | msg: 'error', 63 | result: e.message, 64 | }; 65 | 66 | res.send(JSON.stringify(retObj)); 67 | } 68 | }); 69 | 70 | return api; 71 | }; -------------------------------------------------------------------------------- /test/spec-kmd.js: -------------------------------------------------------------------------------- 1 | const Application = require('spectron').Application 2 | const assert = require('assert') 3 | const electronPath = require('electron') // Require Electron from the binaries included in node_modules. 4 | const path = require('path') 5 | const chai = require('chai') 6 | const timeout = 7500; 7 | describe('Application launch testing native KMD coin', function () { 8 | this.timeout(timeout) 9 | before(function () { 10 | this.gotDomReadyCount = 0 11 | this.app = new Application({ 12 | path: electronPath, 13 | // The following line tells spectron to look and use the main.js file 14 | // and the package.json located 1 level above. 15 | args: [path.join(__dirname, '..')], 16 | startTimeout: timeout, 17 | waitTimeout: timeout 18 | }) 19 | return this.app.start() 20 | }) 21 | 22 | after(function () { 23 | if (this.app && this.app.isRunning()) { 24 | return this.app.stop() 25 | } 26 | }) 27 | 28 | it('opens a window', function (done) { 29 | this.app.client.waitUntilWindowLoaded() 30 | .getWindowCount().then(function (count) { 31 | assert.equal(count, 1) 32 | done() 33 | }) 34 | }) 35 | 36 | it('has a native coin list that takes kmd', function (done) { 37 | // Wait for the left button for native mode coins is visible 38 | this.app.client.element('#react-select-3--value').waitForVisible(3000) 39 | // Click on it and enter kmd 40 | this.app.client.element('#react-select-3--value').click().keys('kmd\r\n').then(function () { 41 | done() 42 | }) 43 | }) 44 | 45 | it('delays for a bit', function() { 46 | return new Promise(function(resolve) { 47 | setTimeout(resolve, 500, true); 48 | }); 49 | }) 50 | 51 | it('has KMD in the HTML body', function(done) { 52 | this.app.client.getHTML('body').then(function (html) { 53 | assert(html.includes('KMD'), 'Did not find KMD coin') 54 | done() 55 | }) 56 | }) 57 | }) 58 | 59 | -------------------------------------------------------------------------------- /routes/api/native/verusid/login/signResponse.js: -------------------------------------------------------------------------------- 1 | const { 2 | VerusIDSignature, 3 | LoginConsentResponse, 4 | LOGIN_CONSENT_RESPONSE_SIG_VDXF_KEY, 5 | } = require("verus-typescript-primitives"); 6 | 7 | module.exports = (api) => { 8 | api.native.verusid.login.sign_response = async (response) => { 9 | const loginResponse = new LoginConsentResponse(response); 10 | const chainTicker = response.chainTicker 11 | // Add the chainTicker when checking the request since the verify request needs it. 12 | let decisionRequest = loginResponse.decision.request 13 | decisionRequest.chainTicker = chainTicker 14 | 15 | const verificatonCheck = await api.native.verusid.login.verify_request( 16 | decisionRequest 17 | ); 18 | 19 | if (!verificatonCheck.verified) { 20 | throw new Error(verificatonCheck.message); 21 | } 22 | 23 | const signdataResult = await api.native.sign_data(chainTicker, 24 | { 25 | "address": loginResponse.signing_id, 26 | "datahash": loginResponse.decision.toSha256().toString("hex") 27 | } 28 | ) 29 | 30 | loginResponse.signature = new VerusIDSignature( 31 | { signature: signdataResult.signature }, 32 | LOGIN_CONSENT_RESPONSE_SIG_VDXF_KEY 33 | ); 34 | 35 | // Remove the chainTicker field since it's not normally part of the response. 36 | delete decisionRequest.chainTicker 37 | 38 | return { response: loginResponse}; 39 | }; 40 | 41 | api.setPost("/native/verusid/login/sign_response", async (req, res, next) => { 42 | const { response } = req.body; 43 | 44 | try { 45 | res.send( 46 | JSON.stringify({ 47 | msg: "success", 48 | result: await api.native.verusid.login.sign_response(response), 49 | }) 50 | ); 51 | } catch (e) { 52 | res.send( 53 | JSON.stringify({ 54 | msg: "error", 55 | result: e.message, 56 | }) 57 | ); 58 | } 59 | }); 60 | 61 | return api; 62 | }; 63 | -------------------------------------------------------------------------------- /test/spec-vrsc.js: -------------------------------------------------------------------------------- 1 | const Application = require('spectron').Application 2 | const assert = require('assert') 3 | const electronPath = require('electron') // Require Electron from the binaries included in node_modules. 4 | const path = require('path') 5 | const chai = require('chai') 6 | const timeout = 7500; 7 | describe('Application launch testing native VRSC coin', function () { 8 | this.timeout(timeout) 9 | before(function () { 10 | this.gotDomReadyCount = 0 11 | this.app = new Application({ 12 | path: electronPath, 13 | // The following line tells spectron to look and use the main.js file 14 | // and the package.json located 1 level above. 15 | args: [path.join(__dirname, '..')], 16 | startTimeout: timeout, 17 | waitTimeout: timeout 18 | }) 19 | return this.app.start() 20 | }) 21 | 22 | after(function () { 23 | if (this.app && this.app.isRunning()) { 24 | return this.app.stop() 25 | } 26 | }) 27 | 28 | it('opens a window', function (done) { 29 | this.app.client.waitUntilWindowLoaded() 30 | .getWindowCount().then(function (count) { 31 | assert.equal(count, 1) 32 | done() 33 | }) 34 | }) 35 | 36 | it('has a native coin list that takes vrsc', function (done) { 37 | // Wait for the left button for native mode coins is visible 38 | this.app.client.element('#react-select-3--value').waitForVisible(3000) 39 | // Click on it and enter vrsc 40 | this.app.client.element('#react-select-3--value').click().keys('vrsc\r\n').then(function () { 41 | done() 42 | }) 43 | }) 44 | 45 | it('delays for a bit', function() { 46 | return new Promise(function(resolve) { 47 | setTimeout(resolve, 500, true); 48 | }); 49 | }) 50 | 51 | it('has VRSC in the HTML body', function(done) { 52 | this.app.client.getHTML('body').then(function (html) { 53 | assert(html.includes('VRSC'), 'Did not find VRSC coin') 54 | done() 55 | }) 56 | }) 57 | }) 58 | 59 | -------------------------------------------------------------------------------- /routes/nativeCoind.js: -------------------------------------------------------------------------------- 1 | const nativeCoind = { 2 | 'btc': { 3 | name: 'Bitcoin', 4 | bin: 'bitcoin', 5 | fullMode: true, 6 | port: 8332, 7 | }, 8 | 'btcd': { 9 | name: 'BitcoinDark', 10 | bin: 'bitcoindarkd', 11 | fullMode: true, 12 | port: 14632, 13 | }, 14 | 'ltc': { 15 | name: 'Litecoin', 16 | bin: 'litecoin', 17 | fullMode: true, 18 | port: 9332, 19 | }, 20 | 'sys': { 21 | name: 'Syscoin', 22 | bin: 'syscoin', 23 | fullMode: true, 24 | port: 8368, 25 | }, 26 | 'uno': { 27 | name: 'Unobtanium', 28 | bin: 'unobtanium', 29 | fullMode: true, 30 | port: 65535, 31 | }, 32 | 'nmc': { 33 | name: 'Namecoin', 34 | bin: 'namecoin', 35 | fullMode: true, 36 | port: 8336, 37 | }, 38 | 'game': { 39 | name: 'GameCredits', 40 | bin: 'gamecredits', 41 | fullMode: true, 42 | port: 40001, 43 | }, 44 | 'mzc': { 45 | name: 'MazaCoin', 46 | bin: 'maza', 47 | fullMode: true, 48 | port: 12832, 49 | }, 50 | 'frk': { 51 | name: 'Franko', 52 | bin: 'franko', 53 | fullMode: true, 54 | port: 7913, 55 | }, 56 | 'doge': { 57 | name: 'Dogecoin', 58 | bin: 'dogecoin', 59 | fullMode: true, 60 | port: 22555, 61 | }, 62 | 'dgb': { 63 | name: 'Digibyte', 64 | bin: 'digibyte', 65 | port: 14022, 66 | }, 67 | 'zet': { 68 | name: 'Zetacoin', 69 | bin: 'zetacoin', 70 | fullMode: true, 71 | port: 17335, 72 | }, 73 | 'btm': { 74 | name: 'Bitmark', 75 | bin: 'bitmark', 76 | fullMode: true, 77 | port: 9266, 78 | }, 79 | 'carb': { 80 | name: 'Carboncoin', 81 | bin: 'carboncoin', 82 | fullMode: true, 83 | port: 9351, 84 | }, 85 | 'anc': { 86 | name: 'Anoncoin', 87 | bin: 'anoncoin', 88 | fullMode: true, 89 | port: 28332, 90 | }, 91 | 'lbc': { 92 | name: 'LBRY Credits', 93 | bin: 'lbrycrd', 94 | port: 9245, 95 | } 96 | }; 97 | 98 | module.exports = nativeCoind; -------------------------------------------------------------------------------- /test/spec.js: -------------------------------------------------------------------------------- 1 | const Application = require('spectron').Application 2 | const assert = require('assert') 3 | const electronPath = require('electron') // Require Electron from the binaries included in node_modules. 4 | const path = require('path') 5 | const chai = require('chai') 6 | const timeout = 7500; 7 | describe('Application launch testing native MORTY coin', function () { 8 | this.timeout(timeout) 9 | before(function () { 10 | this.gotDomReadyCount = 0 11 | this.app = new Application({ 12 | path: electronPath, 13 | // The following line tells spectron to look and use the main.js file 14 | // and the package.json located 1 level above. 15 | args: [path.join(__dirname, '..')], 16 | startTimeout: timeout, 17 | waitTimeout: timeout 18 | }) 19 | return this.app.start() 20 | }) 21 | 22 | after(function () { 23 | if (this.app && this.app.isRunning()) { 24 | return this.app.stop() 25 | } 26 | }) 27 | 28 | it('opens a window', function (done) { 29 | this.app.client.waitUntilWindowLoaded() 30 | .getWindowCount().then(function (count) { 31 | assert.equal(count, 1) 32 | done() 33 | }) 34 | }) 35 | 36 | it('has a native coin list that takes MORTY', function (done) { 37 | // Wait for the left button for native mode coins is visible 38 | this.app.client.element('#react-select-3--value').waitForVisible(3000) 39 | // Click on it and enter MORTY 40 | this.app.client.element('#react-select-3--value').click().keys('MORTY\r\n').then(function () { 41 | done() 42 | }) 43 | }) 44 | 45 | it('delays for a bit', function() { 46 | return new Promise(function(resolve) { 47 | setTimeout(resolve, 500, true); 48 | }); 49 | }) 50 | 51 | it('has MORTY in the HTML body', function(done) { 52 | this.app.client.getHTML('body').then(function (html) { 53 | assert(html.includes('MORTY'), 'Did not find MORTY coin') 54 | done() 55 | }) 56 | }) 57 | }) 58 | 59 | -------------------------------------------------------------------------------- /assets/deps/confs/BTCD_peers.txt: -------------------------------------------------------------------------------- 1 | 89.248.160.237 2 | 89.248.160.238 3 | 89.248.160.239 4 | 89.248.160.240 5 | 89.248.160.241 6 | 89.248.160.242 7 | 89.248.160.243 8 | 89.248.160.244 9 | 89.248.160.245 10 | 5.9.102.210 11 | 78.47.196.146 12 | 85.25.217.233:14631 13 | 88.198.53.194:55692 14 | 88.206.186.58:37299 15 | 162.255.117.105:63084 16 | 115.28.42.60:60878 17 | 82.176.15.155:35026 18 | 88.198.15.19:48150 19 | 176.9.13.13:14631 20 | 217.8.62.188:52714 21 | 162.13.4.69:55410 22 | 211.58.177.43:35581 23 | 63.247.147.166:50266 24 | 24.168.17.50:50793 25 | 46.231.137.186:56963 26 | 178.62.185.131:35572 27 | 62.75.145.171:14631 28 | 89.212.19.49:48018 29 | 192.99.233.217:42232 30 | 68.190.213.46:14631 31 | 162.210.92.46:14631 32 | 98.118.105.12:60805 33 | 75.130.163.51:56719 34 | 51.255.38.28:14631 35 | 88.110.117.18:52158 36 | 24.101.114.249:55457 37 | 99.44.222.86:62377 38 | 108.61.166.209:58365 39 | 98.208.113.72:62065 40 | 72.133.226.130:14631 41 | 5.189.144.97:58243 42 | 14.203.46.202:57987 43 | 98.202.147.55:60460 44 | 24.45.172.109:14631 45 | 89.114.38.65:52768 46 | 68.59.64.126:50633 47 | 68.43.220.127:4303 48 | 81.205.30.207:63077 49 | 113.87.28.142:62764 50 | 73.211.90.130:41271 51 | 110.174.129.213:49252 52 | 68.45.147.145:57803 53 | 95.232.175.161:62633 54 | 73.229.133.160:38440 55 | 124.191.14.253:54342 56 | 167.114.249.196:52705 57 | 92.24.168.248:52892 58 | 93.158.216.201:14631 59 | 158.69.27.82:46643 60 | 104.204.109.11:63390 61 | 68.157.88.187:56711 62 | 71.53.152.87:5234 63 | 82.229.201.131:63466 64 | 59.147.42.146:57461 65 | 81.0.91.211:53187 66 | 82.241.71.230:51945 67 | 108.247.198.39:64094 68 | 77.22.227.8:65093 69 | 122.166.169.11:49325 70 | 173.76.182.122:14631 71 | 173.24.82.253:14631 72 | 100.13.54.119:14631 73 | 2.26.181.208:14631 74 | 94.242.213.3:14631 75 | 87.149.45.42:36077 76 | 98.207.117.83:50955 77 | 71.1.8.48:14631 78 | 71.1.8.48:50439 79 | 101.166.241.31:14631 80 | 178.143.154.142:27497 81 | 103.255.7.59:58660 82 | 156.57.132.119:62428 83 | 60.225.171.82:36834 84 | 46.223.149.120:43358 85 | 37.157.215.75:4162 86 | -------------------------------------------------------------------------------- /routes/api/erc20/balances.js: -------------------------------------------------------------------------------- 1 | const ethers = require('ethers'); 2 | 3 | module.exports = (api) => { 4 | api.setGet("/erc20/get_balances", async (req, res, next) => { 5 | try { 6 | res.send( 7 | JSON.stringify({ 8 | msg: "success", 9 | result: { 10 | native: { 11 | public: { 12 | //TODO: Return string instead 13 | confirmed: Number(ethers.formatUnits( 14 | await api.erc20.get_wallet_balance(req.query.chainTicker), 15 | api.erc20.contracts[req.query.chainTicker].decimals 16 | )), 17 | unconfirmed: null, 18 | immature: null, 19 | interest: null, 20 | }, 21 | private: { 22 | confirmed: null, 23 | }, 24 | }, 25 | reserve: {}, 26 | }, 27 | }) 28 | ); 29 | } catch (e) { 30 | res.send( 31 | JSON.stringify({ 32 | msg: "error", 33 | result: e.message, 34 | }) 35 | ); 36 | } 37 | }); 38 | 39 | api.erc20.get_address_balance = async (contractId, address) => { 40 | if (api.erc20.contracts[contractId] != null) { 41 | if (api.erc20.contracts[contractId].contract.balanceOf) { 42 | return await api.erc20.contracts[contractId].contract.balanceOf(address) 43 | } else { 44 | throw new Error(`ERC20 contract ${contractId} does not support the balanceOf function`) 45 | } 46 | } else { 47 | throw new Error(`Cannot get balance for inactive coin ${contractId}`) 48 | } 49 | } 50 | 51 | api.erc20.get_wallet_balance = async (contractId) => { 52 | if (api.erc20.wallet != null) { 53 | return await api.erc20.get_address_balance( 54 | contractId, 55 | api.erc20.wallet.address 56 | ); 57 | } else { 58 | throw new Error(`No wallet authenticated, cannot get wallet balance for ${contractId}`) 59 | } 60 | } 61 | 62 | return api; 63 | }; -------------------------------------------------------------------------------- /routes/api/utils/plugin/permissions.js: -------------------------------------------------------------------------------- 1 | const READ_CORE = "READ_CORE" 2 | const WRITE_CORE = "WRITE_CORE" 3 | const EXECUTE_CORE = "EXECUTE_CORE" 4 | 5 | const READ_NATIVE = "READ_NATIVE" 6 | const WRITE_NATIVE = "WRITE_NATIVE" 7 | const EXECUTE_NATIVE = "EXECUTE_NATIVE" 8 | 9 | const READ_ELECTRUM = "READ_ELECTRUM" 10 | const WRITE_ELECTRUM = "WRITE_ELECTRUM" 11 | const EXECUTE_ELECTRUM = "EXECUTE_ELECTRUM" 12 | 13 | const READ_ETH = "READ_ETH" 14 | const WRITE_ETH = "WRITE_ETH" 15 | const EXECUTE_ETH = "EXECUTE_ETH" 16 | 17 | const READ_WALLET = "READ_WALLET" 18 | const WRITE_WALLET = "WRITE_WALLET" 19 | const EXECUTE_WALLET = "EXECUTE_WALLET" 20 | 21 | const READ_SENSITIVE = "READ_SENSITIVE" 22 | const WRITE_SENSITIVE = "WRITE_SENSITIVE" 23 | const EXECUTE_SENSITIVE = "EXECUTE_SENSITIVE" 24 | 25 | const READ_PLUGINS = "READ_PLUGINS" 26 | const WRITE_PLUGINS = "WRITE_PLUGINS" 27 | const EXECUTE_PLUGINS = "EXECUTE_PLUGINS" 28 | 29 | const READ_FS = "READ_FS" 30 | const WRITE_FS = "WRITE_FS" 31 | const EXECUTE_FS = "EXECUTE_FS" 32 | 33 | const READ_UTILITIES = "READ_UTILITIES" 34 | const WRITE_UTILITIES = "WRITE_UTILITIES" 35 | const EXECUTE_UTILITIES = "EXECUTE_UTILITIES" 36 | 37 | const READ_SYSDATA = "READ_SYSDATA" 38 | const WRITE_SYSDATA = "WRITE_SYSDATA" 39 | const EXECUTE_SYSDATA = "EXECUTE_SYSDATA" 40 | 41 | const SIGN = "SIGN" 42 | 43 | module.exports = { 44 | READ_CORE, 45 | WRITE_CORE, 46 | EXECUTE_CORE, 47 | 48 | READ_NATIVE, 49 | WRITE_NATIVE, 50 | EXECUTE_NATIVE, 51 | 52 | READ_ELECTRUM, 53 | WRITE_ELECTRUM, 54 | EXECUTE_ELECTRUM, 55 | 56 | READ_ETH, 57 | WRITE_ETH, 58 | EXECUTE_ETH, 59 | 60 | READ_WALLET, 61 | WRITE_WALLET, 62 | EXECUTE_WALLET, 63 | 64 | READ_SENSITIVE, 65 | WRITE_SENSITIVE, 66 | EXECUTE_SENSITIVE, 67 | 68 | READ_PLUGINS, 69 | WRITE_PLUGINS, 70 | EXECUTE_PLUGINS, 71 | 72 | READ_FS, 73 | WRITE_FS, 74 | EXECUTE_FS, 75 | 76 | READ_UTILITIES, 77 | WRITE_UTILITIES, 78 | EXECUTE_UTILITIES, 79 | 80 | READ_SYSDATA, 81 | WRITE_SYSDATA, 82 | EXECUTE_SYSDATA, 83 | 84 | SIGN, 85 | } 86 | 87 | -------------------------------------------------------------------------------- /routes/api/utility_apis/cache.js: -------------------------------------------------------------------------------- 1 | var blake2b = require('blake2b'); 2 | const LFUCache = require('../utils/cache'); 3 | 4 | const BYTES_PER_MB = 1000000 5 | 6 | module.exports = (api) => { 7 | api.derive_cache_key = (cache, query) => { 8 | var hash = blake2b(64) 9 | 10 | for (const type of cache.split('.')) { 11 | hash.update(type) 12 | } 13 | 14 | hash.update(query) 15 | 16 | return hash.digest('hex') 17 | } 18 | 19 | api.initMainCache = () => { 20 | api.internal_cache = new LFUCache( 21 | !isNaN(api.appConfig.general.main.cacheMbLimit) 22 | ? api.appConfig.general.main.cacheMbLimit * BYTES_PER_MB 23 | : 10000000 24 | ) 25 | 26 | api.main_cache = { 27 | del: (cache, query) => 28 | api.internal_cache.del(api.derive_cache_key(cache, query)), 29 | set: (cache, query, value) => { 30 | try { 31 | return api.internal_cache.set(api.derive_cache_key(cache, query), value) 32 | } catch(e) { 33 | api.log( 34 | "Failed to set cache value for the following cache, query, and value, recived the following error.", 35 | "main_cache" 36 | ); 37 | api.log(cache, "main_cache") 38 | api.log(query, "main_cache") 39 | api.log(value, "main_cache") 40 | api.log(e, "main_cache") 41 | 42 | return false 43 | } 44 | }, 45 | get: (cache, query) => 46 | api.internal_cache.get(api.derive_cache_key(cache, query)), 47 | has: (cache, query) => 48 | api.internal_cache.has(api.derive_cache_key(cache, query)), 49 | getStats: () => api.internal_cache.getStats(), 50 | }; 51 | 52 | Object.freeze(api.main_cache); 53 | } 54 | 55 | api.create_sub_cache = (id) => { 56 | return { 57 | del: (query) => api.main_cache.del(id, query), 58 | set: (query, value) => api.main_cache.set(id, query, value), 59 | get: (query) => api.main_cache.get(id, query), 60 | has: (query) => api.main_cache.has(id, query), 61 | } 62 | } 63 | 64 | return api; 65 | }; -------------------------------------------------------------------------------- /routes/api/log.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | const path = require('path') 3 | const { secondsToString } = require('agama-wallet-lib/src/time'); 4 | 5 | module.exports = (api) => { 6 | api.log = (msg, type) => { 7 | if (api.appConfig.general.main.dev || 8 | api.appConfig.general.main.debug || 9 | process.argv.indexOf('devmode') > -1) { 10 | if (type) { 11 | console.log(`\x1b[94m${type}`, '\x1b[0m', msg); 12 | } else { 13 | console.log(msg); 14 | } 15 | } 16 | 17 | if (api.appConfig.general.main.livelog) { 18 | api.writeLog(msg, type) 19 | } 20 | 21 | api.appRuntimeLog.push({ 22 | time: Date.now(), 23 | msg: msg, 24 | type: type, 25 | }); 26 | } 27 | 28 | api.writeLog = (data, type) => { 29 | const logLocation = api.paths.agamaDir; 30 | const timeFormatted = new Date(Date.now()).toLocaleString('en-US', { hour12: false }); 31 | const livelogPath = path.join(logLocation, 'Verus-Desktop.log') 32 | 33 | if (fs.existsSync(livelogPath)) { 34 | fs.appendFile(livelogPath, `${timeFormatted} [${type}] ${data}\r\n`, (err) => { 35 | if (err) { 36 | api.log('error appending live log file'); 37 | } 38 | }); 39 | } else { 40 | fs.writeFile(livelogPath, `${timeFormatted} [${type}] ${data}\r\n`, (err) => { 41 | if (err) { 42 | api.log('error writing live log file'); 43 | } 44 | }); 45 | } 46 | } 47 | 48 | api.clearWriteLog = () => { 49 | const logLocation = api.paths.agamaDir; 50 | const livelogPath = path.join(logLocation, 'Verus-Desktop.log') 51 | 52 | if (fs.existsSync(livelogPath)) { 53 | fs.writeFileSync(livelogPath, ''); 54 | } 55 | } 56 | 57 | api.getAppRuntimeLog = () => { 58 | return new Promise((resolve, reject) => { 59 | resolve(api.appRuntimeLog); 60 | }); 61 | }; 62 | 63 | api.printDirs = () => { 64 | api.log("DIR PATHS:", 'env') 65 | for (const pathType in api.paths) { 66 | api.log(`${pathType}: ${api.paths[pathType]}`, 'env') 67 | } 68 | } 69 | 70 | return api; 71 | }; -------------------------------------------------------------------------------- /routes/api/confMaxconnections.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | 3 | module.exports = (api) => { 4 | api.getMaxconKMDConf = () => { 5 | return new Promise((resolve, reject) => { 6 | fs.readFile(`${api.paths.kmdDataDir}/komodo.conf`, 'utf8', (err, data) => { 7 | if (err) { 8 | api.log('kmd conf maxconnections param read failed', 'native.confd'); 9 | resolve('unset'); 10 | } else { 11 | const _maxcon = data.match(/maxconnections=\s*(.*)/); 12 | 13 | if (!_maxcon) { 14 | api.log('kmd conf maxconnections param is unset', 'native.confd'); 15 | resolve(false); 16 | } else { 17 | api.log(`kmd conf maxconnections param is already set to ${_maxcon[1]}`, 'native.confd'); 18 | resolve(_maxcon[1]); 19 | } 20 | } 21 | }); 22 | }); 23 | } 24 | 25 | api.setMaxconKMDConf = (limit) => { 26 | return new Promise((resolve, reject) => { 27 | fs.readFile(`${api.paths.kmdDataDir}/komodo.conf`, 'utf8', (err, data) => { 28 | const _maxconVal = limit ? 1 : 10; 29 | 30 | if (err) { 31 | api.log(`error reading ${api.paths.kmdDataDir}/komodo.conf`, 'native.confd'); 32 | resolve(false); 33 | } else { 34 | if (data.indexOf('maxconnections=') > -1) { 35 | const _maxcon = data.match(/maxconnections=\s*(.*)/); 36 | 37 | data = data.replace(`maxconnections=${_maxcon[1]}`, `maxconnections=${_maxconVal}`); 38 | } else { 39 | data = `${data}\nmaxconnections=${_maxconVal}\n`; 40 | } 41 | 42 | fs.writeFile(`${api.paths.kmdDataDir}/komodo.conf`, data, (err) => { 43 | if (err) { 44 | api.log(`error writing ${api.paths.kmdDataDir}/komodo.conf maxconnections=${_maxconVal}`, 'native.confd'); 45 | resolve(false); 46 | } else { 47 | api.log(`kmd conf maxconnections is set to ${_maxconVal}`, 'native.confd'); 48 | resolve(true); 49 | } 50 | }); 51 | } 52 | }); 53 | }); 54 | } 55 | 56 | return api; 57 | }; -------------------------------------------------------------------------------- /routes/api/plugin/stop.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.stopPlugin = async (app_id, window_id, builtin, data) => { 3 | try { 4 | let plugin; 5 | let pluginWindow; 6 | let onComplete; 7 | const category = builtin ? "builtin" : "registry" 8 | 9 | try { 10 | plugin = await api.getPlugin(app_id, builtin) 11 | } catch(e) { 12 | api.log("failed to get plugin info for plugin with id " + app_id, "stopPlugin") 13 | throw e 14 | } 15 | 16 | try { 17 | pluginWindow = api.pluginWindows[category][app_id][window_id] 18 | 19 | if (!pluginWindow) throw new Error(`plugin (id: ${app_id}) is not running with window (id: ${window_id})`) 20 | } catch(e) { 21 | api.log(`plugin (id: ${app_id}) is not running with window (id: ${window_id})`, "stopPlugin") 22 | throw new Error(`plugin (id: ${app_id}) is not running with window (id: ${window_id})`) 23 | } 24 | 25 | try { 26 | onComplete = api.pluginOnCompletes[category][app_id][window_id] 27 | } catch(e) {} 28 | 29 | if (onComplete != null) { 30 | try { 31 | await onComplete(data) 32 | } catch(e) { 33 | api.log(`plugin (id: ${app_id}) onComplete failed to execute, closing anyway...`, "stopPlugin") 34 | api.log(e, "stopPlugin") 35 | } 36 | } 37 | 38 | pluginWindow.close() 39 | return; 40 | } catch(e) { 41 | api.log(`Error stopping plugin with id ${app_id}.`, 'stopPlugin') 42 | api.log(e, 'stopPlugin') 43 | throw e 44 | } 45 | } 46 | 47 | api.setPost('/plugin/close', async (req, res, next) => { 48 | const { app_id, window_id, builtin, data } = req.body 49 | 50 | try { 51 | const retObj = { 52 | msg: 'success', 53 | result: await api.stopPlugin(app_id, window_id, builtin, data), 54 | }; 55 | 56 | res.send(JSON.stringify(retObj)); 57 | } catch (e) { 58 | const retObj = { 59 | msg: 'error', 60 | result: e.message, 61 | }; 62 | 63 | res.send(JSON.stringify(retObj)); 64 | } 65 | }); 66 | 67 | return api; 68 | }; -------------------------------------------------------------------------------- /routes/api/eth/transactions.js: -------------------------------------------------------------------------------- 1 | const standardizeEthTxObj = require('../utils/standardization/standardizeEthTxObj'); 2 | 3 | module.exports = (api) => { 4 | api.setGet('/eth/get_transactions', async (req, res, next) => { 5 | try { 6 | res.send(JSON.stringify({ 7 | msg: 'success', 8 | result: await api.eth.get_standardized_wallet_transactions(), 9 | })); 10 | } catch(e) { 11 | res.send(JSON.stringify({ 12 | msg: 'error', 13 | result: e.message, 14 | })); 15 | } 16 | }); 17 | 18 | api.eth.get_transactions = async (address) => { 19 | if (api.eth.interface != null) { 20 | let txs = await api.eth.interface.EtherscanProvider.getHistory(address) 21 | 22 | Object.values(api.eth.temp.pending_txs).forEach(pendingTx => { 23 | if (!(txs.some(tx => tx.hash === pendingTx.hash))) { 24 | txs.unshift(pendingTx) 25 | } else delete api.eth.temp.pending_txs[pendingTx.hash] 26 | }) 27 | 28 | return txs 29 | } else { 30 | throw new Error("Cannot get transaction list for inactive coin ETH") 31 | } 32 | }; 33 | 34 | api.eth.get_standardized_wallet_transactions = async () => { 35 | if (api.eth.wallet != null) { 36 | return standardizeEthTxObj( 37 | await api.eth.get_transactions(api.eth.wallet.address), 38 | api.eth.wallet.address 39 | ); 40 | } else { 41 | throw new Error("No wallet authenticated, cannot get wallet transactions for ETH") 42 | } 43 | } 44 | 45 | api.eth.get_transaction = async (txid) => { 46 | if (api.eth.interface != null) { 47 | // let cachedReceipts = api.eth.cache.tx_cache; 48 | 49 | // if (cachedReceipts[txid] != null) { 50 | // return cachedReceipts[txid] 51 | // } 52 | 53 | const txReceipt = await api.eth.interface.DefaultProvider.getTransactionReceipt(txid) 54 | 55 | // if (txReceipt.confirmations >= 100) { 56 | // api.eth.cache.tx_cache[txid] = txReceipt 57 | // } 58 | 59 | return txReceipt 60 | } else { 61 | throw new Error("Cannot get transaction for inactive coin ETH") 62 | } 63 | } 64 | 65 | return api; 66 | }; -------------------------------------------------------------------------------- /routes/api/electrum/proxy.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = (api) => { 3 | api.proxyActiveCoin = {}; 4 | 5 | api.proxy = (network) => { 6 | if (network) { 7 | api.proxyActiveCoin = network; 8 | } 9 | 10 | return { 11 | connect: () => { 12 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 13 | }, 14 | close: () => { 15 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 16 | }, 17 | blockchainAddressGetBalance: (address) => { 18 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 19 | }, 20 | blockchainAddressListunspent: (address) => { 21 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 22 | }, 23 | blockchainAddressGetHistory: (address) => { 24 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 25 | }, 26 | blockchainEstimatefee: (blocks) => { 27 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 28 | }, 29 | blockchainBlockGetHeader: (height) => { 30 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 31 | }, 32 | blockchainHeadersSubscribe: () => { 33 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 34 | }, 35 | blockchainTransactionGet: (txid) => { 36 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 37 | }, 38 | blockchainTransactionGetMerkle: (txid, height) => { 39 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 40 | }, 41 | serverVersion: () => { 42 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 43 | }, 44 | blockchainTransactionBroadcast: (rawtx) => { 45 | return new Promise((resolve, reject) => reject("Using electrum proxy servers is deprecated.")); 46 | }, 47 | }; 48 | }; 49 | 50 | return api; 51 | } -------------------------------------------------------------------------------- /routes/api/utils/web3/web3Interface.js: -------------------------------------------------------------------------------- 1 | const ethers = require('ethers'); 2 | const { HistorySupportingEtherscanProvider } = require('./etherscan'); 3 | const { DEFAULT_ERC20_ABI } = require('./abi'); 4 | 5 | class Web3Interface { 6 | constructor(network, apiKeys) { 7 | this.network = network; 8 | this.keys = apiKeys; 9 | 10 | this.DefaultProvider = new ethers.getDefaultProvider( 11 | this.network.key, 12 | { 13 | etherscan: apiKeys.etherscan, 14 | infura: apiKeys.infura, 15 | exclusive: [ "etherscan", "infura" ] 16 | } 17 | ); 18 | 19 | this.EtherscanProvider = new HistorySupportingEtherscanProvider( 20 | this.network.key, 21 | apiKeys.etherscan 22 | ); 23 | 24 | this.InfuraProvider = new ethers.InfuraProvider( 25 | this.network.key, 26 | apiKeys.infura 27 | ); 28 | } 29 | 30 | static decodeWeb3Error(errorString) { 31 | try { 32 | let errorJsonString = "{"; 33 | let index = errorString.indexOf("error={") + 7; 34 | let openers = 1; 35 | let closers = 0; 36 | 37 | while (openers != closers && index < errorString.length) { 38 | errorJsonString = errorJsonString + errorString[index]; 39 | 40 | if (errorString[index] === "{") openers++; 41 | else if (errorString[index] === "}") closers++; 42 | 43 | index++; 44 | } 45 | 46 | const firstJson = JSON.parse(errorJsonString) 47 | const secondJson = JSON.parse(firstJson.body != null ? firstJson.body : firstJson.result) 48 | const errorMessage = secondJson.error != null ? secondJson.error.message : secondJson.result 49 | 50 | return { 51 | unparsed: errorString, 52 | message: errorMessage.charAt(0).toUpperCase() + errorMessage.slice(1), 53 | }; 54 | } catch (e) { 55 | return { 56 | unparsed: errorString, 57 | message: "Unknown error", 58 | }; 59 | } 60 | } 61 | 62 | initContract = async (contractAddress) => { 63 | return [contractAddress, DEFAULT_ERC20_ABI]; 64 | }; 65 | 66 | getContract = (contractAddress, abi) => { 67 | return new ethers.Contract(contractAddress, abi, this.DefaultProvider); 68 | }; 69 | 70 | getInfo = () => { 71 | return { 72 | network: this.network, 73 | }; 74 | }; 75 | } 76 | 77 | module.exports = Web3Interface -------------------------------------------------------------------------------- /routes/api/native/reservetransfers.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.getreservetransfers = async (chainTicker) => { 3 | try { 4 | const z_operations = await api.native.callDaemon(chainTicker, 'z_getoperationstatus', []) 5 | let transfers = [] 6 | 7 | for (const z_operation of z_operations) { 8 | if ( 9 | z_operation.method === "sendcurrency" && 10 | (z_operation.params[0].convertto != null || z_operation.params[0].exportto != null) 11 | ) { 12 | let from = []; 13 | let to = []; 14 | let via = []; 15 | 16 | for (const param of z_operation.params) { 17 | const ownCurrency = await api.native.callDaemon(chainTicker, "getcurrency", [param.currency]) 18 | 19 | from.push(ownCurrency); 20 | to.push( 21 | param.convertto != null 22 | ? await api.native.callDaemon(chainTicker, "getcurrency", [param.convertto]) 23 | : ownCurrency 24 | ); 25 | via.push( 26 | param.via 27 | ? await api.native.callDaemon(chainTicker, "getcurrency", [param.via]) 28 | : null 29 | ); 30 | } 31 | 32 | let tx = null; 33 | 34 | try { 35 | if (z_operation.result.txid) { 36 | tx = await api.native.callDaemon(chainTicker, "getrawtransaction", [ 37 | z_operation.result.txid, 38 | 1, 39 | ]); 40 | } 41 | } catch (e) {} 42 | 43 | transfers.push({ 44 | from, 45 | to, 46 | via, 47 | tx, 48 | operation: z_operation, 49 | }); 50 | } 51 | } 52 | 53 | return transfers 54 | } catch(e) { 55 | throw e 56 | } 57 | } 58 | 59 | api.setPost('/native/get_reserve_transfers', async (req, res, next) => { 60 | const { 61 | chainTicker 62 | } = req.body; 63 | 64 | try { 65 | res.send(JSON.stringify({ 66 | msg: "success", 67 | result: await api.native.getreservetransfers(chainTicker) 68 | })); 69 | } catch (e) { 70 | res.send(JSON.stringify({ 71 | msg: "error", 72 | result: e.message 73 | })); 74 | } 75 | }); 76 | 77 | return api; 78 | }; -------------------------------------------------------------------------------- /routes/api/native/restart.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.native.restartCoin = async (chainTicker, launchConfig, startupOptions) => { 3 | if (!api.coinsInitializing[chainTicker]) { 4 | api.log('initiating restart for ' + chainTicker, 'restartCoin') 5 | api.coinsInitializing[chainTicker] = true 6 | 7 | await api.quitDaemon(chainTicker === 'KMD' ? 'komodod' : chainTicker, 30000) 8 | 9 | return new Promise((resolve, reject) => { 10 | let tries = 0 11 | 12 | const intervalId = setInterval(async () => { 13 | api.log('checking if ' + launchConfig.daemon + " process has finished", 'restartCoin') 14 | 15 | const resolveInterval = async () => { 16 | clearInterval(intervalId) 17 | try { 18 | delete api.native.launchConfigs[chainTicker] 19 | api.native.launchConfigs[chainTicker] = launchConfig 20 | 21 | resolve(await api.native.addCoin(chainTicker, launchConfig, startupOptions)) 22 | } catch(e) { 23 | reject(e) 24 | } 25 | } 26 | 27 | if (!(await api.isDaemonRunning(launchConfig.daemon))) { 28 | api.log(`${launchConfig.daemon} no longer running, starting ${launchConfig.daemon}`, 'restartCoin') 29 | await resolveInterval() 30 | } else if (tries >= 20) { 31 | api.log(`${tries * 2} seconds have passed, trying to launch daemon anyways`, 'restartCoin') 32 | await resolveInterval() 33 | } else tries++ 34 | }, 1000) 35 | }) 36 | } else { 37 | api.log('cannot restart ' + chainTicker + ' while it is being initialized', 'restartCoin') 38 | return Promise.reject(new Error(`Cannot restart ${chainTicker} daemon while it is being initialized`)) 39 | } 40 | } 41 | 42 | api.setPost('/native/coins/restart', (req, res) => { 43 | const { chainTicker, launchConfig, startupOptions } = req.body 44 | 45 | api.native.restartCoin(chainTicker, launchConfig, startupOptions) 46 | .then(result => { 47 | res.send(JSON.stringify({ 48 | msg: 'success', 49 | result, 50 | })); 51 | }) 52 | .catch(e => { 53 | const retObj = { 54 | msg: "error", 55 | result: e.message, 56 | }; 57 | 58 | res.send(JSON.stringify(retObj)); 59 | }) 60 | }); 61 | 62 | return api; 63 | }; -------------------------------------------------------------------------------- /routes/api/utility_apis/csvExport.js: -------------------------------------------------------------------------------- 1 | 2 | const createCsvWriter = require('csv-writer').createObjectCsvWriter; 3 | const { dialog } = require('electron') 4 | const path = require('path'); 5 | 6 | module.exports = (api) => { 7 | /** 8 | * Takes in formatted transactions, and saves the 9 | * transaction csv to a folder chosen by the user 10 | * @param {Object[]} transactions Array of {type, amount, fee, date, address, confirmations, affected_balance, txid, coin} 11 | */ 12 | api.saveTransactionCsv = async (transactions) => { 13 | const res = await dialog.showOpenDialog({ properties: ['openDirectory'] }) 14 | 15 | if (res.canceled) { 16 | return 17 | } else { 18 | const csvPath = path.join(res.filePaths[0], `tx_export_${new Date().getTime()}.csv`); 19 | 20 | try { 21 | const csvWriter = createCsvWriter({ 22 | path: csvPath, 23 | header: [ 24 | {id: 'type', title: 'Type'}, 25 | {id: 'amount', title: 'Amount'}, 26 | {id: 'fee', title: 'Fee'}, 27 | {id: 'date', title: 'Date'}, 28 | {id: 'address', title: 'Address'}, 29 | {id: 'confirmations', title: 'Confirmations'}, 30 | {id: 'affected_balance', title: 'Balance'}, 31 | {id: 'txid', title: 'TxID'}, 32 | {id: 'coin', title: 'Coin'} 33 | ] 34 | }); 35 | 36 | await csvWriter.writeRecords(transactions) 37 | 38 | dialog.showMessageBox({ 39 | title: "Success!", 40 | message: "CSV file saved to " + csvPath, 41 | buttons: ["OK"], 42 | }) 43 | } catch (e) { 44 | dialog.showMessageBox({ 45 | type: "error", 46 | title: "Error", 47 | message: "Error saving CSV file to " + csvPath, 48 | buttons: ["OK"], 49 | }) 50 | 51 | throw e 52 | } 53 | } 54 | } 55 | 56 | api.setPost('/export_transaction_csv', async (req, res, next) => { 57 | const { transactions } = req.body 58 | 59 | try { 60 | const retObj = { 61 | msg: 'success', 62 | result: await api.saveTransactionCsv(transactions), 63 | }; 64 | 65 | res.send(JSON.stringify(retObj)); 66 | } catch (e) { 67 | const retObj = { 68 | msg: 'error', 69 | result: e.message, 70 | }; 71 | 72 | res.send(JSON.stringify(retObj)); 73 | } 74 | }); 75 | 76 | return api; 77 | }; -------------------------------------------------------------------------------- /assets/deps/confs/DOGE_peers.txt: -------------------------------------------------------------------------------- 1 | 144.76.71.141 2 | 63.231.239.212 3 | 76.178.149.124 4 | 50.168.159.133 5 | 85.172.79.190 6 | 109.239.49.207 7 | 23.92.25.116 8 | 104.236.136.96 9 | 83.163.222.19 10 | 47.88.34.118 11 | 85.24.244.205 12 | 104.222.120.12 13 | 109.233.58.55 14 | 1.32.70.66 15 | 125.205.136.247 16 | 52.23.175.47 17 | 188.0.80.142 18 | 189.27.147.140 19 | 211.149.148.151 20 | 179.185.112.222 21 | 81.5.71.115 22 | 62.76.15.208 23 | 204.91.28.100 24 | 84.18.118.27 25 | 198.27.81.24 26 | 52.76.154.206 27 | 52.69.7.50 28 | 52.192.155.175 29 | 82.24.81.133 30 | 5.100.250.140 31 | 114.55.5.204 32 | 31.179.43.191 33 | 194.135.90.38 34 | 198.50.242.34 35 | 176.9.31.178 36 | 85.25.41.70 37 | 123.57.60.66 38 | 5.196.82.175 39 | 148.251.88.245 40 | 163.172.19.96 41 | 192.30.138.66 42 | 72.207.111.81 43 | 98.115.147.74 44 | 174.50.64.101 45 | 159.203.107.139 46 | 50.191.229.7 47 | 220.135.22.146 48 | 120.55.80.212 49 | 157.161.128.62 50 | 96.48.162.59 51 | 73.253.240.20 52 | 149.210.242.48 53 | 71.181.42.73 54 | 178.32.9.103 55 | 107.170.82.106 56 | 210.28.136.11 57 | 82.78.191.165 58 | 96.126.123.143 59 | 23.239.31.246 60 | 176.9.50.227 61 | 101.200.156.61 62 | 31.41.40.25 63 | 94.254.62.188 64 | 107.170.86.160 65 | 203.74.121.63 66 | 121.40.17.150 67 | 79.109.198.106 68 | 192.95.56.199 69 | 172.249.137.148 70 | 24.249.152.169 71 | 95.174.187.112 72 | 146.0.32.101 73 | 67.171.207.32 74 | 76.185.84.244 75 | 108.241.66.106 76 | 31.184.195.115 77 | 176.9.113.75 78 | 178.63.18.3 79 | 73.225.31.99 80 | 139.196.9.71 81 | 173.28.134.245 82 | 192.95.29.153 83 | 182.92.183.58 84 | 173.236.240.49 85 | 142.217.48.137 86 | 192.99.11.57 87 | 198.23.230.253 88 | 85.243.255.154 89 | 87.189.43.165 90 | 54.201.183.106 91 | 84.230.4.177 92 | 220.240.96.156 93 | 111.201.159.247 94 | 78.84.100.95 95 | 71.207.13.6 96 | 84.253.125.186 97 | 180.229.32.149 98 | 121.42.206.214 99 | 213.65.111.18 100 | 65.13.189.227 101 | 98.127.32.237 102 | 65.28.164.248 103 | 71.236.237.133 104 | 24.22.225.211 105 | 86.21.9.55 106 | 144.76.239.66 107 | 85.25.200.102 108 | 92.255.199.98 109 | 67.170.74.103 110 | 98.162.199.30 111 | 145.131.3.54 112 | 81.7.3.24 113 | 77.201.157.202 114 | 104.131.40.196 115 | 70.79.168.92 116 | 71.80.233.61 117 | 78.102.123.56 118 | 120.146.143.87 119 | 174.115.20.94 120 | 24.255.204.177 121 | 69.145.193.96 122 | 80.68.90.161 123 | 24.121.141.96 124 | 176.9.65.41 125 | 173.63.255.25 126 | 69.42.223.118 127 | 91.83.69.247 128 | -------------------------------------------------------------------------------- /routes/api/utils/cache.js: -------------------------------------------------------------------------------- 1 | const NodeCache = require("node-cache"); 2 | 3 | class LFUCache { 4 | constructor(maxBytes, cacheOptions = {}, logger = (request, params) => {}) { 5 | this.cacheOptions = cacheOptions 6 | this.cache = new NodeCache(cacheOptions); 7 | this.frequencyMap = {} 8 | this.maxBytes = maxBytes 9 | this.logger = logger 10 | } 11 | 12 | del(key) { 13 | this.logger("DEL", { key }) 14 | 15 | delete this.frequencyMap[key] 16 | return this.cache.del(key) 17 | } 18 | 19 | canHoldValue(key, value) { 20 | const testCache = new NodeCache(this.cacheOptions) 21 | let returnVal = false 22 | 23 | try { 24 | testCache.set(key, value) 25 | const stats = testCache.getStats() 26 | 27 | if ((stats.vsize + stats.ksize) <= this.maxBytes) { 28 | returnVal = true 29 | } 30 | } catch(e) {} 31 | 32 | testCache.flushAll() 33 | return returnVal 34 | } 35 | 36 | set(key, value) { 37 | this.logger("SET", { key, value }) 38 | 39 | if (this.canHoldValue(key, value)) { 40 | this.frequencyMap[key] = 0 41 | const result = this.cache.set(key, value) 42 | let stats = this.cache.getStats() 43 | 44 | if ((stats.vsize + stats.ksize) > this.maxBytes) { 45 | let keys = Object.keys(this.frequencyMap).sort((a, b) => { 46 | if (a == key) return 1 47 | else if (b == key) return -1 48 | else return this.frequencyMap[a] - this.frequencyMap[b] 49 | }) 50 | 51 | for (const toDelete of keys) { 52 | this.del(toDelete) 53 | stats = this.cache.getStats() 54 | 55 | if ((stats.vsize + stats.ksize) <= this.maxBytes) break; 56 | } 57 | } 58 | 59 | return result 60 | } else { 61 | throw new Error("Cannot set key value pair for provided data") 62 | } 63 | } 64 | 65 | get(key) { 66 | this.logger("GET", { key }) 67 | 68 | const value = this.cache.get(key) 69 | 70 | if (value != null && this.frequencyMap[key] != null) { 71 | this.frequencyMap[key] = this.frequencyMap[key] + 1 72 | } else this.frequencyMap[key] = 1 73 | 74 | return this.cache.get(key) 75 | } 76 | 77 | has(key) { 78 | this.logger("HAS", { key }) 79 | 80 | return this.cache.has(key) 81 | } 82 | 83 | keys() { 84 | this.logger("KEYS") 85 | 86 | return this.cache.keys() 87 | } 88 | 89 | getStats() { 90 | return this.cache.getStats() 91 | } 92 | } 93 | 94 | module.exports = LFUCache -------------------------------------------------------------------------------- /routes/api/erc20/transactions.js: -------------------------------------------------------------------------------- 1 | const standardizeEthTxObj = require('../utils/standardization/standardizeEthTxObj'); 2 | 3 | module.exports = (api) => { 4 | api.setGet('/erc20/get_transactions', async (req, res, next) => { 5 | try { 6 | res.send( 7 | JSON.stringify({ 8 | msg: "success", 9 | result: await api.erc20.get_standardized_wallet_transactions( 10 | req.query.chainTicker 11 | ), 12 | }) 13 | ); 14 | } catch(e) { 15 | res.send(JSON.stringify({ 16 | msg: 'error', 17 | result: e.message, 18 | })); 19 | } 20 | }); 21 | 22 | api.erc20.get_transactions = async (contractId, address) => { 23 | if (api.erc20.contracts[contractId] != null) { 24 | let txs = await api.erc20.contracts[ 25 | contractId 26 | ].interface.EtherscanProvider.getHistory( 27 | address, 28 | null, 29 | null, 30 | contractId 31 | ); 32 | 33 | Object.values(api.erc20.contracts[contractId].temp.pending_txs).forEach(pendingTx => { 34 | if (!(txs.some(tx => tx.hash === pendingTx.hash))) { 35 | txs.unshift(pendingTx) 36 | } else delete api.erc20.contracts[contractId].temp.pending_txs[pendingTx.hash] 37 | }) 38 | 39 | return txs 40 | } else { 41 | throw new Error(`Cannot get transaction list for inactive coin ${contractId}`) 42 | } 43 | }; 44 | 45 | api.erc20.get_standardized_wallet_transactions = async (contractId) => { 46 | if (api.erc20.contracts[contractId] != null) { 47 | if (api.erc20.wallet != null) { 48 | return standardizeEthTxObj( 49 | await api.erc20.get_transactions(contractId, api.erc20.wallet.address), 50 | api.erc20.wallet.address, 51 | api.erc20.contracts[contractId].decimals 52 | ); 53 | } else { 54 | throw new Error( 55 | `No wallet authenticated, cannot get wallet transactions for ${contractId}` 56 | ); 57 | } 58 | } else { 59 | throw new Error( 60 | `Cannot get transaction list for inactive coin ${contractId}` 61 | ); 62 | } 63 | }; 64 | 65 | api.erc20.get_transaction = async (contractId, txid) => { 66 | if (api.erc20.contracts[contractId] != null) { 67 | const txReceipt = await api.erc20.contracts[ 68 | contractId 69 | ].interface.DefaultProvider.getTransactionReceipt(txid); 70 | 71 | return txReceipt 72 | } else { 73 | throw new Error(`Cannot get transaction for inactive coin ${contractId}`) 74 | } 75 | } 76 | 77 | return api; 78 | }; -------------------------------------------------------------------------------- /routes/api/native/mininginfo.js: -------------------------------------------------------------------------------- 1 | const { standardizeMiningInfo } = require('../utils/standardization/standardization') 2 | 3 | module.exports = (api) => { 4 | api.native.get_mininginfo = (coin, includeBridgekeeper) => { 5 | return new Promise((resolve, reject) => { 6 | api.native.callDaemon(coin, 'getmininginfo', []) 7 | .then(async (mininginfo) => { 8 | try { 9 | // If mergemining with parent, set hashrate = parent hashrate 10 | if (mininginfo.mergemining != null && mininginfo.mergemining > 0) { 11 | const currentCurrency = await api.native.callDaemon(coin, 'getcurrency', [coin]) 12 | 13 | if ( 14 | currentCurrency.currencyid !== currentCurrency.parent && 15 | currentCurrency.parent != null 16 | ) { 17 | const parentCurrency = await api.native.callDaemon(coin, "getcurrency", [ 18 | currentCurrency.parent, 19 | ]); 20 | const parentMiningInfo = await api.native.callDaemon( 21 | parentCurrency.name, 22 | "getmininginfo", 23 | [] 24 | ); 25 | 26 | if (parentMiningInfo.localhashps > 0) { 27 | mininginfo.localhashps = parentMiningInfo.localhashps; 28 | } 29 | } 30 | } 31 | } catch(e) { 32 | api.log("Could not process mergemining hashrate") 33 | api.log(e, 'get_mininginfo') 34 | } 35 | let retval = standardizeMiningInfo(mininginfo) 36 | if (includeBridgekeeper) { 37 | const bridgeKeeperStatus = await api.native.bridgekeeper_status(coin) 38 | if (bridgeKeeperStatus) { 39 | retval.bridgekeeperstatus = bridgeKeeperStatus; 40 | } 41 | } 42 | resolve(retval) 43 | }) 44 | .catch(err => { 45 | reject(err) 46 | }) 47 | }); 48 | }; 49 | 50 | api.setPost('/native/get_mininginfo', (req, res, next) => { 51 | const coin = req.body.chainTicker; 52 | const includeBridgekeeper = req.body?.includeBridgekeeper; 53 | api.native.get_mininginfo(coin, includeBridgekeeper) 54 | .then((mininginfo) => { 55 | const retObj = { 56 | msg: 'success', 57 | result: mininginfo, 58 | }; 59 | 60 | res.send(JSON.stringify(retObj)); 61 | }) 62 | .catch(error => { 63 | const retObj = { 64 | msg: 'error', 65 | result: error.message, 66 | }; 67 | 68 | res.send(JSON.stringify(retObj)); 69 | }) 70 | }); 71 | 72 | return api; 73 | }; -------------------------------------------------------------------------------- /routes/api/erc20/coins.js: -------------------------------------------------------------------------------- 1 | const { ETH_HOMESTEAD } = require('../utils/constants/eth_networks'); 2 | const { CONTRACT_SYMBOLS } = require('../utils/constants/web3'); 3 | const createInterface = require('../utils/web3/provider'); 4 | 5 | module.exports = (api) => { 6 | api.setPost('/erc20/coins/activate', async (req, res, next) => { 7 | // chainTicker represents contract ID 8 | const { chainTicker, network } = req.body; 9 | 10 | try { 11 | if (chainTicker) { 12 | if (api.erc20.contracts[chainTicker] == null) { 13 | const interface = createInterface( 14 | network == null ? ETH_HOMESTEAD : network 15 | ); 16 | const contractData = await interface.initContract(chainTicker) 17 | 18 | const contract = interface.getContract(...contractData) 19 | 20 | let symbol 21 | 22 | if (CONTRACT_SYMBOLS[chainTicker.toLowerCase()]) { 23 | symbol = CONTRACT_SYMBOLS[chainTicker.toLowerCase()] 24 | } else if (contract.symbol) { 25 | try { 26 | symbol = await contract.symbol(); 27 | } catch(e) { 28 | symbol = chainTicker 29 | } 30 | } else { 31 | symbol = chainTicker 32 | } 33 | 34 | api.erc20.contracts[chainTicker] = { 35 | interface, 36 | contract, 37 | temp: { 38 | pending_txs: {} 39 | }, 40 | decimals: 41 | contract.decimals != null 42 | ? Number(await contract.decimals()) 43 | : 18, 44 | symbol 45 | }; 46 | 47 | const retObj = { 48 | msg: 'success', 49 | result: 'true', 50 | }; 51 | res.send(JSON.stringify(retObj)); 52 | } else { 53 | const retObj = { 54 | msg: 'error', 55 | result: `${chainTicker} already active!`, 56 | }; 57 | res.send(JSON.stringify(retObj)); 58 | } 59 | } else { 60 | const retObj = { 61 | msg: 'error', 62 | result: 'no contract id provided to activate', 63 | }; 64 | res.send(JSON.stringify(retObj)); 65 | } 66 | } catch(e) { 67 | const retObj = { 68 | msg: 'error', 69 | result: e.message, 70 | }; 71 | res.send(JSON.stringify(retObj)); 72 | } 73 | }); 74 | 75 | api.setPost('/erc20/remove_coin', (req, res) => { 76 | api.erc20.contracts[req.body.chainTicker] = null 77 | 78 | const retObj = { 79 | msg: 'success', 80 | result: true, 81 | }; 82 | 83 | res.send(JSON.stringify(retObj)); 84 | }); 85 | 86 | return api; 87 | }; -------------------------------------------------------------------------------- /routes/api/binsUtils.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | const fsnode = require('fs'); 3 | const _fs = require('graceful-fs'); 4 | const { DAEMON_NAMES } = require('./utils/constants'); 5 | const exec = require('child_process').exec; 6 | 7 | module.exports = (api) => { 8 | api.killRogueProcess = (processName) => { 9 | // kill rogue process copies on start 10 | const osPlatform = os.platform(); 11 | let processGrep; 12 | 13 | switch (osPlatform) { 14 | case 'darwin': 15 | processGrep = "ps -p $(ps -A | grep -m1 " + processName + " | awk '{print $1}') | grep -i " + processName; 16 | break; 17 | case 'linux': 18 | processGrep = 'ps -p $(pidof ' + processName + ') | grep -i ' + processName; 19 | break; 20 | case 'win32': 21 | processGrep = 'tasklist'; 22 | break; 23 | } 24 | 25 | exec(processGrep, (error, stdout, stderr) => { 26 | if (stdout.indexOf(processName) > -1) { 27 | const pkillCmd = osPlatform === 'win32' ? `taskkill /f /im ${processName}.exe` : `pkill -15 ${processName}`; 28 | 29 | api.log(`found another ${processName} process(es)`, 'native.process'); 30 | 31 | exec(pkillCmd, (error, stdout, stderr) => { 32 | api.log(`${pkillCmd} is issued`, 'native.process'); 33 | 34 | if (error !== null) { 35 | api.log(`${pkillCmd} exec error: ${error}`, 'native.process'); 36 | }; 37 | }); 38 | } 39 | 40 | if (error !== null) { 41 | api.log(`${processGrep} exec error: ${error}`, 'native.process'); 42 | }; 43 | }); 44 | } 45 | 46 | api.isDaemonRunning = (daemonName) => { 47 | return new Promise((resolve, reject) => { 48 | let platform = os.platform(); 49 | let cmd = ''; 50 | switch (platform) { 51 | case 'win32' : cmd = `tasklist`; break; 52 | case 'darwin' : cmd = `ps -ax | grep ${daemonName}`; break; 53 | case 'linux' : cmd = `ps -A`; break; 54 | default: break; 55 | } 56 | 57 | exec(cmd, (err, stdout, stderr) => { 58 | if (platform === 'darwin') { 59 | resolve(stdout.toLowerCase().indexOf(`assets/bin/osx/${daemonName}`) > -1) 60 | } else { 61 | resolve(stdout.toLowerCase().indexOf(daemonName.toLowerCase()) > -1) 62 | } 63 | }); 64 | }) 65 | } 66 | 67 | api.isAnyDaemonRunning = async () => { 68 | for (const daemon of DAEMON_NAMES) { 69 | if (await api.isDaemonRunning(daemon)) { 70 | api.log(`${daemon} is currently running...`, 'native.process'); 71 | return true; 72 | } else { 73 | api.log(`${daemon} is not currently running...`, 'native.process'); 74 | } 75 | } 76 | } 77 | 78 | return api; 79 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### This is experimental and unfinished software. Use at your own risk! No warranty for any kind of damage! 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | 9 | # Verus Wallet 10 | The Verus Multicoin Wallet and Ecosystem GUI 11 | 12 | ## Build & Installation 13 | 14 | #### Prerequirements: 15 | 16 | 1) [Install yarn](https://yarnpkg.com/) 17 | 18 | 2) [Install git](https://git-scm.com/) 19 | 20 | 21 | #### Build & Start Verus-Desktop-GUI (frontend) 22 | 23 | ```shell 24 | git clone --recursive https://github.com/VerusCoin/Verus --branch master --single-branch 25 | cd Verus/gui/Verus-Desktop-GUI/react/ 26 | yarn install 27 | ``` 28 | Leave the above process running and use a new terminal windows/tab when proceeding with the below steps. 29 | 30 | Now please create a directory called `bin` inside `assets/` and afterwards copy `komodod` and `komodo-cli` to a new subfolder named after the operating system you are building Agama for: `linux64`, `osx` or `win64`. Inside this subfolder, create another directory called `verusd` 31 | and copy `verusd` and `verus-cli` into it. 32 | 33 | From within `Verus/` the structure will be `assets/bin/linux64` (for example on linux). 34 | 35 | 36 | #### Start Verus App (electron) 37 | 38 | ```shell 39 | cd Verus 40 | yarn install 41 | yarn start 42 | ``` 43 | To use debug/dev mode please stop the Verus App (electron) and either set `dev: true` and `debug: true` in `~/.verus/config.json` and then restart the app or replace step 3) from above with the start command below: 44 | 45 | ```shell 46 | yarn start devmode 47 | ``` 48 | 49 | You are ready to dev! 50 | 51 | 52 | ## Bundling & packaging: 53 | 54 | ```shell 55 | yarn run dist 56 | ``` 57 | We refer to the original [electron-builder](https://www.electron.build) website for more detailed information and further documentation. 58 | 59 | 60 | -------------------------------------------------------------------------------- /routes/shepherd/deepmerge.js: -------------------------------------------------------------------------------- 1 | // ref: https://davidwalsh.name/javascript-deep-merge 2 | const isMergeableObject = (val) => { 3 | const nonNullObject = val && typeof val === 'object'; 4 | 5 | return nonNullObject 6 | && Object.prototype.toString.call(val) !== '[object RegExp]' 7 | && Object.prototype.toString.call(val) !== '[object Date]'; 8 | } 9 | 10 | const emptyTarget = (val) => { 11 | return Array.isArray(val) ? [] : {}; 12 | } 13 | 14 | const cloneIfNecessary = (value, optionsArgument) => { 15 | const clone = optionsArgument && optionsArgument.clone === true; 16 | return (clone && isMergeableObject(value)) ? deepmerge(emptyTarget(value), value, optionsArgument) : value; 17 | } 18 | 19 | const defaultArrayMerge = (target, source, optionsArgument) => { 20 | let destination = target.slice(); 21 | 22 | source.forEach((e, i) => { 23 | if (typeof destination[i] === 'undefined') { 24 | destination[i] = cloneIfNecessary(e, optionsArgument); 25 | } else if (isMergeableObject(e)) { 26 | destination[i] = deepmerge(target[i], e, optionsArgument); 27 | } else if (target.indexOf(e) === -1) { 28 | destination.push(cloneIfNecessary(e, optionsArgument)); 29 | } 30 | }); 31 | 32 | return destination; 33 | } 34 | 35 | const mergeObject = (target, source, optionsArgument) => { 36 | let destination = {}; 37 | 38 | if (isMergeableObject(target)) { 39 | Object.keys(target).forEach((key) => { 40 | destination[key] = cloneIfNecessary(target[key], optionsArgument); 41 | }); 42 | } 43 | 44 | Object.keys(source).forEach((key) => { 45 | if (!isMergeableObject(source[key]) || 46 | !target[key]) { 47 | destination[key] = cloneIfNecessary(source[key], optionsArgument); 48 | } else { 49 | destination[key] = deepmerge(target[key], source[key], optionsArgument); 50 | } 51 | }); 52 | 53 | return destination; 54 | } 55 | 56 | let deepmerge = (target, source, optionsArgument) => { 57 | const array = Array.isArray(source); 58 | const options = optionsArgument || { arrayMerge: defaultArrayMerge }; 59 | const arrayMerge = options.arrayMerge || defaultArrayMerge; 60 | 61 | if (array) { 62 | return Array.isArray(target) ? arrayMerge(target, source, optionsArgument) : cloneIfNecessary(source, optionsArgument); 63 | } else { 64 | return mergeObject(target, source, optionsArgument); 65 | } 66 | } 67 | 68 | deepmerge.all = (array, optionsArgument) => { 69 | if (!Array.isArray(array) || 70 | array.length < 2) { 71 | throw new Error('first argument should be an array with at least two elements'); 72 | } 73 | 74 | // we are sure there are at least 2 values, so it is safe to have no initial value 75 | return array.reduce((prev, next) => { 76 | return deepmerge(prev, next, optionsArgument); 77 | }); 78 | } 79 | 80 | module.exports = deepmerge; -------------------------------------------------------------------------------- /routes/api/utils/objectUtil/deepmerge.js: -------------------------------------------------------------------------------- 1 | // ref: https://davidwalsh.name/javascript-deep-merge 2 | const isMergeableObject = (val) => { 3 | const nonNullObject = val && typeof val === 'object'; 4 | 5 | return nonNullObject 6 | && Object.prototype.toString.call(val) !== '[object RegExp]' 7 | && Object.prototype.toString.call(val) !== '[object Date]'; 8 | } 9 | 10 | const emptyTarget = (val) => { 11 | return Array.isArray(val) ? [] : {}; 12 | } 13 | 14 | const cloneIfNecessary = (value, optionsArgument) => { 15 | const clone = optionsArgument && optionsArgument.clone === true; 16 | return (clone && isMergeableObject(value)) ? deepmerge(emptyTarget(value), value, optionsArgument) : value; 17 | } 18 | 19 | const defaultArrayMerge = (target, source, optionsArgument) => { 20 | let destination = target.slice(); 21 | 22 | source.forEach((e, i) => { 23 | if (typeof destination[i] === 'undefined') { 24 | destination[i] = cloneIfNecessary(e, optionsArgument); 25 | } else if (isMergeableObject(e)) { 26 | destination[i] = deepmerge(target[i], e, optionsArgument); 27 | } else if (target.indexOf(e) === -1) { 28 | destination.push(cloneIfNecessary(e, optionsArgument)); 29 | } 30 | }); 31 | 32 | return destination; 33 | } 34 | 35 | const mergeObject = (target, source, optionsArgument) => { 36 | let destination = {}; 37 | 38 | if (isMergeableObject(target)) { 39 | Object.keys(target).forEach((key) => { 40 | destination[key] = cloneIfNecessary(target[key], optionsArgument); 41 | }); 42 | } 43 | 44 | Object.keys(source).forEach((key) => { 45 | if (!isMergeableObject(source[key]) || 46 | !target[key]) { 47 | destination[key] = cloneIfNecessary(source[key], optionsArgument); 48 | } else { 49 | destination[key] = deepmerge(target[key], source[key], optionsArgument); 50 | } 51 | }); 52 | 53 | return destination; 54 | } 55 | 56 | let deepmerge = (target, source, optionsArgument) => { 57 | const array = Array.isArray(source); 58 | const options = optionsArgument || { arrayMerge: defaultArrayMerge }; 59 | const arrayMerge = options.arrayMerge || defaultArrayMerge; 60 | 61 | if (array) { 62 | return Array.isArray(target) ? arrayMerge(target, source, optionsArgument) : cloneIfNecessary(source, optionsArgument); 63 | } else { 64 | return mergeObject(target, source, optionsArgument); 65 | } 66 | } 67 | 68 | deepmerge.all = (array, optionsArgument) => { 69 | if (!Array.isArray(array) || 70 | array.length < 2) { 71 | throw new Error('first argument should be an array with at least two elements'); 72 | } 73 | 74 | // we are sure there are at least 2 values, so it is safe to have no initial value 75 | return array.reduce((prev, next) => { 76 | return deepmerge(prev, next, optionsArgument); 77 | }); 78 | } 79 | 80 | module.exports = deepmerge; -------------------------------------------------------------------------------- /routes/api/native/getCurrency.js: -------------------------------------------------------------------------------- 1 | const { ROOT_SYSTEM_ID } = require("../utils/constants/dev_options"); 2 | 3 | module.exports = (api) => { 4 | // The only difference between this and get_currency is that this cannot 5 | // be used to derive non-static properties of a currency like bestcurrencystate 6 | api.native.get_currency_definition = async (chain, currencyid = ROOT_SYSTEM_ID) => { 7 | if (api.native.cache.currency_definition_cache.has(currencyid)) { 8 | return api.native.cache.currency_definition_cache.get(currencyid) 9 | } else { 10 | const definition = await api.native.callDaemon(chain, 'getcurrency', [currencyid]) 11 | let { name } = definition 12 | 13 | if ( 14 | definition.currencyid !== definition.systemid && 15 | definition.parent !== ROOT_SYSTEM_ID 16 | ) { 17 | name = `${name}.${ 18 | (await api.native.get_currency_definition(chain, definition.parent)) 19 | .name 20 | }`; 21 | } 22 | 23 | const processedDefinition = { 24 | ...definition, 25 | name, 26 | } 27 | 28 | api.native.cache.currency_definition_cache.set(currencyid, processedDefinition) 29 | return processedDefinition 30 | } 31 | } 32 | 33 | api.native.get_currency = async (chain, currencyid = ROOT_SYSTEM_ID) => { 34 | try { 35 | const currencyObject = await api.native.callDaemon(chain, 'getcurrency', [currencyid]) 36 | const parent = await api.native.get_currency_definition(chain, currencyObject.parent) 37 | const spotter = await api.native.get_currency_definition(chain, chain) 38 | 39 | const processedCurrencyObject = { 40 | ...currencyObject, 41 | systemname: parent.name.toUpperCase(), 42 | spottername: chain, 43 | spotterid: spotter.currencyid, 44 | name: 45 | (currencyObject.systemid !== currencyObject.currencyid && 46 | currencyObject.parent !== ROOT_SYSTEM_ID) 47 | ? `${currencyObject.name}.${parent.name}` 48 | : currencyObject.name, 49 | }; 50 | 51 | if (!api.native.cache.currency_definition_cache.has(currencyid)) { 52 | api.native.cache.currency_definition_cache.set(currencyid, processedCurrencyObject) 53 | } 54 | 55 | return processedCurrencyObject 56 | } catch(e) { 57 | throw e 58 | } 59 | }; 60 | 61 | api.setPost('/native/get_currency', async (req, res, next) => { 62 | const { chainTicker, name } = req.body 63 | 64 | try { 65 | const retObj = { 66 | msg: 'success', 67 | result: await api.native.get_currency(chainTicker, name), 68 | }; 69 | 70 | res.send(JSON.stringify(retObj)); 71 | } catch(e) { 72 | const retObj = { 73 | msg: 'error', 74 | result: e.message, 75 | }; 76 | 77 | res.send(JSON.stringify(retObj)); 78 | } 79 | }); 80 | 81 | return api; 82 | }; -------------------------------------------------------------------------------- /routes/api/native/shieldcoinbase.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | /** 3 | * Readies the parameters to pass to z_shieldcoinbase and returns 4 | * the inputted information for the user to double check it 5 | * @param {String} chainTicker The chainticker to call z_shieldcoinbase on 6 | * @param {String} toAddress The Z address to shield coinbases to 7 | * @param {String} fromAddress The from address, leave undefined to get all addresses 8 | * @param {Number} fee (Optional) A custom fee 9 | * @param {Number} limit (Optional) A custom limit of UTXOs to shield 10 | */ 11 | api.native.shieldCoinbasePreflight = ( 12 | chainTicker, 13 | toAddress, 14 | fromAddress, 15 | fee, 16 | limit 17 | ) => { 18 | const FROM_ADDR_INDEX = 0 19 | let inputParams = [fromAddress, toAddress, fee, limit] 20 | let txParams = [] 21 | 22 | inputParams.map((inputParam, index) => { 23 | if (index === FROM_ADDR_INDEX && inputParam === null) txParams.push("*") 24 | else if (inputParam != null) { 25 | txParams.push(inputParam) 26 | } 27 | }) 28 | 29 | return { 30 | chainTicker, 31 | fromAddress, 32 | toAddress, 33 | fee, 34 | limit, 35 | txParams 36 | }; 37 | }; 38 | 39 | api.setPost('/native/shieldcoinbase', (req, res, next) => { 40 | const { 41 | chainTicker, 42 | fromAddress, 43 | toAddress, 44 | fee, 45 | limit 46 | } = req.body; 47 | 48 | const preflightRes = api.native.shieldCoinbasePreflight( 49 | chainTicker, 50 | toAddress, 51 | fromAddress, 52 | fee, 53 | limit 54 | ) 55 | 56 | api.native.callDaemon(chainTicker, 'z_shieldcoinbase', preflightRes.txParams) 57 | .then(shieldObj => { 58 | const retObj = { 59 | msg: "success", 60 | result: { ...preflightRes, ...shieldObj } 61 | }; 62 | res.send(JSON.stringify(retObj)); 63 | }).catch(e => { 64 | const retObj = { 65 | msg: "error", 66 | result: e.message 67 | }; 68 | res.send(JSON.stringify(retObj)); 69 | }) 70 | }); 71 | 72 | api.setPost("/native/shieldcoinbase_preflight", (req, res, next) => { 73 | const { 74 | chainTicker, 75 | fromAddress, 76 | toAddress, 77 | fee, 78 | limit 79 | } = req.body; 80 | 81 | try { 82 | res.send( 83 | JSON.stringify({ 84 | msg: "success", 85 | result: api.native.shieldCoinbasePreflight( 86 | chainTicker, 87 | toAddress, 88 | fromAddress, 89 | fee, 90 | limit 91 | ) 92 | }) 93 | ); 94 | } catch (e) { 95 | const retObj = { 96 | msg: "error", 97 | result: e.message 98 | }; 99 | res.send(JSON.stringify(retObj)); 100 | } 101 | }); 102 | 103 | return api; 104 | }; -------------------------------------------------------------------------------- /routes/api/utils/rpc/rpcStatusCodes.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Non BTC default errors 3 | RPC_OK : 0, 4 | RPC_TIMEOUT : -32, 5 | RPC_WORK_QUEUE_DEPTH_EXCEEDED : -33, 6 | RPC_ERROR_UNKNOWN : -34, 7 | RPC_PARSE_ERROR : -35, 8 | 9 | RPC_MISC_ERROR : -1, //!< std::exception thrown in command handling 10 | RPC_FORBIDDEN_BY_SAFE_MODE : -2, //!< Server is in safe mode, and command is not allowed in safe mode 11 | RPC_TYPE_ERROR : -3, //!< Unexpected type was passed as parameter 12 | RPC_INVALID_ADDRESS_OR_KEY : -5, //!< Invalid address or key 13 | RPC_OUT_OF_MEMORY : -7, //!< Ran out of memory during operation 14 | RPC_INVALID_PARAMETER : -8, //!< Invalid, missing or duplicate parameter 15 | RPC_DATABASE_ERROR : -20, //!< Database error 16 | RPC_DESERIALIZATION_ERROR : -22, //!< Error parsing or validating structure in raw format 17 | RPC_VERIFY_ERROR : -25, //!< General error during transaction or block submission 18 | RPC_VERIFY_REJECTED : -26, //!< Transaction or block was rejected by network rules 19 | RPC_VERIFY_ALREADY_IN_CHAIN : -27, //!< Transaction already in chain 20 | RPC_IN_WARMUP : -28, //!< Client still warming up 21 | 22 | //! P2P client errors 23 | RPC_CLIENT_NOT_CONNECTED : -9, //!< Bitcoin is not connected 24 | RPC_CLIENT_IN_INITIAL_DOWNLOAD : -10, //!< Still downloading initial blocks 25 | RPC_CLIENT_NODE_ALREADY_ADDED : -23, //!< Node is already added 26 | RPC_CLIENT_NODE_NOT_ADDED : -24, //!< Node has not been added before 27 | RPC_CLIENT_NODE_NOT_CONNECTED : -29, //!< Node to disconnect not found in connected nodes 28 | RPC_CLIENT_INVALID_IP_OR_SUBNET : -30, //!< Invalid IP/Subnet 29 | RPC_CLIENT_P2P_DISABLED : -31, //!< No valid connection manager instance found 30 | 31 | //! Wallet errors 32 | RPC_WALLET_ERROR : -4, //!< Unspecified problem with wallet (key not found etc.) 33 | RPC_WALLET_INSUFFICIENT_FUNDS : -6, //!< Not enough funds in wallet or account 34 | RPC_WALLET_INVALID_ACCOUNT_NAME : -11, //!< Invalid account name 35 | RPC_WALLET_KEYPOOL_RAN_OUT : -12, //!< Keypool ran out, call keypoolrefill first 36 | RPC_WALLET_UNLOCK_NEEDED : -13, //!< Enter the wallet passphrase with walletpassphrase first 37 | RPC_WALLET_PASSPHRASE_INCORRECT : -14, //!< The wallet passphrase entered was incorrect 38 | RPC_WALLET_WRONG_ENC_STATE : -15, //!< Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.) 39 | RPC_WALLET_ENCRYPTION_FAILED : -16, //!< Failed to encrypt the wallet 40 | RPC_WALLET_ALREADY_UNLOCKED : -17, //!< Wallet is already unlocked 41 | RPC_WALLET_NOT_FOUND : -18, //!< Invalid wallet specified 42 | RPC_WALLET_NOT_SPECIFIED : -19, //!< No wallet specified (error when there are multiple wallets loaded) 43 | } -------------------------------------------------------------------------------- /routes/api/native/cryptoConditions.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = (api) => { 4 | //TODO: Finish when API call for estimatefee is completed 5 | api.native.parse_reserve_transfer = async (chainTicker, rawTx) => { 6 | let totalIn, totalOut, totalTransferFees, totalNetworkFees, conversionFee = 0 7 | let isConversion, currencyNotChainticker = false 8 | 9 | const decodedTx = await api.native.callDaemon( 10 | chainTicker, 11 | "decoderawtransaction", 12 | [rawTx] 13 | ); 14 | 15 | let outs = decodedTx.vout 16 | let ins = decodedTx.vin 17 | 18 | for (let i = 0; i < outs.length; i++) { 19 | let output = outs[i] 20 | 21 | if ( 22 | output.scriptPubKey != null && 23 | output.scriptPubKey.type === "cryptocondition" && 24 | output.scriptPubKey.reservetransfer != null 25 | ) { 26 | totalOut += (output.scriptPubKey.reservetransfer.value + output.scriptPubKey.reservetransfer.fees) 27 | totalTransferFees += output.scriptPubKey.reservetransfer.fees 28 | 29 | if (!currencyNotChainticker && await api.native.get_currency_definition(chain, currency).name !== chainTicker) { 30 | currencyNotChainticker = true 31 | } 32 | 33 | if (!isConversion && output.scriptPubKey.reservetransfer.convert) { 34 | isConversion = true 35 | } 36 | } 37 | } 38 | 39 | for (let i = 0; i < ins.length; i++) { 40 | let input = ins[i] 41 | 42 | if (input.txid != null) { 43 | const inputTx = await api.native.callDaemon( 44 | chainTicker, 45 | "decoderawtransaction", 46 | [await api.native.callDaemon( 47 | chainTicker, 48 | "getrawtransaction", 49 | [input.txid] 50 | )] 51 | ); 52 | 53 | let inouts = inputTx.vout 54 | 55 | for (let i = 0; i < inouts.length; i++) { 56 | let output = inouts[i] 57 | 58 | if ( 59 | currencyNotChainticker && 60 | output.scriptPubKey != null && 61 | output.scriptPubKey.type === "cryptocondition" && 62 | output.scriptPubKey.reservetransfer != null 63 | ) { 64 | totalOut += (output.scriptPubKey.reservetransfer.value + output.scriptPubKey.reservetransfer.fees) 65 | totalTransferFees += output.scriptPubKey.reservetransfer.fees 66 | 67 | if (!currencyNotChainticker && await api.native.get_currency_definition(chain, currency).name !== chainTicker) { 68 | currencyNotChainticker = true 69 | } 70 | 71 | if (!isConversion && output.scriptPubKey.reservetransfer.convert) { 72 | isConversion = true 73 | } 74 | } else if (!currencyNotChainticker && 75 | output.scriptPubKey != null && 76 | output.scriptPubKey.value) { 77 | // TODO: Finish calculating fee 78 | } 79 | } 80 | } 81 | } 82 | }; 83 | 84 | return api; 85 | }; -------------------------------------------------------------------------------- /routes/api/electrum/interest.js: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2018 - 2019 Atomic Labs, Luke Childs 5 | Copyright (c) 2019 - 2022 Komodo Platform 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | */ 25 | 26 | const KOMODO_ENDOFERA = 7777777; 27 | const LOCKTIME_THRESHOLD = 500000000; 28 | const MIN_SATOSHIS = 1000000000; 29 | const ONE_MONTH_CAP_HARDFORK = 1000000; 30 | const ONE_HOUR = 60; 31 | const ONE_MONTH = 31 * 24 * 60; 32 | const ONE_YEAR = 365 * 24 * 60; 33 | const DEVISOR = 10512000; 34 | const N_S7_HARDFORK_HEIGHT = 3484958; 35 | 36 | module.exports = (api) => { 37 | api.kmdCalcInterest = (locktime, value, height) => { 38 | const tiptime = Math.floor(Date.now() / 1000) - 777; 39 | const satoshis = value; 40 | 41 | // Calculate coinage 42 | const coinage = Math.floor((tiptime - locktime) / ONE_HOUR); 43 | 44 | // Return early if UTXO is not eligible for rewards 45 | if ( 46 | (height >= KOMODO_ENDOFERA) || 47 | (locktime < LOCKTIME_THRESHOLD) || 48 | (satoshis < MIN_SATOSHIS) || 49 | (coinage < ONE_HOUR) || 50 | (!height) 51 | ) { 52 | return 0; 53 | } 54 | 55 | // Cap reward periods 56 | const limit = (height >= ONE_MONTH_CAP_HARDFORK) ? ONE_MONTH : ONE_YEAR; 57 | let rewardPeriod = Math.min(coinage, limit); 58 | 59 | // The first hour of coinage should not accrue rewards 60 | rewardPeriod -= 59; 61 | 62 | // Calculate rewards 63 | let rewards = Math.floor(satoshis / DEVISOR) * rewardPeriod; 64 | 65 | // Vote-KIP0001 resulted in a reduction of the AUR from 5% to 0.01% 66 | // https://github.com/KomodoPlatform/kips/blob/main/kip-0001.mediawiki 67 | // https://github.com/KomodoPlatform/komodo/pull/584 68 | if (height >= N_S7_HARDFORK_HEIGHT) { 69 | rewards = Math.floor(rewards / 500); 70 | } 71 | 72 | // Ensure reward value is never negative 73 | if (rewards < 0) { 74 | throw new Error('Reward should never be negative'); 75 | } 76 | 77 | return rewards; 78 | }; 79 | 80 | return api; 81 | }; -------------------------------------------------------------------------------- /routes/api/electrum/addresses.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.electrum.get_addresses = async (coin) => { 3 | const coinLc = coin.toLowerCase() 4 | let addresses = { 5 | public: [], 6 | private: [] 7 | } 8 | 9 | if (!api.electrumKeys[coinLc] || !api.electrumKeys[coinLc].pub) { 10 | throw new Error(`No address found for ${coin}`); 11 | } 12 | 13 | addresses.public.push({address: api.electrumKeys[coinLc].pub, tag: 'public'}) 14 | 15 | for (let i = 0; i < addresses.public.length; i++) { 16 | const addressObj = addresses.public[i]; 17 | 18 | try { 19 | const addressBalances = await api.electrum.get_balances(addressObj.address, coin) 20 | 21 | addresses.public[i] = { 22 | ...addressObj, 23 | balances: { native: addressBalances.confirmed, reserve: {} }, 24 | }; 25 | } catch(e) { 26 | api.log("Error fetching balance for " + addressObj.address, "electrum.get_addresses") 27 | api.log(e, "electrum.get_addresses") 28 | 29 | addresses.public[i] = { 30 | ...addressObj, 31 | balances: null 32 | }; 33 | } 34 | } 35 | 36 | return addresses 37 | }; 38 | 39 | api.setPost('/electrum/get_pubkey', (req, res, next) => { 40 | const coin = req.body.chainTicker; 41 | const coinLc = coin.toLowerCase() 42 | 43 | if (api.electrumKeys[coinLc] && api.electrumKeys[coinLc].pubHex) { 44 | res.send(JSON.stringify({ 45 | msg: 'success', 46 | result: api.electrumKeys[coinLc].pubHex 47 | })); 48 | } else { 49 | res.send(JSON.stringify({ 50 | msg: 'error', 51 | result: `No pubkey found for electrum coin ${coin}` 52 | })); 53 | } 54 | }); 55 | 56 | api.setPost('/electrum/get_privkey', (req, res, next) => { 57 | const coin = req.body.chainTicker; 58 | const coinLc = coin.toLowerCase() 59 | 60 | if (api.electrumKeys[coinLc] && api.electrumKeys[coinLc].priv) { 61 | res.send(JSON.stringify({ 62 | msg: 'success', 63 | result: api.electrumKeys[coinLc].priv 64 | })); 65 | } else { 66 | res.send(JSON.stringify({ 67 | msg: 'error', 68 | result: `No privkey found for electrum coin ${coin}` 69 | })); 70 | } 71 | }, true); 72 | 73 | api.setGet('/electrum/get_addresses', (req, res, next) => { 74 | const coin = req.query.chainTicker; 75 | 76 | if (!req.query.chainTicker) { 77 | res.send(JSON.stringify({msg: 'error', result: "No coin passed to electrum get_addresses"})); 78 | } 79 | 80 | api.electrum.get_addresses(coin) 81 | .then((addresses) => { 82 | const retObj = { 83 | msg: 'success', 84 | result: addresses, 85 | }; 86 | 87 | res.send(JSON.stringify(retObj)); 88 | }) 89 | .catch(error => { 90 | const retObj = { 91 | msg: 'error', 92 | result: error.message, 93 | }; 94 | 95 | res.send(JSON.stringify(retObj)); 96 | }) 97 | }); 98 | 99 | return api; 100 | }; --------------------------------------------------------------------------------