diff --git a/config-test.json b/config-test.json index f5f05eb..bab8052 100644 --- a/config-test.json +++ b/config-test.json @@ -117,6 +117,7 @@ "interval": 60, "depth": 10, "poolFee": 0.2, + "soloFee": 0.2, "devDonation": 0.5, "networkFee": 0.0 }, diff --git a/config.json b/config.json index 26e404f..b9906f0 100644 --- a/config.json +++ b/config.json @@ -117,6 +117,7 @@ "interval": 60, "depth": 10, "poolFee": 0.2, + "soloFee": 0.2, "devDonation": 0.5, "networkFee": 0.0 }, diff --git a/lib/api.js b/lib/api.js index 307f4c5..9c64546 100644 --- a/lib/api.js +++ b/lib/api.js @@ -378,6 +378,7 @@ function collectStats(){ cnBlobType: config.cnBlobType || 0, hashrateWindow: config.api.hashrateWindow, fee: config.blockUnlocker.poolFee, + soloFee: config.blockUnlocker.soloFee >= 0 ? config.blockUnlocker.soloFee : (config.blockUnlocker.poolFee > 0 ? config.blockUnlocker.poolFee : 0), networkFee: config.blockUnlocker.networkFee || 0, coin: config.coin, coinUnits: config.coinUnits, diff --git a/lib/blockUnlocker.js b/lib/blockUnlocker.js index 5a0f52d..9ce97d6 100644 --- a/lib/blockUnlocker.js +++ b/lib/blockUnlocker.js @@ -218,7 +218,10 @@ function runInterval(){ block.reward ].join(':')]) - let feePercent = config.blockUnlocker.poolFee / 100 + let feePercent = (config.blockUnlocker.poolFee > 0 ? config.blockUnlocker.poolFee : 0) / 100 + + if (block.rewardType === 'solo') + feePercent = (config.blockUnlocker.soloFee >= 0 ? config.blockUnlocker.soloFee : (config.blockUnlocker.poolFee > 0 ? config.blockUnlocker.poolFee : 0)) / 100 if (Object.keys(donations).length) { for(let wallet in donations) { diff --git a/lib/charts.js b/lib/charts.js index bd862d9..bac20d0 100644 --- a/lib/charts.js +++ b/lib/charts.js @@ -77,6 +77,17 @@ let statValueHandler = { } }; +let preSaveFunctions = { + hashrate: statValueHandler.avgRound, + hashrateSolo: statValueHandler.avgRound, + workers: statValueHandler.max, + workersSolo: statValueHandler.max, + difficulty: statValueHandler.avgRound, + price: statValueHandler.avg, + profit: statValueHandler.avg +}; + +/* // Presave functions let preSaveFunctions = { hashrate: statValueHandler.avgRound, @@ -85,14 +96,49 @@ let preSaveFunctions = { price: statValueHandler.avg, profit: statValueHandler.avg }; +*/ // Store collected values in redis database function storeCollectedValues(chartName, values, settings) { for(let i in values) { - storeCollectedValue(chartName + ':' + i, values[i], settings); + storeCollectedValue(chartName + ':' + i, [values[i]], settings); } } +function storeCollectedValue (chartName, values, settings) { + let now = new Date() / 1000 | 0; + values.forEach((value, index) => { + let name = `${chartName}` + (index === 0 ? '' : 'Solo') + return getChartDataFromRedis(name, function (sets) { + let lastSet = sets[sets.length - 1]; // [time, avgValue, updatesCount] + if (!lastSet || now - lastSet[0] > settings.stepInterval) { + lastSet = [now, value, 1]; + sets.push(lastSet); + while (now - sets[0][0] > settings.maximumPeriod) { // clear old sets + sets.shift(); + } + } else { + preSaveFunctions[name] ? + preSaveFunctions[name](lastSet, value) : + statValueHandler.avgRound(lastSet, value); + lastSet[2]++; + } + + if (getStatsRedisKey(name) + .search(`^${config.coin}:charts:hashrate$`) >= 0) { + redisClient.set(getStatsRedisKey(name), JSON.stringify(sets), 'EX', (86400 * cleanupInterval)); + } else if (getStatsRedisKey(name) + .search(`^${config.coin}:charts:hashrateSolo$`) >= 0) { + redisClient.set(getStatsRedisKey(name), JSON.stringify(sets), 'EX', (86400 * cleanupInterval)); + } else { + redisClient.set(getStatsRedisKey(name), JSON.stringify(sets)); + } + log('info', logSystem, name + ' chart collected value ' + value + '. Total sets count ' + sets.length); + }); + }) +} + +/* // Store collected value in redis database function storeCollectedValue(chartName, value, settings) { let now = new Date() / 1000 | 0; @@ -122,6 +168,7 @@ function storeCollectedValue(chartName, value, settings) { log('info', logSystem, chartName + ' chart collected value ' + value + '. Total sets count ' + sets.length); }); } +*/ // Collect pool statistics with an interval function collectPoolStatWithInterval(chartName, settings) { @@ -166,7 +213,7 @@ function getPoolStats(callback) { **/ function getPoolHashrate(callback) { getPoolStats(function(error, stats) { - callback(error, stats.pool ? Math.round(stats.pool.hashrate) : null); + callback(error, stats.pool ? [Math.round(stats.pool.hashrate), Math.round(stats.pool.hashrateSolo)] : null); }); } @@ -175,7 +222,7 @@ function getPoolHashrate(callback) { **/ function getPoolMiners(callback) { getPoolStats(function(error, stats) { - callback(error, stats.pool ? stats.pool.miners : null); + callback(error, stats.pool ? [stats.pool.miners, stats.pool.minersSolo] : null); }); } @@ -184,7 +231,7 @@ function getPoolMiners(callback) { **/ function getPoolWorkers(callback) { getPoolStats(function(error, stats) { - callback(error, stats.pool ? stats.pool.workers : null); + callback(error, stats.pool ? [stats.pool.workers, stats.pool.workersSolo] : null); }); } @@ -193,7 +240,7 @@ function getPoolWorkers(callback) { **/ function getNetworkDifficulty(callback) { getPoolStats(function(error, stats) { - callback(error, stats.pool ? stats.network.difficulty : null); + callback(error, stats.pool ? [stats.network.difficulty] : null); }); } @@ -327,6 +374,12 @@ function getPoolChartsData(callback) { redisKeys.push(getStatsRedisKey(chartName)); } } + chartsNames.push('hashrateSolo') + chartsNames.push('minersSolo') + chartsNames.push('workersSolo') + redisKeys.push(getStatsRedisKey('hashrateSolo')) + redisKeys.push(getStatsRedisKey('minersSolo')) + redisKeys.push(getStatsRedisKey('workersSolo')) if(redisKeys.length) { redisClient.mget(redisKeys, function(error, data) { let stats = {}; diff --git a/lib/pool.js b/lib/pool.js index 7c252d9..6d36957 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -1007,6 +1007,26 @@ function recordShareData(miner, job, shareDiff, blockCandidate, hashHex, shareTy redisCommands.push(['hset', `${coin}:unique_workers:${login}~${workerName}`, 'lastShare', dateNowSeconds]); redisCommands.push(['expire', `${coin}:unique_workers:${login}~${workerName}`, (86400 * cleanupInterval)]); } +/* + if (blockCandidate){ + redisCommands.push(['hset', `${coin}:stats`, `lastBlockFound${rewardType}`, Date.now()]); + redisCommands.push(['rename', `${coin}:scores:prop:roundCurrent`, coin + ':scores:prop:round' + job_height]); + redisCommands.push(['rename', `${coin}:scores:solo:roundCurrent`, coin + ':scores:solo:round' + job_height]); + redisCommands.push(['rename', `${coin}:shares_actual:prop:roundCurrent`, `${coin}:shares_actual:prop:round${job_height}`]); + redisCommands.push(['rename', `${coin}:shares_actual:solo:roundCurrent`, `${coin}:shares_actual:solo:round${job_height}`]); + if (rewardType === 'prop') { + redisCommands.push(['hgetall', `${coin}:scores:prop:round${job_height}`]); + redisCommands.push(['hgetall', `${coin}:shares_actual:prop:round${job_height}`]); + } + if (rewardType === 'solo') { + redisCommands.push(['hget', `${coin}:scores:solo:round${job_height}`, login]); + redisCommands.push(['hget', `${coin}:shares_actual:solo:round${job_height}`, login]); + } + + } +*/ + + if (blockCandidate){ redisCommands.push(['hset', `${coin}:stats`, `lastBlockFound${rewardType}`, Date.now()]); diff --git a/website_example/js/common.js b/website_example/js/common.js index 1d0087a..b98023c 100644 --- a/website_example/js/common.js +++ b/website_example/js/common.js @@ -1,7 +1,7 @@ /** * Common javascript code for cryptonote-nodejs-pool - * Author: Daniel Vandal - * GitHub: https://github.com/dvandal/cryptonote-nodejs-pool + * Author: Muscleman + * GitHub: https://github.com/muscleman/cryptonote-nodejs-pool **/ /** @@ -9,7 +9,8 @@ **/ // Collapse menu on load for mobile devices -$('#menu-content').collapse('hide'); +$('#menu-content') + .collapse('hide'); /** * Cookies handler @@ -17,34 +18,41 @@ $('#menu-content').collapse('hide'); var docCookies = { getItem: function (sKey) { - return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; + return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey) + .replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; }, - setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { - if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } + setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure=true) { + if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { + return false; + } var sExpires = ""; if (vEnd) { switch (vEnd.constructor) { - case Number: - sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; - break; - case String: - sExpires = "; expires=" + vEnd; - break; - case Date: - sExpires = "; expires=" + vEnd.toUTCString(); - break; + case Number: + sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; + break; + case String: + sExpires = "; expires=" + vEnd; + break; + case Date: + sExpires = "; expires=" + vEnd.toUTCString(); + break; } } - document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); + document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "") + "; SameSite=strict"; return true; }, removeItem: function (sKey, sPath, sDomain) { - if (!sKey || !this.hasItem(sKey)) { return false; } - document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : ""); + if (!sKey || !this.hasItem(sKey)) { + return false; + } + document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); return true; }, hasItem: function (sKey) { - return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); + return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey) + .replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")) + .test(document.cookie); } }; @@ -56,25 +64,31 @@ var docCookies = { var currentPage; // Handle hash change -window.onhashchange = function(){ +window.onhashchange = function () { routePage(); }; // Route to page var xhrPageLoading; -function routePage(loadedCallback) { + +function routePage (loadedCallback) { if (currentPage) currentPage.destroy(); - $('#page').html(''); - $('#loading').show(); + $('#page') + .html(''); + $('#loading') + .show(); if (xhrPageLoading) { xhrPageLoading.abort(); } - $('.hot_link').parent().removeClass('active'); + $('.hot_link') + .parent() + .removeClass('active'); var $link = $('a.hot_link[href="' + (window.location.hash || '#') + '"]'); - $link.parent().addClass('active'); + $link.parent() + .addClass('active'); var page = $link.data('page'); loadTranslations(); @@ -83,10 +97,14 @@ function routePage(loadedCallback) { url: 'pages/' + page, cache: false, success: function (data) { - $('#menu-content').collapse('hide'); - $('#loading').hide(); - $('#page').show().html(data); - loadTranslations(); + $('#menu-content') + .collapse('hide'); + $('#loading') + .hide(); + $('#page') + .show() + .html(data); + loadTranslations(); if (currentPage) currentPage.update(); if (loadedCallback) loadedCallback(); } @@ -98,7 +116,7 @@ function routePage(loadedCallback) { **/ // Add .update() custom jQuery function to update text content -$.fn.update = function(txt){ +$.fn.update = function (txt) { var el = this[0]; if (el && el.textContent !== txt) el.textContent = txt; @@ -106,10 +124,10 @@ $.fn.update = function(txt){ }; // Update Text classes -function updateTextClasses(className, text){ +function updateTextClasses (className, text) { var els = document.getElementsByClassName(className); if (els) { - for (var i = 0; i < els.length; i++){ + for (var i = 0; i < els.length; i++) { var el = els[i]; if (el && el.textContent !== text) el.textContent = text; @@ -118,45 +136,41 @@ function updateTextClasses(className, text){ } // Update Text content -function updateText(elementId, text){ +function updateText (elementId, text) { var el = document.getElementById(elementId); - if (el && el.textContent !== text){ + if (el && el.textContent !== text) { el.textContent = text; } return el; } -// Convert float to string -function floatToString(float) { - return float.toFixed(6).replace(/[0\.]+$/, ''); -} - // Format number -function formatNumber(number, delimiter){ - if(number != '') { - number = number.split(delimiter).join(''); +function formatNumber (number, delimiter) { + if (number != '') { + number = number.split(delimiter) + .join(''); var formatted = ''; var sign = ''; - if(number < 0){ + if (number < 0) { number = -number; sign = '-'; } - while(number >= 1000){ + while (number >= 1000) { var mod = number % 1000; - if(formatted != '') formatted = delimiter + formatted; - if(mod == 0) formatted = '000' + formatted; - else if(mod < 10) formatted = '00' + mod + formatted; - else if(mod < 100) formatted = '0' + mod + formatted; + if (formatted != '') formatted = delimiter + formatted; + if (mod == 0) formatted = '000' + formatted; + else if (mod < 10) formatted = '00' + mod + formatted; + else if (mod < 100) formatted = '0' + mod + formatted; else formatted = mod + formatted; number = parseInt(number / 1000); } - if(formatted != '') formatted = sign + number + delimiter + formatted; + if (formatted != '') formatted = sign + number + delimiter + formatted; else formatted = sign + number; return formatted; } @@ -164,109 +178,135 @@ function formatNumber(number, delimiter){ } // Format date -function formatDate(time){ +function formatDate (time) { if (!time) return ''; - return new Date(parseInt(time) * 1000).toLocaleString(); + let timeZone = moment.tz.guess() + let options = { + year: 'numeric', month: 'numeric', day: 'numeric', + hour: 'numeric', minute: 'numeric', second: 'numeric', + hour12: false, + timeZone: timeZone + } + return new Intl.DateTimeFormat('en-US', options).format(new Date(parseInt(time) * 1000)) } // Format percentage -function formatPercent(percent) { +function formatPercent (percent) { if (!percent && percent !== 0) return ''; return percent + '%'; } // Get readable time -function getReadableTime(seconds){ - var units = [ [60, 'second'], [60, 'minute'], [24, 'hour'], - [7, 'day'], [4, 'week'], [12, 'month'], [1, 'year'] ]; +function getReadableTime (seconds) { + if (isNaN(seconds)) return seconds + var units = [[60, 'second'], [60, 'minute'], [24, 'hour'], + [7, 'day'], [4, 'week'], [12, 'month'], [1, 'year']]; - function formatAmounts(amount, unit){ + function formatAmounts (amount, unit) { var rounded = Math.round(amount); - var unit = unit + (rounded > 1 ? 's' : ''); + unit = unit + (rounded > 1 ? 's' : ''); if (getTranslation(unit)) unit = getTranslation(unit); return '' + rounded + ' ' + unit; } var amount = seconds; - for (var i = 0; i < units.length; i++){ + for (var i = 0; i < units.length; i++) { if (amount < units[i][0]) { return formatAmounts(amount, units[i][1]); - } + } amount = amount / units[i][0]; } - return formatAmounts(amount, units[units.length - 1][1]); + return formatAmounts(amount, units[units.length - 1][1]); } // Get readable hashrate -function getReadableHashRateString(hashrate){ +function getReadableHashRateString (hashrate) { var i = 0; - var byteUnits = [' H', ' KH', ' MH', ' GH', ' TH', ' PH' ]; - while (hashrate > 1000){ + //var byteUnits = [' H', ' KH', ' MH', ' GH', ' TH', ' PH']; + while (hashrate > 1000) { hashrate = hashrate / 1000; i++; } if (typeof hashrate != 'number') - hashrate = 0; + hashrate = 0; return hashrate.toFixed(2) + byteUnits[i]; } -function getCoinDecimalPlace(stats) -{ +function getCoinDecimalPlace (stats) { if (typeof coinDecimalPlaces != "undefined") return coinDecimalPlaces; else if (stats.config.coinDecimalPlaces) return stats.config.coinDecimalPlaces; - else stats.config.coinUnits.toString().length - 1; + else stats.config.coinUnits.toString() + .length - 1; } -function getReadableCoin(stats, coins, digits, withoutSymbol) { +function getReadableCoin (stats, coins, digits, withoutSymbol) { let coinDecimalPlaces = getCoinDecimalPlace(stats) - let amount = parseFloat((parseInt(coins || 0) / stats.config.coinUnits).toFixed(digits || coinDecimalPlaces)) + let amount = parseFloat((coins || 0) / stats.config.coinUnits) + .toFixed(digits || coinDecimalPlaces) return amount.toString() + (withoutSymbol ? '' : (' ' + stats.config.symbol)); } // Format payment link -function formatPaymentLink(hash, merged){ +function formatPaymentLink (hash, merged) { return '' + hash + ''; } // Format difficulty -function formatDifficulty(x) { - return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " "); +function formatDifficulty (x) { + return x.toString() + .replace(/\B(?=(\d{3})+(?!\d))/g, " "); } // Format luck / current effort -function formatLuck(difficulty, shares, solo=false) { +function formatLuck (difficulty, shares, solo = false) { // Only an approximation to reverse the calculations done in pool.js, because the shares with their respective times are not recorded in redis // Approximation assumes equal pool hashrate for the whole round // Could potentially be replaced by storing the sum of all job.difficulty in the redis db. + let accurateShares = shares if (lastStats.config.slushMiningEnabled) { // Uses integral calculus to calculate the average of a dynamic function - var accurateShares = 1/lastStats.config.blockTime * ( // 1/blockTime to get the average - shares * lastStats.config.weight * ( // Basically calculates the 'area below the graph' between 0 and blockTime + accurateShares = 1 / lastStats.config.blockTime * ( // 1/blockTime to get the average + shares * lastStats.config.weight * ( // Basically calculates the 'area below the graph' between 0 and blockTime 1 - Math.pow( Math.E, - ((- lastStats.config.blockTime) / lastStats.config.weight) // blockTime is equal to the highest possible result of (dateNowSeconds - scoreTime) + ((-lastStats.config.blockTime) / lastStats.config.weight) // blockTime is equal to the highest possible result of (dateNowSeconds - scoreTime) ) ) ); - } - else { - var accurateShares = shares; - } + } - var percent = Math.round(accurateShares / difficulty * 100); - if(!percent){ - return `?` + (solo === true ? `` : ``); - } - else if(percent <= 100){ + let percent = 0.00 + if (difficulty > 0) + percent = parseFloat(accurateShares / difficulty * 100).toFixed(2) + if (!percent) { + return `0.00% ` + (solo === true ? `` : ``); + } else if (percent >=0 && percent < 1) { return `${percent}% ` + (solo === true ? `` : ``); - } - else if(percent >= 101 && percent <= 150){ + } else if (percent <= 100) { + return `${percent}% ` + (solo === true ? `` : ``); + } else if (percent >= 101 && percent <= 150) { return `${percent}% ` + (solo === true ? `` : ``); - } - else{ + } else { return `${percent}% ` + (solo === true ? `` : ``); } + +/* + let percent = 0.00 + if (difficulty > 0) + percent = parseFloat(accurateShares / difficulty * 100).toFixed(2) + if (!percent) { + return `0.00% ` + (solo === true ? `` : ``); + } else if (percent >=0 && percent < 1) { + return `${percent}% ` + (solo === true ? `` : ``); + } else if (percent <= 100) { + return `${percent}% ` + (solo === true ? `` : ``); + } else if (percent >= 101 && percent <= 150) { + return `${percent}% ` + (solo === true ? `` : ``); + } else { + return `${percent}% ` + (solo === true ? `` : ``); + } +*/ } /** @@ -274,23 +314,25 @@ function formatLuck(difficulty, shares, solo=false) { **/ // Return pool host -function getPoolHost() { +function getPoolHost () { if (typeof poolHost != "undefined") return poolHost; if (lastStats.config.poolHost) return lastStats.config.poolHost; else return window.location.hostname; } // Return transaction URL -function getTransactionUrl(id, stats) { - if (stats && blockExplorers){ - return blockExplorers[stats.config.coin].transactionExplorer.replace('{symbol}', stats.config.symbol.toLowerCase()).replace('{id}', id); +function getTransactionUrl (id, stats) { + if (stats && blockExplorers && blockExplorers[stats.config.coin]) { + return blockExplorers[stats.config.coin].transactionExplorer.replace('{symbol}', stats.config.symbol.toLowerCase()) + .replace('{id}', id); } } // Return blockchain explorer URL -function getBlockchainUrl(id, stats) { - if (stats && blockExplorers){ - return blockExplorers[stats.config.coin].blockchainExplorer.replace('{symbol}', stats.config.symbol.toLowerCase()).replace('{id}', id); +function getBlockchainUrl (id, stats) { + if (stats && blockExplorers && blockExplorers[stats.config.coin]) { + return blockExplorers[stats.config.coin].blockchainExplorer.replace('{symbol}', stats.config.symbol.toLowerCase()) + .replace('{id}', id); } } @@ -299,31 +341,45 @@ function getBlockchainUrl(id, stats) { **/ // Sort table cells -function sortTable() { - var table = $(this).parents('table').eq(0), - rows = table.find('tr:gt(0)').toArray().sort(compareTableRows($(this).index())); +function sortTable () { + var table = $(this) + .parents('table') + .eq(0), + rows = table.find('tr:gt(0)') + .toArray() + .sort(compareTableRows($(this) + .index())); this.asc = !this.asc; - if(!this.asc) { + if (!this.asc) { rows = rows.reverse() } - for(var i = 0; i < rows.length; i++) { + for (var i = 0; i < rows.length; i++) { table.append(rows[i]) } } // Compare table rows -function compareTableRows(index) { - return function(a, b) { - var valA = getCellValue(a, index), valB = getCellValue(b, index); - if (!valA) { valA = 0; } - if (!valB) { valB = 0; } - return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.toString().localeCompare(valB.toString()) +function compareTableRows (index) { + return function (a, b) { + var valA = getCellValue(a, index), + valB = getCellValue(b, index); + if (!valA) { + valA = 0; + } + if (!valB) { + valB = 0; + } + return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.toString() + .localeCompare(valB.toString()) } } // Get table cell value -function getCellValue(row, index) { - return $(row).children('td').eq(index).data("sort") +function getCellValue (row, index) { + return $(row) + .children('td') + .eq(index) + .data("sort") } /** @@ -331,7 +387,9 @@ function getCellValue(row, index) { **/ if (typeof langs == "undefined") { - var langs = { en: 'English' }; + var langs = { + en: 'English' + }; } if (typeof defaultLang == "undefined") { @@ -341,58 +399,69 @@ if (typeof defaultLang == "undefined") { var langCode = defaultLang; var langData = null; -function getTranslation(key) { +function getTranslation (key) { if (!langData || !langData[key]) return null; return langData[key]; } -var translate = function(data) { +var translate = function (data) { $("html")[0].lang = langCode; langData = data; - $("[data-tkey]").each(function(index) { - var strTr = data[$(this).attr('data-tkey')]; - $(this).html(strTr); - }); + $("[data-tkey]") + .each(function (index) { + var strTr = data[$(this) + .attr('data-tkey')]; + $(this) + .html(strTr); + }); - $("[data-tplaceholder]").each(function(index) { - var strTr = data[$(this).attr('data-tplaceholder')]; - $(this).attr('placeholder', strTr) - }); + $("[data-tplaceholder]") + .each(function (index) { + var strTr = data[$(this) + .attr('data-tplaceholder')]; + $(this) + .attr('placeholder', strTr) + }); - $("[data-tvalue]").each(function(index) { - var strTr = data[$(this).attr('data-tvalue')]; - $(this).attr('value', strTr) - }); + $("[data-tvalue]") + .each(function (index) { + var strTr = data[$(this) + .attr('data-tvalue')]; + $(this) + .attr('value', strTr) + }); } // Get language code from URL const $_GET = {}; -const args = location.search.substr(1).split(/&/); -for (var i=0; i' + langs[lang] + ''; - numLangs ++; + numLangs++; } - html += ''; + html += ''; } if (html && numLangs > 1) { - $('#langSelector').html(html); - $('#newLang').each(function(){ - $(this).change(function() { - var newLang = $(this).val(); - var url = '?lang=' + newLang; - if (window.location.hash) url += window.location.hash; - window.location.href = url; + $('#langSelector') + .html(html); + $('#newLang') + .each(function () { + $(this) + .change(function () { + var newLang = $(this) + .val(); + var url = '?lang=' + newLang; + if (window.location.hash) url += window.location.hash; + window.location.href = url; + }); }); - }); } // Mobile @@ -425,20 +498,24 @@ function renderLangSelector() { for (var lang in langs) { var selected = lang == langCode ? ' selected="selected"' : ''; html += ''; - numLangs ++; + numLangs++; } - html += ''; + html += ''; } if (html && numLangs > 1) { - $('#mLangSelector').html(html); - $('#mNewLang').each(function(){ - $(this).change(function() { - var newLang = $(this).val(); - var url = '?lang=' + newLang; - if (window.location.hash) url += window.location.hash; - window.location.href = url; + $('#mLangSelector') + .html(html); + $('#mNewLang') + .each(function () { + $(this) + .change(function () { + var newLang = $(this) + .val(); + var url = '?lang=' + newLang; + if (window.location.hash) url += window.location.hash; + window.location.href = url; + }); }); - }); } } @@ -449,35 +526,37 @@ pool_block methods *************************************************************** */ -function poolBlocks_GenerateChart(data, displayedChart) { - if (displayedChart[data.config.coin] || !data.charts.blocks || data.charts.blocks === "undefined" || !data.charts.blocksSolo || data.charts.blocksSolo === "undefined") return ; - let chartDays = data.config.blocksChartDays || null; - let title = getTranslation('poolBlocks') ? getTranslation('poolBlocks') : 'Blocks found'; +function poolBlocks_GenerateChart (data, displayedChart) { + if (displayedChart[data.config.coin] || !data.charts.blocks || data.charts.blocks === "undefined" || !data.charts.blocksSolo || data.charts.blocksSolo === "undefined") return; + let chartDays = data.config.blocksChartDays || null; + let title = getTranslation('poolBlocks') ? getTranslation('poolBlocks') : 'Blocks found'; if (chartDays) { if (chartDays === 1) title = getTranslation('blocksFoundLast24') ? getTranslation('blocksFoundLast24') : 'Blocks found in the last 24 hours'; else title = getTranslation('blocksFoundLastDays') ? getTranslation('blocksFoundLastDays') : 'Blocks found in the last {DAYS} days'; title = title.replace('{DAYS}', chartDays); } updateText(`blocksChartTitle${data.config.coin}`, title); - let labels = []; - let values = []; - let valuesSolo = []; - for (let key in data.charts.blocks) { - let label = key; + let labels = []; + let values = []; + let valuesSolo = []; + for (let key in data.charts.blocks) { + let label = key; if (chartDays && chartDays === 1) { - let keyParts = key.split(' '); + let keyParts = key.split(' '); label = keyParts[1].replace(':00', ''); } labels.push(label); values.push(data.charts.blocks[key]); } - for (let key in data.charts.blocksSolo) { + for (let key in data.charts.blocksSolo) { valuesSolo.push(data.charts.blocksSolo[key]); } - let $chart = $(`blocksChartObj${data.config.coin}`); - let bgcolor = null, bordercolor = null, borderwidth = null; - let colorelem = $chart.siblings('a.chart-style'); + let $chart = $(`blocksChartObj${data.config.coin}`); + let bgcolor = null, + bordercolor = null, + borderwidth = null; + let colorelem = $chart.siblings('a.chart-style'); if (colorelem.length == 1) { bgcolor = colorelem.css('background-color'); bordercolor = colorelem.css('border-left-color'); @@ -488,111 +567,117 @@ function poolBlocks_GenerateChart(data, displayedChart) { if (borderwidth === null || isNaN(borderwidth)) borderwidth = 1; let chartElement = document.getElementById(`blocksChartObj${data.config.coin}`) if (!chartElement) return - let chart = new Chart(chartElement, { + let chart = new Chart(chartElement, { type: 'bar', data: { labels: labels, datasets: [{ - label: 'Prop Blocks', - data: values, - fill: false, - backgroundColor: bgcolor, - borderColor: bordercolor, - borderWidth: borderwidth + label: 'Prop Blocks', + data: values, + fill: false, + backgroundColor: bgcolor, + borderColor: bordercolor, + borderWidth: borderwidth }, - { - label: 'Solo Blocks', - data: valuesSolo, - fill: false, - backgroundColor: 'rgba(0, 230, 64, 1)', - borderColor: bordercolor, - borderWidth: borderwidth + { + label: 'Solo Blocks', + data: valuesSolo, + fill: false, + backgroundColor: 'rgba(0, 230, 64, 1)', + borderColor: bordercolor, + borderWidth: borderwidth }] }, options: { responsive: true, maintainAspectRatio: false, - legend: { display: false }, + legend: { + display: false + }, scales: { yAxes: [{ ticks: { beginAtZero: true, - userCallback: function(label, index, labels) { + userCallback: function (label, index, labels) { if (Math.floor(label) === label) return label; } } }], }, layout: { - padding: { top: 0, left: 0, right: 0, bottom: 0 } + padding: { + top: 0, + left: 0, + right: 0, + bottom: 0 + } } } }); - $(`#blocksChart${data.config.coin}`).show(); + $(`#blocksChart${data.config.coin}`) + .show(); displayedChart[data.config.coin] = true; } // Parse block data -function poolBlocks_ParseBlock(height, serializedBlock, stats){ +function poolBlocks_ParseBlock (height, serializedBlock, stats) { var parts = serializedBlock.split(':'); let block = {} - if (parts[0].includes('solo') || parts[0].includes('prop')){ + if (parts[0].includes('solo') || parts[0].includes('prop')) { block = { height: parseInt(height), - solo: parts[0] === 'solo', - address: parts[1], + solo: parts[0] === 'solo', + address: parts[1], hash: parts[2], time: parts[3], - difficulty: parseInt(parts[4]), - shares: parseInt(parts[5]), + difficulty: parseFloat(parts[4]), + shares: parseFloat(parts[5]), orphaned: parts[6], reward: parts[7] }; - }else{ + } else { block = { height: parseInt(height), - solo: false, - address: '', + solo: false, + address: '', hash: parts[0], time: parts[1], - difficulty: parseInt(parts[2]), - shares: parseInt(parts[3]), + difficulty: parseFloat(parts[2]), + shares: parseFloat(parts[3]), orphaned: parts[4], reward: parts[5] }; } var toGo = stats.config.depth - (stats.network.height - block.height - 1); - if(toGo > 1){ + if (toGo > 1) { block.maturity = toGo + ' to go'; - } - else if(toGo == 1){ + } else if (toGo == 1) { block.maturity = ""; - } - else if(toGo <= 0){ + } else if (toGo <= 0) { block.maturity = ""; } - switch (block.orphaned){ - case '0': - block.status = 'unlocked'; - block.maturity = ""; - break; - case '1': - block.status = 'orphaned'; - block.maturity = ""; - block.reward = 0; - break; - default: - block.status = 'pending'; - break; + switch (block.orphaned) { + case '0': + block.status = 'unlocked'; + block.maturity = ""; + break; + case '1': + block.status = 'orphaned'; + block.maturity = ""; + block.reward = 0; + break; + default: + block.status = 'pending'; + break; } return block; } // Get block row element -function getBlockRowElement(block, jsonString, stats){ - function formatBlockLink(hash, stats){ +function getBlockRowElement (block, jsonString, stats) { + function formatBlockLink (hash, stats) { return '' + hash + ''; } @@ -610,10 +695,9 @@ function getBlockRowElement(block, jsonString, stats){ row.className = blockStatusClasses[block.status]; var reward = ""; - if(typeof block.reward == "undefined"){ + if (typeof block.reward == "undefined") { reward = "Waiting..."; - } - else{ + } else { reward = getReadableCoin(stats, block.reward, null, true); } @@ -633,31 +717,33 @@ function getBlockRowElement(block, jsonString, stats){ } // Render blocks -function poolBlocks_RenderBlocks(blocksResults, stats){ +function poolBlocks_RenderBlocks (blocksResults, stats) { var $blocksRows = $(`#blocksReport${stats.config.coin}_rows`); - for (var i = 0; i < blocksResults.length; i += 2){ + for (var i = 0; i < blocksResults.length; i += 2) { var block = poolBlocks_ParseBlock(blocksResults[i + 1], blocksResults[i], stats); var blockJson = JSON.stringify(block); var existingRow = document.getElementById(`blockRow${stats.config.coin}${block.height}`); - if (existingRow && existingRow.getAttribute(`data-json`) !== blockJson){ - $(existingRow).replaceWith(getBlockRowElement(block, blockJson, stats)); - } - else if (!existingRow){ + if (existingRow && existingRow.getAttribute(`data-json`) !== blockJson) { + $(existingRow) + .replaceWith(getBlockRowElement(block, blockJson, stats)); + } else if (!existingRow) { var blockElement = getBlockRowElement(block, blockJson, stats); var inserted = false; - var rows = $blocksRows.children().get(); + var rows = $blocksRows.children() + .get(); for (var f = 0; f < rows.length; f++) { var bHeight = parseInt(rows[f].getAttribute(`data-height`)); - if (bHeight < block.height){ + if (bHeight < block.height) { inserted = true; - $(rows[f]).before(blockElement); + $(rows[f]) + .before(blockElement); break; } } - if (!inserted){ + if (!inserted) { $blocksRows.append(blockElement); } } @@ -665,114 +751,198 @@ function poolBlocks_RenderBlocks(blocksResults, stats){ } // Load more blocks button -function poolBlocks_Setup(api, stats, xhrGetBlocks) { - $(`#loadMoreBlocks${stats.config.coin}`).click(function(xhrGetBlocks){ - if (xhrGetBlocks[stats.config.coin]) xhrGetBlocks[stats.config.coin].abort(); - xhrGetBlocks[stats.config.coin] = $.ajax({ - url: api + '/get_blocks', - data: { - height: $(`#blocksReport${stats.config.coin}_rows`).children().last().data(`height`) - }, - dataType: 'json', - cache: 'false', - success: function(data){ - poolBlocks_RenderBlocks(data, stats); - } +function poolBlocks_Setup (api, stats, xhrGetBlocks) { + $(`#loadMoreBlocks${stats.config.coin}`) + .click(function (xhrGetBlocks) { + if (xhrGetBlocks[stats.config.coin]) xhrGetBlocks[stats.config.coin].abort(); + xhrGetBlocks[stats.config.coin] = $.ajax({ + url: api + '/get_blocks', + data: { + height: $(`#blocksReport${stats.config.coin}_rows`) + .children() + .last() + .data(`height`) + }, + dataType: 'json', + cache: 'false', + success: function (data) { + poolBlocks_RenderBlocks(data, stats); + } + }); }); - }); } -function poolBlocks_InitTemplate(ranOnce, displayedChart, xhrGetBlocks) { - let coin = lastStats.config.coin - if ($(`#blocksTabs li:contains(${coin})`).length == 0) { - let template1 = $('#siblingTemplate').html() - Mustache.parse(template1) - let rendered1 = Mustache.render(template1, {coin:lastStats.config.coin, active:'active'}) - $('#tab-content').append(rendered1) +function poolBlocks_updateStats(stats, key) { + updateText(`blocksTotal${key}`, stats.pool.totalBlocks.toString()); + if (stats.pool.lastBlockFound) { + var d = new Date(parseInt(stats.pool.lastBlockFound)).toISOString(); + $(`#lastBlockFound${key}`) + .timeago('update', d); + } else { + $(`#lastBlockFound${key}`) + .removeAttr('title') + .data('ts', '') + .update('Never'); + } - let template = $('#siblingTabTemplate').html(); + updateText(`blocksTotalSolo${key}`, stats.pool.totalBlocksSolo.toString()); + if (stats.pool.lastBlockFoundSolo) { + var d = new Date(parseInt(stats.pool.lastBlockFoundSolo)) + .toISOString(); + $(`#lastBlockFoundSolo${key}`) + .timeago('update', d); + } else { + $(`#lastBlockFoundSolo${key}`) + .removeAttr('title') + .data('ts', '') + .update('Never'); + } + + updateText(`blocksMaturityCount${key}`, stats.config.depth.toString()); + $(`#averageLuck${key}`) + .html(formatLuck(stats.pool.totalDiff, stats.pool.totalShares)); + $(`#averageLuckSolo${key}`) + .html(formatLuck(stats.pool.totalDiffSolo, stats.pool.totalSharesSolo)); +} + +function poolBlocks_InitTemplate (ranOnce, displayedChart, xhrGetBlocks) { + let coin = lastStats.config.coin + if ($(`#blocksTabs li:contains(${coin})`) + .length == 0) { + let template1 = $('#siblingTemplate') + .html() + Mustache.parse(template1) + let rendered1 = Mustache.render(template1, { + coin: lastStats.config.coin, + active: 'active' + }) + $('#tab-content') + .append(rendered1) + + let template = $('#siblingTabTemplate') + .html(); Mustache.parse(template) - let rendered = Mustache.render(template, {coin:lastStats.config.coin, symbol:`(${lastStats.config.symbol})`, active:'active'}); - $('#blocksTabs').append(rendered) - + let rendered = Mustache.render(template, { + coin: lastStats.config.coin, + symbol: `(${lastStats.config.symbol})`, + active: 'active' + }); + $('#blocksTabs') + .append(rendered) + poolBlocks_Setup(api, lastStats, xhrGetBlocks) } - - + poolBlocks_updateStats(lastStats, coin) +/* updateText(`blocksTotal${coin}`, lastStats.pool.totalBlocks.toString()); if (lastStats.pool.lastBlockFound) { - var d = new Date(parseInt(lastStats.pool.lastBlockFound)).toISOString(); - $(`#lastBlockFound${coin}`).timeago('update', d); - } - else { - $(`#lastBlockFound${coin}`).removeAttr('title').data('ts', '').update('Never'); + var d = new Date(parseInt(lastStats.pool.lastBlockFound)) + .toISOString(); + $(`#lastBlockFound${coin}`) + .timeago('update', d); + } else { + $(`#lastBlockFound${coin}`) + .removeAttr('title') + .data('ts', '') + .update('Never'); } updateText(`blocksTotalSolo${coin}`, lastStats.pool.totalBlocksSolo.toString()); if (lastStats.pool.lastBlockFoundSolo) { - var d = new Date(parseInt(lastStats.pool.lastBlockFoundSolo)).toISOString(); - $(`#lastBlockFoundSolo${coin}`).timeago('update', d); - } - else { - $(`#lastBlockFoundSolo${coin}`).removeAttr('title').data('ts', '').update('Never'); + var d = new Date(parseInt(lastStats.pool.lastBlockFoundSolo)) + .toISOString(); + $(`#lastBlockFoundSolo${coin}`) + .timeago('update', d); + } else { + $(`#lastBlockFoundSolo${coin}`) + .removeAttr('title') + .data('ts', '') + .update('Never'); } updateText(`blocksMaturityCount${coin}`, lastStats.config.depth.toString()); - $(`#averageLuck${coin}`).html(formatLuck(lastStats.pool.totalDiff, lastStats.pool.totalShares)); + $(`#averageLuck${coin}`) + .html(`PROP: ${formatLuck(lastStats.pool.totalDiff, lastStats.pool.totalShares)}`); + $(`#averageLuckSolo${coin}`) + .html(`SOLO: ${formatLuck(lastStats.pool.totalDiffSolo, lastStats.pool.totalSharesSolo)}`); +*/ displayedChart[lastStats.config.coin] = false if (lastStats.charts.blocks) { - poolBlocks_GenerateChart(lastStats, displayedChart); + poolBlocks_GenerateChart(lastStats, displayedChart); } poolBlocks_RenderBlocks(lastStats.pool.blocks, lastStats); - Object.keys(mergedStats).forEach(key => { - if ($(`#blocksTabs li:contains(${key})`).length == 0) { - let template1 = $('#siblingTemplate').html() - Mustache.parse(template1) - let rendered1 = Mustache.render(template1, {coin:key}) - $('#tab-content').append(rendered1) + Object.keys(mergedStats) + .forEach(key => { + if ($(`#blocksTabs li:contains(${key})`) + .length == 0) { + let template1 = $('#siblingTemplate') + .html() + Mustache.parse(template1) + let rendered1 = Mustache.render(template1, { + coin: key + }) + $('#tab-content') + .append(rendered1) - let template = $('#siblingTabTemplate').html(); - Mustache.parse(template) - let rendered = Mustache.render(template, {coin:key, symbol:`(${mergedStats[key].config.symbol})`}); - $('#blocksTabs').append(rendered) + let template = $('#siblingTabTemplate') + .html(); + Mustache.parse(template) + let rendered = Mustache.render(template, { + coin: key, + symbol: `(${mergedStats[key].config.symbol})` + }); + $('#blocksTabs') + .append(rendered) - poolBlocks_Setup(mergedApis[key].api, mergedStats[key]) - } + poolBlocks_Setup(mergedApis[key].api, mergedStats[key]) + } +/* + updateText(`blocksTotal${key}`, mergedStats[key].pool.totalBlocks.toString()); + if (mergedStats[key].pool.lastBlockFound) { + var d = new Date(parseInt(mergedStats[key].pool.lastBlockFound)) + .toISOString(); + $(`#lastBlockFound${key}`) + .timeago('update', d); + } else { + $(`#lastBlockFound${key}`) + .removeAttr('title') + .data('ts', '') + .update('Never'); + } - updateText(`blocksTotal${key}`, mergedStats[key].pool.totalBlocks.toString()); - if (mergedStats[key].pool.lastBlockFound) { - var d = new Date(parseInt(mergedStats[key].pool.lastBlockFound)).toISOString(); - $(`#lastBlockFound${key}`).timeago('update', d); - } - else { - $(`#lastBlockFound${key}`).removeAttr('title').data('ts', '').update('Never'); - } + updateText(`blocksTotalSolo${key}`, mergedStats[key].pool.totalBlocksSolo.toString()); + if (mergedStats[key].pool.lastBlockFoundSolo) { + var d = new Date(parseInt(mergedStats[key].pool.lastBlockFoundSolo)) + .toISOString(); + $(`#lastBlockFoundSolo${key}`) + .timeago('update', d); + } else { + $(`#lastBlockFoundSolo${key}`) + .removeAttr('title') + .data('ts', '') + .update('Never'); + } - updateText(`blocksTotalSolo${key}`, mergedStats[key].pool.totalBlocksSolo.toString()); - if (mergedStats[key].pool.lastBlockFoundSolo) { - var d = new Date(parseInt(mergedStats[key].pool.lastBlockFoundSolo)).toISOString(); - $(`#lastBlockFoundSolo${key}`).timeago('update', d); - } - else { - $(`#lastBlockFoundSolo${key}`).removeAttr('title').data('ts', '').update('Never'); - } + updateText(`blocksMaturityCount${key}`, mergedStats[key].config.depth.toString()); - updateText(`blocksMaturityCount${key}`, mergedStats[key].config.depth.toString()); - - $(`#averageLuck${key}`).html(formatLuck(mergedStats[key].pool.totalDiff, mergedStats[key].pool.totalShares)); - displayedChart[key] = false - if (mergedStats[key].charts.blocks) { - poolBlocks_GenerateChart(mergedStats[key], displayedChart); - } - poolBlocks_RenderBlocks(mergedStats[key].pool.blocks, mergedStats[key]); - }) + $(`#averageLuck${key}`) + .html(formatLuck(mergedStats[key].pool.totalDiff, mergedStats[key].pool.totalShares)); + $(`#averageLuckSolo${key}`) + .html(formatLuck(mergedStats[key].pool.totalDiffSolo, mergedStats[key].pool.totalSharesSolo)); +*/ + displayedChart[key] = false + if (mergedStats[key].charts.blocks) { + poolBlocks_GenerateChart(mergedStats[key], displayedChart); + } + poolBlocks_RenderBlocks(mergedStats[key].pool.blocks, mergedStats[key]); + }) sortElementList($(`#blocksTabs`), $(`#blocksTabs>div`), mergedStats) - if (!ranOnce) + if (!ranOnce) ranOnce = RunOnce() } @@ -782,73 +952,103 @@ top10miners methods *************************************************************** */ -function top10Miners_GetMinerCells(position, data){ +function top10Miners_GetMinerCells (position, data) { var miner = data.miner; var hashrate = data.hashrate ? data.hashrate : 0; var lastShare = data.lastShare ? data.lastShare : 0; - var hashes = (data.hashes || 0).toString(); - + var hashes = (data.hashes || 0) + .toString(); + return '' + position + '' + - '' + miner + '' + - '' + getReadableHashRateString(hashrate) + '/sec' + - '' + (lastShare ? $.timeago(new Date(parseInt(lastShare) * 1000).toISOString()) : 'Never') + '' + - '' + hashes + ''; + '' + miner + '' + + '' + getReadableHashRateString(hashrate) + '/sec' + + '' + (lastShare ? $.timeago(new Date(parseInt(lastShare) * 1000) + .toISOString()) : 'Never') + '' + + '' + hashes + ''; } // Update top10 miners report -function top10Miners_UpdateTop10(xhrGetMiners, endPoint, key) { +function top10Miners_UpdateTop10 (xhrGetMiners, endPoint, key) { if (xhrGetMiners[key]) xhrGetMiners[key].abort() - $( `#top10miners_rows${key}`).empty(); + $(`#top10miners_rows${key}`) + .empty(); xhrGetMiners[key] = $.ajax({ url: `${endPoint}/get_top10miners`, data: { - time: $(`#top10_rows${key}`).children().last().data('time') + time: $(`#top10_rows${key}`) + .children() + .last() + .data('time') }, dataType: 'json', cache: 'false', - success: function(data){ + success: function (data) { if (!data) return; - for (var i=0; i' + top10Miners_GetMinerCells(i+1, data[i]) + ''); + for (var i = 0; i < data.length; ++i) { + $(`#top10miners_rows${key}`) + .append('' + top10Miners_GetMinerCells(i + 1, data[i]) + ''); } } }); } -function top10Miners_InitTemplate(xhrGetMiners, ranOnce) { +function top10Miners_InitTemplate (xhrGetMiners, ranOnce) { let coin = lastStats.config.coin - if ($(`#blocksTabs li:contains(${coin})`).length === 0) { - let template = $('#siblingTabTemplate').html(); - Mustache.parse(template) - let rendered = Mustache.render(template, {coin:lastStats.config.coin, symbol:`(${lastStats.config.symbol})`, active: 'active'}); - $('#blocksTabs').append(rendered) + if ($(`#blocksTabs li:contains(${coin})`) + .length === 0) { + let template = $('#siblingTabTemplate') + .html(); + Mustache.parse(template) + let rendered = Mustache.render(template, { + coin: lastStats.config.coin, + symbol: `(${lastStats.config.symbol})`, + active: 'active' + }); + $('#blocksTabs') + .append(rendered) - template = $('#siblingTemplate').html() - Mustache.parse(template) - rendered = Mustache.render(template, {coin:coin, active: 'active'}) - $('#tab-content').append(rendered) + template = $('#siblingTemplate') + .html() + Mustache.parse(template) + rendered = Mustache.render(template, { + coin: coin, + active: 'active' + }) + $('#tab-content') + .append(rendered) } top10Miners_UpdateTop10(xhrGetMiners, api, coin); - Object.keys(mergedStats).forEach(key => { - if ($(`#blocksTabs li:contains(${key})`).length === 0) { - coin = key - let template = $('#siblingTabTemplate').html(); - Mustache.parse(template) - let rendered = Mustache.render(template, {coin:mergedStats[key].config.coin, symbol:`(${mergedStats[key].config.symbol})`}); - $('#blocksTabs').append(rendered) + Object.keys(mergedStats) + .forEach(key => { + if ($(`#blocksTabs li:contains(${key})`) + .length === 0) { + coin = key + let template = $('#siblingTabTemplate') + .html(); + Mustache.parse(template) + let rendered = Mustache.render(template, { + coin: mergedStats[key].config.coin, + symbol: `(${mergedStats[key].config.symbol})` + }); + $('#blocksTabs') + .append(rendered) - template = $('#siblingTemplate').html() - Mustache.parse(template) - rendered = Mustache.render(template, {coin:coin}) - $('#tab-content').append(rendered) - } - top10Miners_UpdateTop10(xhrGetMiners, mergedApis[key].api, key); - }) + template = $('#siblingTemplate') + .html() + Mustache.parse(template) + rendered = Mustache.render(template, { + coin: coin + }) + $('#tab-content') + .append(rendered) + } + top10Miners_UpdateTop10(xhrGetMiners, mergedApis[key].api, key); + }) sortElementList($(`#blocksTabs`), $(`#blocksTabs>li`), mergedStats) if (!ranOnce) ranOnce = RunOnce() @@ -860,72 +1060,98 @@ settings methods *************************************************************** */ -function settings_Setup(api, stats) { +function settings_Setup (api, stats) { var address = getCurrentAddress(stats.config.coin); - if (address){ - $(`#yourAddress${stats.config.coin}`).val(address); + if (address) { + $(`#yourAddress${stats.config.coin}`) + .val(address); settings_GetPayoutLevel(api, address, stats); settings_GetEmailAddress(api, address, stats); } // Handle click on Set button - $(`#payoutSetButton${stats.config.coin}`).click(function(){ - var address = $(`#yourAddress${stats.config.coin}`).val().trim(); - if (!address || address == '') { - settings_ShowError('noMinerAddress', 'No miner address specified', '', false); - return; - } + $(`#payoutSetButton${stats.config.coin}`) + .click(function () { + var address = $(`#yourAddress${stats.config.coin}`) + .val() + .trim(); + if (!address || address == '') { + settings_ShowError('noMinerAddress', 'No miner address specified', '', false); + return; + } - var ip = $(`#yourIP${stats.config.coin}`).val().trim(); - if (!ip || ip == '') { - settings_ShowError('noMinerIP', 'No miner IP address specified', '', false); - return; - } + var ip = $(`#yourIP${stats.config.coin}`) + .val() + .trim(); + if (!ip || ip == '') { + settings_ShowError('noMinerIP', 'No miner IP address specified', '', false); + return; + } - var level = $(`#yourPayoutRate${stats.config.coin}`).val().trim(); - if (!level || level < 0) { - settings_ShowError('noPayoutLevel', 'No payout level specified', '', false); - return; - } - settings_SetPayoutLevel(api, address, ip, level, stats); - }); + var level = $(`#yourPayoutRate${stats.config.coin}`) + .val() + .trim(); + if (!level || level < 0) { + settings_ShowError('noPayoutLevel', 'No payout level specified', '', false); + return; + } + settings_SetPayoutLevel(api, address, ip, level, stats); + }); // Handle click on Enable button - $(`#enableButton${stats.config.coin}`).click(function(){ - var address = $(`#yourAddress${stats.config.coin}`).val().trim(); - var ip = $(`#yourIP${stats.config.coin}`).val().trim(); - var email = $(`#yourEmail${stats.config.coin}`).val(); - settings_SetEmailNotifications(stats, api, email, address, ip, true); - }); + $(`#enableButton${stats.config.coin}`) + .click(function () { + var address = $(`#yourAddress${stats.config.coin}`) + .val() + .trim(); + var ip = $(`#yourIP${stats.config.coin}`) + .val() + .trim(); + var email = $(`#yourEmail${stats.config.coin}`) + .val(); + settings_SetEmailNotifications(stats, api, email, address, ip, true); + }); // Handle click on Disable button - $(`#disableButton${stats.config.coin}`).click(function(){ - var address = $(`#yourAddress${stats.config.coin}`).val().trim(); - var ip = $(`#yourIP${stats.config.coin}`).val().trim(); - var email = $(`#yourEmail${stats.config.coin}`).val(); - settings_SetEmailNotifications(stats, api, email, address, ip, false); - }); + $(`#disableButton${stats.config.coin}`) + .click(function () { + var address = $(`#yourAddress${stats.config.coin}`) + .val() + .trim(); + var ip = $(`#yourIP${stats.config.coin}`) + .val() + .trim(); + var email = $(`#yourEmail${stats.config.coin}`) + .val(); + settings_SetEmailNotifications(stats, api, email, address, ip, false); + }); } /** * Error Message **/ -function settings_ShowError(id, message, extra, stats) { +function settings_ShowError (id, message, extra, stats) { if (getTranslation(id)) message = getTranslation(id); message = message.trim(); if (extra) message += ' ' + extra; - $(`#action_update_message${stats.config.coin}`).text(message); - $(`#action_update_message${stats.config.coin}`).removeClass().addClass('alert alert-danger'); + $(`#action_update_message${stats.config.coin}`) + .text(message); + $(`#action_update_message${stats.config.coin}`) + .removeClass() + .addClass('alert alert-danger'); } /** * Success Message **/ -function settings_ShowSuccess(id, message, stats) { +function settings_ShowSuccess (id, message, stats) { if (getTranslation(id)) message = getTranslation(id); - $(`#action_update_message${stats.config.coin}`).text(message); - $(`#action_update_message${stats.config.coin}`).removeClass().addClass('alert alert-success'); + $(`#action_update_message${stats.config.coin}`) + .text(message); + $(`#action_update_message${stats.config.coin}`) + .removeClass() + .addClass('alert alert-success'); } /** @@ -933,42 +1159,45 @@ function settings_ShowSuccess(id, message, stats) { **/ // Get current payout level -function settings_GetPayoutLevel(api, address, stats) { - if (!address || address == '') +function settings_GetPayoutLevel (api, address, stats) { + if (!address || address == '') return; $.ajax({ - url: `${api}/get_miner_payout_level`, - data: { - address: address - }, - dataType: 'json', - cache: 'false' - }).done(function(data){ - if (data.level != undefined) { - $(`#yourPayoutRate${stats.config.coin}`).val(data.level); - } - }); -} + url: `${api}/get_miner_payout_level`, + data: { + address: address + }, + dataType: 'json', + cache: 'false' + }) + .done(function (data) { + if (data.level != undefined) { + $(`#yourPayoutRate${stats.config.coin}`) + .val(data.level); + } + }); +} // Set payout level -function settings_SetPayoutLevel(api, address, ip, level, stats) { +function settings_SetPayoutLevel (api, address, ip, level, stats) { let params = { - address: address, - ip: ip, - level: level - } + address: address, + ip: ip, + level: level + } $.ajax({ - url: `${api}/set_miner_payout_level`, - data: params, - dataType: 'json', - cache: 'false' - }).done(function(data){ - if (data.status == 'done') { - settings_ShowSuccess('minerPayoutSet', 'Done! Your minimum payout level was set', stats); - } else { - settings_ShowError('Error:', data.status, null, stats); - } - }); + url: `${api}/set_miner_payout_level`, + data: params, + dataType: 'json', + cache: 'false' + }) + .done(function (data) { + if (data.status == 'done') { + settings_ShowSuccess('minerPayoutSet', 'Done! Your minimum payout level was set', stats); + } else { + settings_ShowError('Error:', data.status, null, stats); + } + }); } /** @@ -976,44 +1205,52 @@ function settings_SetPayoutLevel(api, address, ip, level, stats) { **/ // Check if specified value is a valid email -function settings_IsEmail(email) { +function settings_IsEmail (email) { var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/; return regex.test(email); } // Get current email address for notifications -function settings_GetEmailAddress(endPoint, address, stats) { +function settings_GetEmailAddress (endPoint, address, stats) { if (!address || address == '') return; - + $.ajax({ - url: `${endPoint}/get_email_notifications`, - data: { - address: address - }, - dataType: 'json', - cache: 'false' - }).done(function(data){ - if (data.email != undefined) { - $(`#yourEmail${stats.config.coin}`).val(data.email); - } - }); + url: `${endPoint}/get_email_notifications`, + data: { + address: address + }, + dataType: 'json', + cache: 'false' + }) + .done(function (data) { + if (data.email != undefined) { + $(`#yourEmail${stats.config.coin}`) + .val(data.email); + } + }); } - + // Set email address for notifications -function settings_SetEmailNotifications(stats, endPoint, email, address, ip, enable) { - var address = $(`#yourAddress${stats.config.coin}`).val().trim(); +function settings_SetEmailNotifications (stats, endPoint, email, address, ip, enable) { + var address = $(`#yourAddress${stats.config.coin}`) + .val() + .trim(); if (!address || address == '') { settings_ShowError('noMinerAddress', 'No miner address specified', null, stats); return; } - var ip = $(`#yourIP${stats.config.coin}`).val().trim(); + var ip = $(`#yourIP${stats.config.coin}`) + .val() + .trim(); if (!ip || ip == '') { settings_ShowError('noMinerIP', 'No miner IP address specified', null, stats); return; } - var email = $(`#yourEmail${stats.config.coin}`).val().trim(); + var email = $(`#yourEmail${stats.config.coin}`) + .val() + .trim(); if (enable && !email) { settings_ShowError('noEmail', 'No email address specified', null, stats); return; @@ -1024,65 +1261,91 @@ function settings_SetEmailNotifications(stats, endPoint, email, address, ip, ena } $.ajax({ - url: `${endPoint}/set_email_notifications`, - data: { - address: address, - ip: ip, - email: email, - action: enable ? 'enable' : 'disable' - }, - dataType: 'json', - cache: 'false' - }).done(function(data){ - if (data.status == "done") { - if (enable) { - settings_ShowSuccess('notificationEnabled', 'Done! Email notifications have been enabled', stats); - } else { - settings_ShowSuccess('notificationDisabled', 'Done! Email notifications have been disabled', stats); + url: `${endPoint}/set_email_notifications`, + data: { + address: address, + ip: ip, + email: email, + action: enable ? 'enable' : 'disable' + }, + dataType: 'json', + cache: 'false' + }) + .done(function (data) { + if (data.status == "done") { + if (enable) { + settings_ShowSuccess('notificationEnabled', 'Done! Email notifications have been enabled', stats); + } else { + settings_ShowSuccess('notificationDisabled', 'Done! Email notifications have been disabled', stats); + } + } else { + settings_ShowError('error', 'Error:', data.status, stats); } - } else { - settings_ShowError('error', 'Error:', data.status, stats); - } - }); + }); } -function settings_InitTemplate(ranOnce) { - if (!lastStats.config.sendEmails) $(`#emailNotifications${lastStats.config.coin}`).hide(); +function settings_InitTemplate (ranOnce) { + if (!lastStats.config.sendEmails) $(`#emailNotifications${lastStats.config.coin}`) + .hide(); let coin = lastStats.config.coin - let template = $('#siblingTemplate').html() - if ($(`#blocksTabs li:contains(${coin})`).length === 0) { + let template = $('#siblingTemplate') + .html() + if ($(`#blocksTabs li:contains(${coin})`) + .length === 0) { Mustache.parse(template) - let rendered = Mustache.render(template, {coin:coin, active:'active'}) - $('#tab-content').append(rendered) + let rendered = Mustache.render(template, { + coin: coin, + active: 'active' + }) + $('#tab-content') + .append(rendered) - template = $('#siblingTabTemplate').html(); + template = $('#siblingTabTemplate') + .html(); Mustache.parse(template) - rendered = Mustache.render(template, {coin:lastStats.config.coin, symbol:`(${lastStats.config.symbol})`, active:'active'}); - $('#blocksTabs').append(rendered) + rendered = Mustache.render(template, { + coin: lastStats.config.coin, + symbol: `(${lastStats.config.symbol})`, + active: 'active' + }); + $('#blocksTabs') + .append(rendered) settings_Setup(api, lastStats) } - Object.keys(mergedStats).forEach(key => { - if ($(`#blocksTabs li:contains(${key})`).length === 0) { - if (!mergedStats[key].config.sendEmails) - $(`#emailNotifications${mergedStats[key].config.coin}`).hide(); - template = $('#siblingTemplate').html() - Mustache.parse(template) - let rendered = Mustache.render(template, {coin:key}) - $('#tab-content').append(rendered) + Object.keys(mergedStats) + .forEach(key => { + if ($(`#blocksTabs li:contains(${key})`) + .length === 0) { + if (!mergedStats[key].config.sendEmails) + $(`#emailNotifications${mergedStats[key].config.coin}`) + .hide(); + template = $('#siblingTemplate') + .html() + Mustache.parse(template) + let rendered = Mustache.render(template, { + coin: key + }) + $('#tab-content') + .append(rendered) - template = $('#siblingTabTemplate').html(); - Mustache.parse(template) - rendered = Mustache.render(template, {coin:key, symbol:`(${mergedStats[key].config.symbol})`}); - $('#blocksTabs').append(rendered) + template = $('#siblingTabTemplate') + .html(); + Mustache.parse(template) + rendered = Mustache.render(template, { + coin: key, + symbol: `(${mergedStats[key].config.symbol})` + }); + $('#blocksTabs') + .append(rendered) - settings_Setup(mergedApis[key].api, mergedStats[key]) - } - }) + settings_Setup(mergedApis[key].api, mergedStats[key]) + } + }) sortElementList($(`#blocksTabs`), $(`#blocksTabs>li`), mergedStats) - if (!ranOnce) - ranOnce = RunOnce() + if (!ranOnce) + ranOnce = RunOnce() } /* @@ -1092,7 +1355,7 @@ payments methods */ // Parse payment data -function payments_ParsePayment(time, serializedPayment){ +function payments_ParsePayment (time, serializedPayment) { var parts = serializedPayment.split(':'); return { time: parseInt(time), @@ -1105,17 +1368,17 @@ function payments_ParsePayment(time, serializedPayment){ } // Get payment cells -function payments_GetPaymentCells(payment, stats){ +function payments_GetPaymentCells (payment, stats) { return '' + formatDate(payment.time) + '' + - '' + formatPaymentLink(payment.hash, stats) + '' + - '' + (getReadableCoin(stats, payment.amount)) + '' + - '' + (getReadableCoin(stats, payment.fee)) + '' + - '' + payment.mixin + '' + - '' + payment.recipients + ''; + '' + formatPaymentLink(payment.hash, stats) + '' + + '' + (getReadableCoin(stats, payment.amount)) + '' + + '' + (getReadableCoin(stats, payment.fee)) + '' + + '' + payment.mixin + '' + + '' + payment.recipients + ''; } // Get payment row element -function payments_GetPaymentRowElement(payment, jsonString, stats){ +function payments_GetPaymentRowElement (payment, jsonString, stats) { var row = document.createElement('tr'); row.setAttribute(`data-json`, jsonString); row.setAttribute(`data-time`, payment.time); @@ -1127,26 +1390,28 @@ function payments_GetPaymentRowElement(payment, jsonString, stats){ } // Render payments data -function payments_renderPayments(paymentsResults, stats){ +function payments_renderPayments (paymentsResults, stats) { var $paymentsRows = $(`#paymentsReport${stats.config.coin}_rows`); - for (var i = 0; i < paymentsResults.length; i += 2){ + for (var i = 0; i < paymentsResults.length; i += 2) { var payment = payments_ParsePayment(paymentsResults[i + 1], paymentsResults[i]); var paymentJson = JSON.stringify(payment); var existingRow = document.getElementById(`paymentRow${stats.config.coin}${payment.time}`); - if (existingRow && existingRow.getAttribute(`data-json`) !== paymentJson){ - $(existingRow).replaceWith(payments_GetPaymentRowElement(payment, paymentJson, stats)); - } - else if (!existingRow){ + if (existingRow && existingRow.getAttribute(`data-json`) !== paymentJson) { + $(existingRow) + .replaceWith(payments_GetPaymentRowElement(payment, paymentJson, stats)); + } else if (!existingRow) { var paymentElement = payments_GetPaymentRowElement(payment, paymentJson, stats); var inserted = false; - var rows = $paymentsRows.children().get(); + var rows = $paymentsRows.children() + .get(); for (var f = 0; f < rows.length; f++) { var pTime = parseInt(rows[f].getAttribute(`data-time`)); - if (pTime < payment.time){ + if (pTime < payment.time) { inserted = true; - $(rows[f]).before(paymentElement); + $(rows[f]) + .before(paymentElement); break; } } @@ -1158,71 +1423,98 @@ function payments_renderPayments(paymentsResults, stats){ } // Load more payments button -function payments_Setup(xhrGetPayments, api, stats) { - $(`#loadMorePayments${stats.config.coin}`).click(function(){ - if (xhrGetPayments[stats.config.coin]) xhrGetPayments[stats.config.coin].abort(); - xhrGetPayments[stats.config.coin] = $.ajax({ - url: api + '/get_payments', - data: { - time: $(`#paymentsReport${stats.config.coin}_rows`).children().last().data(`time`) - }, - dataType: 'json', - cache: 'false', - success: function(data){ - payments_renderPayments(data, stats); - } - }); - }); +function payments_Setup (xhrGetPayments, api, stats) { + $(`#loadMorePayments${stats.config.coin}`) + .click(function () { + if (xhrGetPayments[stats.config.coin]) xhrGetPayments[stats.config.coin].abort(); + xhrGetPayments[stats.config.coin] = $.ajax({ + url: api + '/get_payments', + data: { + time: $(`#paymentsReport${stats.config.coin}_rows`) + .children() + .last() + .data(`time`) + }, + dataType: 'json', + cache: 'false', + success: function (data) { + payments_renderPayments(data, stats); + } + }); + }); } -function payments_InitTemplate(xhrGetPayments, ranOnce) { - let coin = lastStats.config.coin - if ($(`#blocksTabs li:contains(${coin})`).length === 0) { - let template1 = $('#siblingTemplate').html() - Mustache.parse(template1) - let rendered1 = Mustache.render(template1, {coin:coin, active:'active'}) - $('#tab-content').append(rendered1) - - let template = $('#siblingTabTemplate').html(); - Mustache.parse(template) - let rendered = Mustache.render(template, {coin:lastStats.config.coin, symbol:`(${lastStats.config.symbol})`, active:'active'}); - $('#blocksTabs').append(rendered) - - payments_Setup(xhrGetPayments, api, lastStats) - } - updateText(`paymentsTotal${coin}`, lastStats.pool.totalPayments.toString()); - updateText(`paymentsTotalPaid${coin}`, lastStats.pool.totalMinersPaid.toString()); - updateText(`paymentsInterval${coin}`, getReadableTime(lastStats.config.paymentsInterval)); - updateText(`paymentsMinimum${coin}`, getReadableCoin(lastStats, lastStats.config.minPaymentThreshold)); - updateText(`paymentsDenomination${coin}`, getReadableCoin(lastStats, lastStats.config.denominationUnit, 3)); - payments_renderPayments(lastStats.pool.payments, lastStats); - - Object.keys(mergedStats).forEach(key => { - if ($(`#blocksTabs li:contains(${key})`).length === 0) { - - let template1 = $('#siblingTemplate').html() - Mustache.parse(template1) - let rendered1 = Mustache.render(template1, {coin:key}) - $('#tab-content').append(rendered1) - - let template = $('#siblingTabTemplate').html(); - Mustache.parse(template) - let rendered = Mustache.render(template, {coin:key, symbol:`(${mergedStats[key].config.symbol})`}); - $('#blocksTabs').append(rendered) - - payments_Setup(xhrGetPayments, mergedApis[key].api, mergedStats[key]) - } - - updateText(`paymentsTotal${key}`, mergedStats[key].pool.totalPayments.toString()); - updateText(`paymentsTotalPaid${key}`, mergedStats[key].pool.totalMinersPaid.toString()); - updateText(`paymentsInterval${key}`, getReadableTime(mergedStats[key].config.paymentsInterval)); - updateText(`paymentsMinimum${key}`, getReadableCoin(mergedStats[key], mergedStats[key].config.minPaymentThreshold)); - updateText(`paymentsDenomination${key}`, getReadableCoin(mergedStats[key], mergedStats[key].config.denominationUnit, 3)); - payments_renderPayments(mergedStats[key].pool.payments, mergedStats[key]); +function payments_InitTemplate (xhrGetPayments, ranOnce) { + let coin = lastStats.config.coin + if ($(`#blocksTabs li:contains(${coin})`) + .length === 0) { + let template1 = $('#siblingTemplate') + .html() + Mustache.parse(template1) + let rendered1 = Mustache.render(template1, { + coin: coin, + active: 'active' }) - sortElementList($(`#blocksTabs`), $(`#blocksTabs>li`), mergedStats) - if (!ranOnce) - ranOnce = RunOnce() + $('#tab-content') + .append(rendered1) + + let template = $('#siblingTabTemplate') + .html(); + Mustache.parse(template) + let rendered = Mustache.render(template, { + coin: lastStats.config.coin, + symbol: `(${lastStats.config.symbol})`, + active: 'active' + }); + $('#blocksTabs') + .append(rendered) + + payments_Setup(xhrGetPayments, api, lastStats) + } + updateText(`paymentsTotal${coin}`, lastStats.pool.totalPayments.toString()); + updateText(`paymentsTotalPaid${coin}`, lastStats.pool.totalMinersPaid.toString()); + updateText(`paymentsInterval${coin}`, getReadableTime(lastStats.config.paymentsInterval)); + updateText(`paymentsMinimum${coin}`, getReadableCoin(lastStats, lastStats.config.minPaymentThreshold)); + updateText(`paymentsDenomination${coin}`, getReadableCoin(lastStats, lastStats.config.denominationUnit, 3)); + payments_renderPayments(lastStats.pool.payments, lastStats); + + Object.keys(mergedStats) + .forEach(key => { + if ($(`#blocksTabs li:contains(${key})`) + .length === 0) { + + let template1 = $('#siblingTemplate') + .html() + Mustache.parse(template1) + let rendered1 = Mustache.render(template1, { + coin: key + }) + $('#tab-content') + .append(rendered1) + + let template = $('#siblingTabTemplate') + .html(); + Mustache.parse(template) + let rendered = Mustache.render(template, { + coin: key, + symbol: `(${mergedStats[key].config.symbol})` + }); + $('#blocksTabs') + .append(rendered) + + payments_Setup(xhrGetPayments, mergedApis[key].api, mergedStats[key]) + } + + updateText(`paymentsTotal${key}`, mergedStats[key].pool.totalPayments.toString()); + updateText(`paymentsTotalPaid${key}`, mergedStats[key].pool.totalMinersPaid.toString()); + updateText(`paymentsInterval${key}`, getReadableTime(mergedStats[key].config.paymentsInterval)); + updateText(`paymentsMinimum${key}`, getReadableCoin(mergedStats[key], mergedStats[key].config.minPaymentThreshold)); + updateText(`paymentsDenomination${key}`, getReadableCoin(mergedStats[key], mergedStats[key].config.denominationUnit, 3)); + payments_renderPayments(mergedStats[key].pool.payments, mergedStats[key]); + }) + sortElementList($(`#blocksTabs`), $(`#blocksTabs>li`), mergedStats) + if (!ranOnce) + ranOnce = RunOnce() } /* @@ -1231,43 +1523,49 @@ market methods *************************************************************** */ -function market_LoadMarketData(api, stats, loadedData, currencyPairs, xhrMarketGets, marketPrices) { - if (loadedData[stats.config.coin]) return ; - - if (typeof marketCurrencies !== 'undefined' && marketCurrencies.length > 0){ +function market_LoadMarketData (api, stats, loadedData, currencyPairs, xhrMarketGets, marketPrices) { + if (loadedData[stats.config.coin]) return; + + if (typeof marketCurrencies !== 'undefined' && marketCurrencies.length > 0) { let intervalMarketPolling = setInterval(market_UpdateMarkets(api, stats, currencyPairs, xhrMarketGets, marketPrices), 300000); market_UpdateMarkets(api, stats, currencyPairs, xhrMarketGets, marketPrices); } else { - $(`#marketInfos${stats.config.coin}`).hide(); + $(`#marketInfos${stats.config.coin}`) + .hide(); } - + loadedData[stats.config.coin] = true; } - + // Market data polling (poll data every 5 minutes) -function market_UpdateMarkets(api, stats, currencyPairs, xhrMarketGets, marketPrices){ - if (typeof marketCurrencies === 'undefined' || marketCurrencies.length === 0) return ; - +function market_UpdateMarkets (api, stats, currencyPairs, xhrMarketGets, marketPrices) { + if (typeof marketCurrencies === 'undefined' || marketCurrencies.length === 0) return; + currencyPairs[stats.config.coin] = [] - for (let i = 0; i < marketCurrencies.length; i++){ - currencyPairs[stats.config.coin].push(marketCurrencies[i].replace('{symbol}', stats.config.symbol).toUpperCase()); + for (let i = 0; i < marketCurrencies.length; i++) { + currencyPairs[stats.config.coin].push(marketCurrencies[i].replace('{symbol}', stats.config.symbol) + .toUpperCase()); } if (xhrMarketGets[stats.config.coin]) xhrMarketGets[stats.config.coin].abort() xhrMarketGets[stats.config.coin] = $.ajax({ url: api + '/get_market', - data: { tickers: currencyPairs[stats.config.coin] }, + data: { + tickers: currencyPairs[stats.config.coin] + }, dataType: 'json', cache: 'false', - success: function(data) { + success: function (data) { if (!data || data.length === 0) { - $(`#marketInfos${stats.config.coin}`).hide(); + $(`#marketInfos${stats.config.coin}`) + .hide(); return; } - $(`#marketInfos${stats.config.coin}`).empty(); + $(`#marketInfos${stats.config.coin}`) + .empty(); for (let i in data) { if (!data[i] || !data[i].ticker) continue; let ticker = data[i].ticker; @@ -1275,23 +1573,25 @@ function market_UpdateMarkets(api, stats, currencyPairs, xhrMarketGets, marketPr let tickerBase = tickerParts[0] || null; let tickerTarget = tickerParts[1] || null; - let price = data[i].price; + let price = data[i].price; if (!price || price === 0) continue; let dataSource = data[i].source; market_RenderMarketPrice(tickerBase, tickerTarget, price, dataSource, stats, marketPrices); } - $(`#marketInfos${stats.config.coin}`).show(); - }, - error: function() { - $(`#marketInfos${stats.config.coin}`).hide(); + $(`#marketInfos${stats.config.coin}`) + .show(); + }, + error: function () { + $(`#marketInfos${stats.config.coin}`) + .hide(); } }); } // Render market price -function market_RenderMarketPrice(base, target, price, source, stats, marketPrices) { +function market_RenderMarketPrice (base, target, price, source, stats, marketPrices) { let icon = 'fa-money'; if (target == 'BTC') icon = 'fa-btc'; if (target == 'BCH') icon = 'fa-btc'; @@ -1300,12 +1600,13 @@ function market_RenderMarketPrice(base, target, price, source, stats, marketPric if (target == 'EUR') icon = 'fa-eur'; if (target == 'GBP') icon = 'fa-gbp'; if (target == 'JPY') icon = 'fa-jpy'; - + if (target == 'CNY') icon = 'fa-jpy'; + if (base == stats.config.symbol.toUpperCase()) { marketPrices[stats.config.coin][target] = price; } - if (target == 'USD' || target == 'CAD' || target == 'EUR' || target == 'GBP' || target == 'JPY') { + if (target == 'USD' || target == 'CAD' || target == 'EUR' || target == 'GBP' || target == 'JPY') { price = price.toFixed(4); } else { price = price.toFixed(8); @@ -1319,19 +1620,21 @@ function market_RenderMarketPrice(base, target, price, source, stats, marketPric else if (source == 'stocks.exchange') sourceURL = 'https://stocks.exchange/'; else if (source == 'tradeogre') sourceURL = 'https://tradeogre.com/'; - source = source.charAt(0).toUpperCase() + source.slice(1); - if (sourceURL) source = ''+source+''; + source = source.charAt(0) + .toUpperCase() + source.slice(1); + if (sourceURL) source = '' + source + ''; - $(`#marketInfos${stats.config.coin}`).append( - '
' + - '
' + - '
' + - '
' + base + ' to ' + target + '
' + - '
' + price + '
' + - '
Source: ' + source + '
' + - '
' + - '
' - ); + $(`#marketInfos${stats.config.coin}`) + .append( + '
' + + '
' + + '
' + + '
' + base + ' to ' + target + '
' + + '
' + price + '
' + + '
Source: ' + source + '
' + + '
' + + '
' + ); } /** @@ -1339,18 +1642,20 @@ function market_RenderMarketPrice(base, target, price, source, stats, marketPric **/ // Create charts -function market_CreateCharts(stats) { - if (!stats || !stats.charts) return ; +function market_CreateCharts (stats) { + if (!stats || !stats.charts) return; let data = stats.charts; let graphData = { price: market_GetGraphData(data.price), profit: market_GetGraphData(data.profit) }; - for(let graphType in graphData) { + for (let graphType in graphData) { if (graphData[graphType].values.length > 1) { - let $chart = $(`#chart${stats.config.coin}_${graphType}`); - let bgcolor = null, bordercolor = null, borderwidth = null; + let $chart = $(`#chart${stats.config.coin}_${graphType}`); + let bgcolor = null, + bordercolor = null, + borderwidth = null; let colorelem = $chart.siblings('a.chart-style'); if (colorelem.length == 1) { bgcolor = colorelem.css('background-color'); @@ -1377,56 +1682,79 @@ function market_CreateCharts(stats) { animation: false, responsive: true, maintainAspectRatio: false, - legend: { display: false }, - elements: { point: { radius: 0, hitRadius: 10, hoverRadius: 5 } }, + legend: { + display: false + }, + elements: { + point: { + radius: 0, + hitRadius: 10, + hoverRadius: 5 + } + }, scales: { xAxes: [{ display: false, - ticks: { display: false }, - gridLines: { display: false } + ticks: { + display: false + }, + gridLines: { + display: false + } }], yAxes: [{ display: false, ticks: { display: false, beginAtZero: true, - userCallback: function(label, index, labels) { + userCallback: function (label, index, labels) { if (Math.floor(label) === label) return label; } }, - gridLines: { display: false } + gridLines: { + display: false + } }] }, layout: { - padding: { top: 5, left: 10, right: 10, bottom: 10 } + padding: { + top: 5, + left: 10, + right: 10, + bottom: 10 + } }, tooltips: { callbacks: { - label: function(tooltipItem, data) { + label: function (tooltipItem, data) { let dataType = data.datasets[tooltipItem.datasetIndex].dataType || ''; let label = tooltipItem.yLabel; - if (dataType == 'price') label = parseFloat(tooltipItem.yLabel).toFixed(4); - else if (dataType == 'profit') label = parseFloat(tooltipItem.yLabel).toFixed(10); + if (dataType == 'price') label = parseFloat(tooltipItem.yLabel) + .toFixed(4); + else if (dataType == 'profit') label = parseFloat(tooltipItem.yLabel) + .toFixed(10); return ' ' + label; } } } } }); - $chart.closest('.marketChart').show(); + $chart.closest('.marketChart') + .show(); } } } // Get chart data -function market_GetGraphData(rawData) { +function market_GetGraphData (rawData) { let graphData = { names: [], values: [] }; - if(rawData) { + if (rawData) { for (let i = 0, xy; xy = rawData[i]; i++) { - graphData.names.push(new Date(xy[0]*1000).toLocaleString()); + graphData.names.push(new Date(xy[0] * 1000) + .toLocaleString()); graphData.values.push(xy[1]); } } @@ -1434,19 +1762,27 @@ function market_GetGraphData(rawData) { } + // Calculate current estimation -function market_CalcEstimateProfit(marketPrices){ - let rateUnit = Math.pow(1000,parseInt($('#calcHashUnit').data('mul'))); - let hashRate = parseFloat($('#calcHashRate').val()) * rateUnit; +function market_CalcEstimateProfit (marketPrices) { + let rateUnit = Math.pow(1000, parseInt($('#calcHashUnit') + .data('mul'))); + let hashRate = parseFloat($('#calcHashRate') + .val()) * rateUnit; let coin = lastStats.config.coin try { - if ($(`#calcHashAmount${coin}`).length == 0) { - let template = $(`#calcHashResultTemplate`).html() + if ($(`#calcHashAmount${coin}`) + .length == 0) { + let template = $(`#calcHashResultTemplate`) + .html() Mustache.parse(template) - let rendered = Mustache.render(template, {coin:coin}) - $(`#calcHashHolder`).append(rendered) + let rendered = Mustache.render(template, { + coin: coin + }) + $(`#calcHashHolder`) + .append(rendered) } - let profit = (hashRate * 86400 / lastStats.network.difficulty) * lastStats.lastblock.reward; + let profit = ( hashRate * 86400 / lastStats.network.adjustedDifficulty ) * ( lastStats.lastblock.reward - (lastStats.lastblock.reward * (lastStats.config.networkFee + lastStats.config.fee) / 100) ) if (profit) { updateText(`calcHashAmount${coin}1`, getReadableCoin(lastStats, profit)); updateText(`calcHashAmount${coin}2`, market_GetCurrencyPriceText(lastStats, profit, marketPrices)); @@ -1455,123 +1791,153 @@ function market_CalcEstimateProfit(marketPrices){ updateText(`calcHashAmount${coin}1`, ''); updateText(`calcHashAmount${coin}2`, ''); } - } - catch (e){ + } catch (e) { updateText(`calcHashAmount${coin}1`, ''); updateText(`calcHashAmount${coin}2`, ''); } - Object.keys(mergedStats).forEach(key => { - try { - if ($(`#calcHashAmount${key}`).length == 0) { - let template = $(`#calcHashResultTemplate`).html() - Mustache.parse(template) - let rendered = Mustache.render(template, {coin:key}) - $(`#calcHashHolder`).append(rendered) - } + Object.keys(mergedStats) + .forEach(key => { + try { + if ($(`#calcHashAmount${key}`) + .length == 0) { + let template = $(`#calcHashResultTemplate`) + .html() + Mustache.parse(template) + let rendered = Mustache.render(template, { + coin: key + }) + $(`#calcHashHolder`) + .append(rendered) + } - let profit = (hashRate * 86400 / mergedStats[key].network.difficulty) * mergedStats[key].lastblock.reward; - if (profit) { - updateText(`calcHashAmount${key}1`, getReadableCoin(mergedStats[key], profit)); - updateText(`calcHashAmount${key}2`, market_GetCurrencyPriceText(mergedStats[key], profit, marketPrices)); - return; - } else { + let profit = (hashRate * 86400 / mergedStats[key].network.difficulty) * (mergedStats[key].lastblock.reward - (mergedStats[key].lastblock.reward * mergedStats[key].config.networkFee / 100)); + if (profit) { + updateText(`calcHashAmount${key}1`, getReadableCoin(mergedStats[key], profit)); + updateText(`calcHashAmount${key}2`, market_GetCurrencyPriceText(mergedStats[key], profit, marketPrices)); + return; + } else { + updateText(`calcHashAmount${key}1`, ''); + updateText(`calcHashAmount${key}2`, ''); + } + } catch (e) { updateText(`calcHashAmount${key}1`, ''); updateText(`calcHashAmount${key}2`, ''); } - } - catch(e) - { - updateText(`calcHashAmount${key}1`, ''); - updateText(`calcHashAmount${key}2`, ''); - } - }) + }) } // Get price in specified currency -function market_GetCurrencyPriceText(stats, coinsRaw, marketPrices) { - if (!priceCurrency || !marketPrices[stats.config.coin] || !marketPrices[stats.config.coin][priceCurrency]) return ; +function market_GetCurrencyPriceText (stats, coinsRaw, marketPrices) { + if (!priceCurrency || !marketPrices[stats.config.coin] || !marketPrices[stats.config.coin][priceCurrency]) return; let priceInCurrency = (Math.trunc(getReadableCoin(stats, coinsRaw, 2, true) * marketPrices[stats.config.coin][priceCurrency] * 100) / 100); - return priceInCurrency + ' ' + priceCurrency; + return priceInCurrency + ' ' + priceCurrency; } -function market_InitTemplate(ranOnce, chartsInitialized, loadedData, marketPrices, intervalChartsUpdate, currencyPairs, xhrMarketGets) { +function market_InitTemplate (ranOnce, chartsInitialized, loadedData, marketPrices, intervalChartsUpdate, currencyPairs, xhrMarketGets) { priceSource = lastStats.config.priceSource || 'cryptonator'; priceCurrency = lastStats.config.priceCurrency || 'USD'; let coin = lastStats.config.coin - if ($(`#blocksTabs li:contains(${coin})`).length == 0) { + if ($(`#blocksTabs li:contains(${coin})`) + .length == 0) { chartsInitialized[coin] = false loadedData[coin] = false marketPrices[coin] = {} - let template = $('#siblingTabTemplate').html(); + let template = $('#siblingTabTemplate') + .html(); Mustache.parse(template) - let rendered = Mustache.render(template, {coin:lastStats.config.coin, symbol:`(${lastStats.config.symbol})`, active:'active'}); - $('#blocksTabs').append(rendered) - - let template1 = $('#siblingMarketTemplate').html() - Mustache.parse(template1) - let rendered1 = Mustache.render(template1, {coin:coin, active:'active'}) - $(`#tab-content`).append(rendered1) + let rendered = Mustache.render(template, { + coin: lastStats.config.coin, + symbol: `(${lastStats.config.symbol})`, + active: 'active' + }); + $('#blocksTabs') + .append(rendered) - - let template2 = $('#siblingCalculatorTemplate').html() + let template1 = $('#siblingMarketTemplate') + .html() + Mustache.parse(template1) + let rendered1 = Mustache.render(template1, { + coin: coin, + active: 'active' + }) + $(`#tab-content`) + .append(rendered1) + + + let template2 = $('#siblingCalculatorTemplate') + .html() Mustache.parse(template2) - let rendered2 = Mustache.render(template2, {coin:coin}) - $(`#calculator`).append(rendered2) + let rendered2 = Mustache.render(template2, { + coin: coin + }) + $(`#calculator`) + .append(rendered2) updateText(`priceChartCurrency${lastStats.config.coin}`, priceCurrency); updateText(`profitChartProfit${lastStats.config.coin}`, priceCurrency); if (lastStats.charts && !chartsInitialized[coin]) { - intervalChartsUpdate[coin] = setInterval(market_CreateCharts(lastStats), 60*1000); + intervalChartsUpdate[coin] = setInterval(market_CreateCharts(lastStats), 60 * 1000); market_CreateCharts(lastStats); chartsInitialized[coin] = true; } } - market_LoadMarketData(api, lastStats, loadedData, currencyPairs, xhrMarketGets, marketPrices); + market_LoadMarketData(api, lastStats, loadedData, currencyPairs, xhrMarketGets, marketPrices); - Object.keys(mergedStats).forEach(key => { - if ($(`#blocksTabs li:contains(${key})`).length === 0) { - chartsInitialized[key] = false; - loadedData[key] = false - marketPrices[key] = {} - let template1 = $('#siblingMarketTemplate').html() - Mustache.parse(template1) - let rendered1 = Mustache.render(template1, {coin:key}) - $('#tab-content').append(rendered1) + Object.keys(mergedStats) + .forEach(key => { + if ($(`#blocksTabs li:contains(${key})`) + .length === 0) { + chartsInitialized[key] = false; + loadedData[key] = false + marketPrices[key] = {} + let template1 = $('#siblingMarketTemplate') + .html() + Mustache.parse(template1) + let rendered1 = Mustache.render(template1, { + coin: key + }) + $('#tab-content') + .append(rendered1) - let template = $('#siblingTabTemplate').html(); - Mustache.parse(template) - let rendered = Mustache.render(template, {coin:key, symbol:`(${mergedStats[key].config.symbol})`}); - $('#blocksTabs').append(rendered) + let template = $('#siblingTabTemplate') + .html(); + Mustache.parse(template) + let rendered = Mustache.render(template, { + coin: key, + symbol: `(${mergedStats[key].config.symbol})` + }); + $('#blocksTabs') + .append(rendered) - } + } - updateText(`priceChartCurrency${mergedStats[key].config.coin}`, priceCurrency); - updateText(`profitChartProfit${mergedStats[key].config.coin}`, priceCurrency); + updateText(`priceChartCurrency${mergedStats[key].config.coin}`, priceCurrency); + updateText(`profitChartProfit${mergedStats[key].config.coin}`, priceCurrency); - market_LoadMarketData(mergedApis[key].api, mergedStats[key], loadedData, currencyPairs, xhrMarketGets, marketPrices); + market_LoadMarketData(mergedApis[key].api, mergedStats[key], loadedData, currencyPairs, xhrMarketGets, marketPrices); - if (mergedStats[key].charts && !chartsInitialized[key]) { - intervalChartsUpdate[key] = setInterval(market_CreateCharts(mergedStats[key]), 60*1000); - market_CreateCharts(mergedStats[key]); - chartsInitialized[key] = true; - } + if (mergedStats[key].charts && !chartsInitialized[key]) { + intervalChartsUpdate[key] = setInterval(market_CreateCharts(mergedStats[key]), 60 * 1000); + market_CreateCharts(mergedStats[key]); + chartsInitialized[key] = true; + } - }) + }) market_CalcEstimateProfit(marketPrices); -sortElementList($(`#blocksTabs`), $(`#blocksTabs>li`), mergedStats) + sortElementList($(`#blocksTabs`), $(`#blocksTabs>li`), mergedStats) - if (!ranOnce) + if (!ranOnce) ranOnce = RunOnce() } @@ -1581,295 +1947,495 @@ workerstats methods *************************************************************** */ -function workerstats_Setup(stats, api, addressTimeout, xhrAddressPoll, xhrGetPayments ) { +function workerstats_Setup (stats, api, addressTimeout, xhrAddressPoll, xhrGetPayments, xhrGetBlockRewards) { // Enable time ago on last submitted share - $(`#yourLastShare${stats.config.coin}`).timeago(); - - $(`#lookUp${stats.config.coin}`).click(function(){ - var address = $(`#yourStatsInput${stats.config.coin}`).val().trim(); + $(`#yourLastShare${stats.config.coin}`) + .timeago(); - if (getCurrentAddress(stats.config.coin) != address) { - docCookies.setItem(`mining_address_${stats.config.coin}`, address, Infinity); + $(`#lookUp${stats.config.coin}`) + .click(function () { + var address = $(`#yourStatsInput${stats.config.coin}`) + .val() + .trim(); - var urlWalletAddress = location.search.split('walletMerged=')[1] || 0; - if (urlWalletAddress){ - window.location.href = "/#worker_stats"; - return ; - } - else { + if (getCurrentAddress(stats.config.coin) != address) { docCookies.setItem(`mining_address_${stats.config.coin}`, address, Infinity); - loadLiveStats(true, mergedStats); + + var urlWalletAddress = location.search.split('walletMerged=')[1] || 0; + if (urlWalletAddress) { + window.location.href = "/#worker_stats"; + return; + } else { + docCookies.setItem(`mining_address_${stats.config.coin}`, address, Infinity); + loadLiveStats(true, mergedStats); + } } - } - $(`#addressError${stats.config.coin}, .yourStats${stats.config.coin}, .yourWorkers${stats.config.coin}, .userChart${stats.config.coin}`).hide(); - $(`#workersReport_rows_${stats.config.coin}`).empty(); - $(`#paymentsReport_rows_${stats.config.coin}`).empty(); + $(`#addressError${stats.config.coin}, .yourStats${stats.config.coin}, .yourWorkers${stats.config.coin}, .userChart${stats.config.coin}`) + .hide(); + $(`#workersReport_rows_${stats.config.coin}`) + .empty(); + $(`#paymentsReport_rows_${stats.config.coin}`) + .empty(); + $(`#recentBlock_rows_${stats.config.coin}`) + .empty(); - $(`#lookUp${stats.config.coin} > span:first-child`).hide(); - $(`#lookUp${stats.config.coin} > span:last-child`).show(); + $(`#lookUp${stats.config.coin} > span:first-child`) + .hide(); + $(`#lookUp${stats.config.coin} > span:last-child`) + .show(); - if (addressTimeout[stats.config.coin]) clearTimeout(addressTimeout[stats.config.coin]); + if (addressTimeout[stats.config.coin]) clearTimeout(addressTimeout[stats.config.coin]); - if (xhrAddressPoll[stats.config.coin]) - xhrAddressPoll[stats.config.coin].abort(); + if (xhrAddressPoll[stats.config.coin]) + xhrAddressPoll[stats.config.coin].abort(); - $(`#lookUp${stats.config.coin} > span:last-child`).hide(); - $(`#lookUp${stats.config.coin} > span:first-child`).show(); + $(`#lookUp${stats.config.coin} > span:last-child`) + .hide(); + $(`#lookUp${stats.config.coin} > span:first-child`) + .show(); - if (!address){ - $(`#yourStatsInput${stats.config.coin}`).focus(); - return; - } + if (!address) { + $(`#yourStatsInput${stats.config.coin}`) + .focus(); + return; + } - workerstats_FetchAddressStats(false, stats, api, xhrAddressPoll); + workerstats_FetchAddressStats(false, stats, api, xhrAddressPoll); - }); + }); var address = getCurrentAddress(stats.config.coin); - if (address){ - $(`#yourStatsInput${stats.config.coin}`).val(address); - $(`#lookUp${stats.config.coin}`).click(); + if (address) { + $(`#yourStatsInput${stats.config.coin}`) + .val(address); + $(`#lookUp${stats.config.coin}`) + .click(); + } else { + $(`#lookUp${stats.config.coin} > span:last-child`) + .hide(); + $(`#lookUp${stats.config.coin} > span:first-child`) + .show(); + $(`#addressError${stats.config.coin}, .yourStats${stats.config.coin}, .yourWorkers${stats.config.coin}, .userChart${stats.config.coin}`) + .hide(); } - else { - $(`#lookUp${stats.config.coin} > span:last-child`).hide(); - $(`#lookUp${stats.config.coin} > span:first-child`).show(); - $(`#addressError${stats.config.coin}, .yourStats${stats.config.coin}, .yourWorkers${stats.config.coin}, .userChart${stats.config.coin}`).hide(); - } - - $(`#yourStatsInput${stats.config.coin}`).keyup(function(e){ - if(e.keyCode === 13) - $(`#lookUp${stats.config.coin}`).click(); - }); + + $(`#yourStatsInput${stats.config.coin}`) + .keyup(function (e) { + if (e.keyCode === 13) + $(`#lookUp${stats.config.coin}`) + .click(); + }); // Handle sort on workers table //$(`#workersReport${stats.config.coin} th.sort`).on('click', sortTable); - $(`.workerStats th.sort`).on('click', sortTable); + $(`.workerStats th.sort`) + .on('click', sortTable); // Load more payments button - $(`#loadMorePayments${stats.config.coin}`).click(function(xhrGetPayments){ - if (xhrGetPayments[stats.config.coin]) - xhrGetPayments[stats.config.coin].abort(); + $(`#loadMorePayments${stats.config.coin}`) + .click(function (xhrGetPayments) { + if (xhrGetPayments[stats.config.coin]) + xhrGetPayments[stats.config.coin].abort(); - xhrGetPayments[stats.config.coin] = $.ajax({ - url: `${api}/get_payments`, - data: { - time: $(`#paymentsReport_rows_${stats.config.coin}`).children().last().data('time'), - address: address - }, - dataType: 'json', - cache: 'false', - success: function(data){ - workerstats_RenderPayments(data, stats); - } + xhrGetPayments[stats.config.coin] = $.ajax({ + url: `${api}/get_payments`, + data: { + time: $(`#paymentsReport_rows_${stats.config.coin}`) + .children() + .last() + .data('time'), + address: address + }, + dataType: 'json', + cache: 'false', + success: function (data) { + workerstats_RenderPayments(data, stats); + } + }); + }); + // Load more block rewards button + $(`#loadMoreBlockRewards${stats.config.coin}`) + .click(function (xhrGetBlockRewards) { + if (xhrGetBlockRewards[stats.config.coin]) + xhrGetBlockRewards[stats.config.coin].abort(); + + xhrGetBlockRewards[stats.config.coin] = $.ajax({ + url: `${api}/get_blockRewards`, + data: { + height: $(`#recentBlock_rows_${stats.config.coin}`) + .children() + .last() + .data('height'), + address: address + }, + dataType: 'json', + cache: 'false', + success: function (data) { + workerstats_RenderBlockRewards(data, stats); + } + }); }); - }); } /** * Miner statistics **/ - // Load current miner statistics -function workerstats_FetchAddressStats(longpoll, stats, api, xhrAddressPoll){ +function workerstats_FetchAddressStats (longpoll, stats, api, xhrAddressPoll) { let address = getCurrentAddress(stats.config.coin) - xhrAddressPoll[stats.config.coin] = $.ajax({ - url: `${api}/stats_address`, - data: { - address: address, - longpoll: longpoll - }, - dataType: 'json', - cache: 'false', - success: function(data){ - if (!data.stats){ - $(`.yourStats${stats.config.coin}, .yourWorkers${stats.config.coin}, .userChart${stats.config.coin}`).hide(); - $(`#addressError${stats.config.coin}`).text(data.error).show(); - docCookies.setItem(`mining_address_${stats.config.coin}`, '', Infinity); - loadLiveStats(true); - return; - } - $(`#addressError${stats.config.coin}`).hide(); + if (address) { + xhrAddressPoll[stats.config.coin] = $.ajax({ + url: `${api}/stats_address`, + data: { + address: address, + longpoll: longpoll + }, + dataType: 'json', + cache: 'false', + success: function (data) { + if (!data.stats) { + $(`.yourStats${stats.config.coin}, .yourWorkers${stats.config.coin}, .userChart${stats.config.coin}`) + .hide(); + $(`#addressError${stats.config.coin}`) + .text(data.error) + .show(); + docCookies.setItem(`mining_address_${stats.config.coin}`, '', Infinity); + loadLiveStats(true); + return; + } + $(`#addressError${stats.config.coin}`) + .hide(); - if (data.stats.lastShare) { - $(`#yourLastShare${stats.config.coin}`).timeago('update', new Date(parseInt(data.stats.lastShare) * 1000).toISOString()); - } // AQUÍ - else { - updateText(`yourLastShare${stats.config.coin}`, 'Never'); - } - - - updateText(`yourHashrateHolder${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate) || '0 H') + '/sec'); - if ('hashrate_1h' in data.stats) { - $(`#minerAvgHR${stats.config.coin}`).show(); - updateText(`yourHR1h${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate_1h) || '0 H') + '/s'); - updateText(`yourHR6h${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate_6h) || '0 H') + '/s'); - updateText(`yourHR24h${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate_24h) || '0 H') + '/s'); - } else { - $(`#minerAvgHR${stats.config.coin}`).hide(); - } - - let totalCoins = data.stats.paid; - let last24hCoins = 0; - let last7dCoins = 0; - - for (let i = 0; i < data.payments.length; i += 2) { - let payment = workerstats_ParsePayment(data.payments[i + 1], data.payments[i]); - let paymentDate = new Date(parseInt(payment.time) * 1000); - let daysDiff = moment().diff(moment(paymentDate), 'days'); - - if (daysDiff < 1) { - last24hCoins = last24hCoins + parseInt(payment.amount); + if (data.stats.lastShare) { + $(`#yourLastShare${stats.config.coin}`) + .timeago('update', new Date(parseInt(data.stats.lastShare) * 1000) + .toISOString()); + } // AQUÃ + else { + updateText(`yourLastShare${stats.config.coin}`, 'Never'); } - if (daysDiff < 7) { - last7dCoins = last7dCoins + parseInt(payment.amount); + + updateText(`yourHashrateHolder${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate) || '0 H') + '/sec'); + if ('hashrate_1h' in data.stats) { + $(`#minerAvgHR${stats.config.coin}`) + .show(); + updateText(`yourHR1h${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate_1h) || '0 H') + '/s'); + updateText(`yourHR6h${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate_6h) || '0 H') + '/s'); + updateText(`yourHR24h${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate_24h) || '0 H') + '/s'); + } else { + $(`#minerAvgHR${stats.config.coin}`) + .hide(); } - } - - // $.getJSON(`https://api.coingecko.com/api/v3/coins/${stats.config.coin.toLowerCase()}?sparkline=true`, function() {}) - // .done(data => { - // let paidTotalUSD = getReadableCoin(stats, totalCoins, 2, true) * data.market_data.current_price.usd; - // let paid24hUSD = getReadableCoin(stats, last24hCoins, 2, true) * data.market_data.current_price.usd; - // let paid7dUSD = getReadableCoin(stats, last7dCoins, 2, true) * data.market_data.current_price.usd; - - // updateText(`yourPaid${stats.config.coin}`, `${getReadableCoin(stats, totalCoins)} - $${paidTotalUSD.toFixed(2)}`); - // updateText(`paid24h${stats.config.coin}`, `${getReadableCoin(stats, last24hCoins)} - $${paid24hUSD.toFixed(2)}`); - // updateText(`paid7d${stats.config.coin}`, `${getReadableCoin(stats, last7dCoins)} - $${paid7dUSD.toFixed(2)}`); - // }) - // .fail(() => { - updateText(`yourPaid${stats.config.coin}`, getReadableCoin(stats, totalCoins)); - updateText(`paid24h${stats.config.coin}`, getReadableCoin(stats, last24hCoins)); - updateText(`paid7d${stats.config.coin}`, getReadableCoin(stats, last7dCoins)); - // }) + updateText(`yourPaid${stats.config.coin}`, getReadableCoin(stats, data.stats.paid)); + updateText(`paid24h${stats.config.coin}`, getReadableCoin(stats, data.stats.paid24h)); + updateText(`paid7d${stats.config.coin}`, getReadableCoin(stats, data.stats.paid7d)); - updateText(`yourHashes${stats.config.coin}`, (data.stats.hashes || 0).toString()); - //updateText(`yourPaid${stats.config.coin}`, getReadableCoin(stats, data.stats.paid)); - updateText(`yourPendingBalance${stats.config.coin}`, getReadableCoin(stats, data.stats.balance)); + updateText(`yourHashes${stats.config.coin}`, (data.stats.hashes || 0) + .toString()); + updateText(`yourPendingBalance${stats.config.coin}`, getReadableCoin(stats, data.stats.balance)); - let userRoundHashes = parseInt(data.stats.roundHashes || 0); - let poolRoundHashes = parseInt(stats.pool.roundHashes || 0); - let userRoundScore = parseFloat(data.stats.roundScore || 0); - let poolRoundScore = parseFloat(stats.pool.roundScore || 0); - let lastReward = parseFloat(stats.lastblock.reward || 0); - - - let poolFee = stats.config.fee; - if (Object.keys((stats.config.donation)).length) { - let totalDonation = 0; - let ldon = stats.config.donation; - for(let i in ldon) { - totalDonation += ldon[i]; + let allWorkers = 0, onlineWorkers = 0, offlineWorkers = 0 + if(data && data.workers) { + for (var worker = 0; worker < data.workers.length; worker++) { + if (Date.now() / 1000 - parseInt(data.workers[worker].lastShare) > 2 * 86400) + continue + allWorkers++ + if(data.workers[worker].hashrate === 0) { + offlineWorkers++ + } + else { + onlineWorkers++ + } + } } - poolFee += totalDonation; - } - let transferFee = stats.config.transferFee; - let share_pct = userRoundHashes * 100 / poolRoundHashes; - let score_pct = userRoundScore * 100 / poolRoundScore; - updateText(`yourRoundShareProportion${stats.config.coin}`, isNaN(share_pct) ? 0.0 : Math.round(share_pct * 1000) / 1000); - updateText(`yourRoundScoreProportion${stats.config.coin}`, isNaN(score_pct) ? 0.0 : Math.round(score_pct * 1000) / 1000); - if (!lastStats.config.slushMiningEnabled) { - $(`#slush_round_info${stats.config.coin}`).hide(); - } + updateText(`allWorkers_${stats.config.coin}`, allWorkers) + updateText(`onlineWorkers_${stats.config.coin}`, onlineWorkers) + updateText(`offlineWorkers_${stats.config.coin}`, offlineWorkers) - let payoutEstimatePct = parseFloat(userRoundHashes * 100 / poolRoundHashes) - let payoutEstimate = Math.round(lastReward * (payoutEstimatePct / 100)); + let userRoundHashes = parseFloat(data.stats.roundHashes || 0); + let poolRoundHashes = parseFloat(stats.pool.roundHashes || 0); + let userRoundScore = parseFloat(data.stats.roundScore || 0); + let poolRoundScore = parseFloat(stats.pool.roundScore || 0); + let lastReward = stats.lastblock.reward - (stats.lastblock.reward * (stats.config.networkFee ? stats.config.networkFee / 100 : 0)); + + let poolFee = stats.config.fee; + if (Object.keys((stats.config.donation)) + .length) { + let totalDonation = 0; + let ldon = stats.config.donation; + for (let i in ldon) { + totalDonation += ldon[i]; + } + poolFee += totalDonation; + } + let transferFee = stats.config.transferFee; + + let share_pct = userRoundHashes * 100 / poolRoundHashes; + let score_pct = userRoundScore * 100 / poolRoundScore; + updateText(`yourRoundShareProportion${stats.config.coin}`, isNaN(share_pct) ? 0.0 : Math.round(share_pct * 1000) / 1000); + updateText(`yourRoundScoreProportion${stats.config.coin}`, isNaN(score_pct) ? 0.0 : Math.round(score_pct * 1000) / 1000); + if (!lastStats.config.slushMiningEnabled) { + $(`#slush_round_info${stats.config.coin}`) + .hide(); + } + + let payoutEstimatePct = parseFloat(userRoundHashes * 100 / poolRoundHashes) + let payoutEstimate = Math.round(lastReward * (payoutEstimatePct / 100)); if (transferFee) payoutEstimate = payoutEstimate - transferFee; - if (payoutEstimate < 0) - payoutEstimate = 0; - updateText(`yourPayoutEstimate${stats.config.coin}`, getReadableCoin(stats, payoutEstimate)); + if (payoutEstimate < 0) + payoutEstimate = 0; + updateText(`yourPayoutEstimate${stats.config.coin}`, getReadableCoin(stats, payoutEstimate)); - workerstats_RenderPayments(data.payments, stats); + workerstats_RenderPayments(data.payments, stats); + if (data.block_rewards) + workerstats_RenderBlockRewards(data.block_rewards, stats) - if (data.workers && data.workers.length > 0) { - workerstats_RenderWorkers(data.workers, stats); - $(`.yourWorkers${stats.config.coin}`).show(); + if (data.workers && data.workers.length > 0) { + workerstats_RenderWorkers(data.workers, stats); + $(`.yourWorkers${stats.config.coin}`) + .show(); + } + + $(`.yourStats${stats.config.coin}`) + .show(); + workerstats_CreateCharts(data, stats); + + }, + error: function (e) { + if (e.statusText === 'abort') return; + $(`#addressError${stats.config.coin}`) + .text('Connection error') + .show(); + + if (addressTimeout[stats.config.coin]) + clearTimeout(addressTimeout[stats.config.coin]); + + addressTimeout[stats.config.coin] = setTimeout(function () { + workerstats_FetchAddressStats(false, stats, mergedApis[stats.config.coin].api); + }, 2000); } - - $(`.yourStats${stats.config.coin}`).show(); - workerstats_CreateCharts(data, stats); - - }, - error: function(e){ - if (e.statusText === 'abort') return; - $(`#addressError${stats.config.coin}`).text('Connection error').show(); - - if (addressTimeout[stats.config.coin]) - clearTimeout(addressTimeout[stats.config.coin]); - - addressTimeout[stats.config.coin] = setTimeout(function(){ - workerstats_FetchAddressStats(false, stats, mergedApis[stats.config.coin].api); - }, 2000); - } - }); + }); + } } /** * Charts **/ + let workerstats_graphSettings = { + type: 'line', + width: '100%', + height: '140', + lineColor: '#03a9f4', + fillColor: 'rgba(3, 169, 244, .4)', + spotColor: null, + minSpotColor: null, + maxSpotColor: null, + highlightLineColor: '#236d26', + spotRadius: 3, + chartRangeMin: 0, + drawNormalOnTop: false, + tooltipFormat: '
{{y}} – {{offset:names}}
', + tooltipFormatter: (sp, options, fields) => { + let format = $.spformat(options.mergedOptions.tooltipFormat) + if (options.get('tooltipValueLookups').type == 'hashrate') + fields.y = getReadableHashRateString(fields.y) + return format.render(fields, options.get('tooltipValueLookups'), options) + } +}; + // Create charts -function workerstats_CreateCharts(data, stats) { +function workerstats_CreateCharts (data, stats) { if (data.hasOwnProperty("charts")) { var graphData = { - hashrate: workerstats_GetGraphData(stats, data.charts.hashrate), - payments: workerstats_GetGraphData(stats, data.charts.payments, true) - }; - - for(var graphType in graphData) { - if(graphData[graphType].values.length > 1) { - var settings = jQuery.extend({}, graphSettings); - settings.tooltipValueLookups = {names: graphData[graphType].names}; - var $chart = $(`[data-chart=user_${graphType}_${stats.config.coin}]`).show().find('.chart'); - $chart.sparkline(graphData[graphType].values, settings); + hashrate: { + data: [workerstats_GetGraphData(stats, data.charts.hashrate), workerstats_GetGraphData(stats, data.charts.hashrateSolo)], + options: { + lineColor: 'orange' + } } } + + for (var graphType in graphData) { + if (graphData[graphType].data[0].values.length > 1) { + var settings = jQuery.extend({}, workerstats_graphSettings); + settings.tooltipValueLookups = { + names: graphData[graphType].data[0].names, + type: graphType + }; + var $chart = $(`[data-chart=user_${graphType}_${stats.config.coin}]`) + .show() + .find('.chart'); + $chart.sparkline(graphData[graphType].data[0].values, settings); + if (graphData[graphType].data[1]) { + settings.composite = true + settings.lineColor = graphData[graphType].options.lineColor + $chart.sparkline(graphData[graphType].data[1].values, settings); + } + } + } + workerstats_createMinerCharts(data, stats) } } -// Get chart data -function workerstats_GetGraphData(stats, rawData, fixValueToCoins) { +function workerstats_GetEarningsData(rawData) { var graphData = { names: [], values: [] }; - - if(rawData) { - for (var i = 0, xy; xy = rawData[i]; i++) { - graphData.names.push(new Date(xy[0]*1000).toLocaleString()); - graphData.values.push(fixValueToCoins ? getReadableCoin(stats, xy[1], null, true) : xy[1]); + if (rawData) { + for (var i = 0; i < rawData.length - 1; i+=2) { + graphData.names.push(new Date(rawData[i+1] * 1000).toDateString()); + graphData.values.push(rawData[i]); } } + return graphData +} +let charts = {} + +function workerstats_createMinerCharts(data, stats) { + let graphData = { + payments: workerstats_GetEarningsData(data.stats.earnings) + }; + for (var graphType in graphData) { + if (charts[graphType]) { + charts[graphType].destroy(); + } + if (graphData[graphType].values) { + let $chart = $(`[data-chart=user_${graphType}_${stats.config.coin}]`); + let bgcolor = null, bordercolor = null, borderwidth = null; + let colorelem = $chart.siblings('a.chart-style'); + if (colorelem.length == 1) { + bgcolor = colorelem.css('background-color'); + bordercolor = colorelem.css('border-left-color'); + borderwidth = parseFloat(colorelem.css('width')); + } + if (bgcolor === null) bgcolor = 'rgba(3, 169, 244, .4)'; + if (bordercolor === null) bordercolor = '#03a9f4'; + if (borderwidth === null || isNaN(borderwidth)) borderwidth = 1; + charts[graphType] = new Chart(document.getElementById(`chart_${graphType}_${stats.config.coin}`), { + type: 'bar', + data: { + labels: graphData[graphType].names, + datasets: [{ + data: graphData[graphType].values, + dataType: graphType, + fill: true, + backgroundColor: bgcolor, + borderColor: bordercolor, + borderWidth: borderwidth + }] + }, + options: { + animation: false, + title: { + display: true, + text: 'Miner Payments' + }, + responsive: true, + maintainAspectRatio: false, + legend: {display: false}, + elements: {point: {radius: 0, hitRadius: 10, hoverRadius: 5}}, + scales: { + xAxes: [{ + "fontSize": 12, + "fontFamily": "Source Sans Pro", + display: false, + ticks: {display: false}, + gridLines: {display: false} + }], + yAxes: [{ + display: true, + ticks: { + "fontSize": 12, + "fontFamily": "Source Sans Pro", + display: true, + beginAtZero: true, + callback: (graphType == 'payments' ? function (label, index, labels) { + return getReadableCoin(stats, label); + } : function (label, index, labels) { + return label; + }) + }, + gridLines: {display: false} + }] + }, + layout: { + padding: {top: 15, left: 0, right: 15, bottom: 15} + }, + tooltips: { + callbacks: { + label: function (tooltipItem, data) { + return ` ${getReadableCoin(stats, tooltipItem.yLabel)}` + } + } + } + } + }); + $chart.closest(`.userPaymentChart${stats.config.coin}`).show(); + } + } +} + +function workerstats_GetGraphData (stats, rawData, fixValueToCoins, collate) { + var graphData = { + names: [], + values: [] + }; + collate = collate ? collate : false + if (rawData) { + let currentDate = null + let accumulator = -1 + for (var i = 0, xy; xy = rawData[i]; i++) { + if (collate) { + if (currentDate === new Date(xy[0] * 1000).setHours(0, 0, 0, 0)) { + graphData.values[accumulator] += parseFloat(xy[1]) + } else { + accumulator++ + currentDate = new Date(xy[0] * 1000).setHours(0, 0, 0, 0) + graphData.names.push(new Date(currentDate).toDateString()); + graphData.values[accumulator] = parseFloat(xy[1]); + } + } + else { + graphData.names.push(new Date(xy[0] * 1000).toLocaleString()); + graphData.values.push(fixValueToCoins ? getReadableCoin(stats, xy[1], null, true) : xy[1]); + } + } + } return graphData; } + /** * Workers report **/ // Get worker row id -function workerstats_GetWorkerRowId(workerName){ +function workerstats_GetWorkerRowId (workerName) { var id = btoa(workerName); id = id.replace(/=/, ''); return id; } // Get worker row element -function workerstats_GetWorkerRowElement(worker, jsonString, stats){ +function workerstats_GetWorkerRowElement (worker, jsonString, stats) { var row = document.createElement('tr'); row.setAttribute('data-json', jsonString); row.setAttribute('data-name', worker.name); @@ -1881,64 +2447,68 @@ function workerstats_GetWorkerRowElement(worker, jsonString, stats){ } // Get worker cells -function workerstats_GetWorkerCells(worker){ +function workerstats_GetWorkerCells (worker) { let hashrate = worker.hashrate ? worker.hashrate : 0; - let hashrate1h = worker.hashrate_1h || 0; - let hashrate6h = worker.hashrate_6h || 0; - let hashrate24h = worker.hashrate_24h || 0; + let hashrate1h = worker.hashrate_1h || 0; + let hashrate6h = worker.hashrate_6h || 0; + let hashrate24h = worker.hashrate_24h || 0; let lastShare = worker.lastShare ? worker.lastShare : 0; - let hashes = (worker.hashes || 0).toString(); + let hashes = (worker.hashes || 0) + .toString(); let status = (hashrate <= 0) ? 'error' : 'ok'; - return '' + - '' + (worker.name != 'undefined' ? worker.name : 'Undefined') + '' + - '' + getReadableHashRateString(hashrate) + '/s' + - '' + getReadableHashRateString(hashrate1h) + '/s' + - '' + getReadableHashRateString(hashrate6h) + '/s' + - '' + getReadableHashRateString(hashrate24h) + '/s' + - '' + (lastShare ? $.timeago(new Date(parseInt(lastShare) * 1000).toISOString()) : 'Never') + '' + - '' + hashes + ''; + return '' + + '' + (worker.name != 'undefined' ? worker.name : 'Undefined') + '' + + '' + getReadableHashRateString(hashrate) + '/s' + + '' + getReadableHashRateString(hashrate1h) + '/s' + + '' + getReadableHashRateString(hashrate6h) + '/s' + + '' + getReadableHashRateString(hashrate24h) + '/s' + + '' + (lastShare ? $.timeago(new Date(parseInt(lastShare) * 1000) + .toISOString()) : 'Never') + '' + + '' + hashes + ''; } // Sort workers -function workerstats_SortWorkers(a, b){ +function workerstats_SortWorkers (a, b) { var aName = a.name.toLowerCase(); var bName = b.name.toLowerCase(); return ((aName < bName) ? -1 : ((aName > bName) ? 1 : 0)); } // Render workers list -function workerstats_RenderWorkers(workersData, stats){ +function workerstats_RenderWorkers (workersData, stats) { workersData = workersData.sort(workerstats_SortWorkers); var $workersRows = $(`#workersReport_rows_${stats.config.coin}`); - for (var i = 0; i < workersData.length; i++){ + for (var i = 0; i < workersData.length; i++) { var existingRow = document.getElementById(`workerRow${stats.config.coin}_${workerstats_GetWorkerRowId(workersData[i].name)}`); - if (!existingRow){ + if (!existingRow) { $workersRows.empty(); break; } } - let have_avg_hr = false; + let have_avg_hr = false; - for (var i = 0; i < workersData.length; i++){ + for (var i = 0; i < workersData.length; i++) { var worker = workersData[i]; - if (Date.now()/1000 - parseInt(worker.lastShare) > 2 * 86400) continue; + if (Date.now() / 1000 - parseInt(worker.lastShare) > 2 * 86400) continue; if (!have_avg_hr && 'hashrate_1h' in worker) have_avg_hr = true; var workerJson = JSON.stringify(worker); var existingRow = document.getElementById(`workerRow${stats.config.coin}_${workerstats_GetWorkerRowId(worker.name)}`); - if (existingRow && existingRow.getAttribute('data-json') !== workerJson){ - $(existingRow).replaceWith(workerstats_GetWorkerRowElement(worker, workerJson, stats)); - } - else if (!existingRow){ + if (existingRow && existingRow.getAttribute('data-json') !== workerJson) { + $(existingRow) + .replaceWith(workerstats_GetWorkerRowElement(worker, workerJson, stats)); + } else if (!existingRow) { var workerElement = workerstats_GetWorkerRowElement(worker, workerJson, stats); $workersRows.append(workerElement); } } - if (!have_avg_hr) $(`#workersReport${stats.config.coin} .avghr`).hide(); - else $(`#workersReport${stats.config.coin} .avghr`).show(); + if (!have_avg_hr) $(`#workersReport${stats.config.coin} .avghr`) + .hide(); + else $(`#workersReport${stats.config.coin} .avghr`) + .show(); } /** @@ -1946,7 +2516,7 @@ function workerstats_RenderWorkers(workersData, stats){ **/ // Parse payment data -function workerstats_ParsePayment(time, serializedPayment){ +function workerstats_ParsePayment (time, serializedPayment) { var parts = serializedPayment.split(':'); return { time: parseInt(time), @@ -1958,8 +2528,25 @@ function workerstats_ParsePayment(time, serializedPayment){ }; } +// Parse block_reward data +function workerstats_ParseBlockReward (height, serializedPayment) { + var parts = serializedPayment.split(':'); + return { + height: height, + rewardType: parts[0], + hash: parts[1], + time: parseInt(parts[2]), + difficulty: parts[3], + shares: parts[4], + blockReward: parts[5], + reward: parts[6], + percent: parts[7], + finderFee: parts[8] + }; +} + // Get payment row element -function workerstats_GetPaymentRowElement(payment, jsonString, stats){ +function workerstats_GetPaymentRowElement (payment, jsonString, stats) { var row = document.createElement('tr'); row.setAttribute('data-json', jsonString); row.setAttribute('data-time', payment.time); @@ -1970,16 +2557,41 @@ function workerstats_GetPaymentRowElement(payment, jsonString, stats){ return row; } +// Get blockreward row element +function workerstats_GetBlockRewardRowElement (block_reward, jsonString, stats) { + var row = document.createElement('tr'); + row.setAttribute('data-json', jsonString); + row.setAttribute('data-height', block_reward.height); + row.setAttribute('id', 'blockRewardRow' + stats.config.coin + block_reward.time); + row.innerHTML = workerstats_GetBlockRewardCells(block_reward, stats); + return row; +} + // Get payment cells -function workerstats_GetPaymentCells(payment, stats){ - return '' + formatDate(payment.time) + '' + - '' + formatPaymentLink(payment.hash, stats) + '' + - '' + getReadableCoin(stats, payment.amount) + '' + - '' + payment.mixin + ''; +function workerstats_GetPaymentCells (payment, stats) { + return `${formatDate(payment.time)}` + + `${formatPaymentLink(payment.hash, stats)}` + + `${getReadableCoin(stats, payment.amount)}` + + `${getReadableCoin(stats, payment.fee)}` + + `${payment.mixin}`; +} + +// Get block_reward cells +function workerstats_GetBlockRewardCells (block_reward, stats) { + function formatBlockRewardLink (block_reward, stats) { + return '' + block_reward.height + ''; + } + return `${formatBlockRewardLink(block_reward, stats)}` + + `${formatDate(block_reward.time)}` + + `${block_reward.difficulty}` + + `${formatLuck(block_reward.difficulty, block_reward.shares, false)}` + + `${getReadableCoin(stats, block_reward.blockReward)}` + + `${getReadableCoin(stats, block_reward.reward)} ( = ${(block_reward.percent * 100).toFixed(2)}% after pool fees)` + + ` ${block_reward.rewardType}`; } // Get summary row element -function workerstats_GetSummaryRowElement(summary, jsonString, stats){ +function workerstats_GetSummaryRowElement (summary, jsonString, stats) { var row = document.createElement('tr'); row.setAttribute('data-json', jsonString); row.setAttribute('data-date', summary.date); @@ -1992,42 +2604,55 @@ function workerstats_GetSummaryRowElement(summary, jsonString, stats){ } // Get summary cells -function workerstats_GetSummaryCells(summary, stats){ +function workerstats_GetSummaryCells (summary, stats) { var text = getTranslation('paymentSummaryMulti') ? getTranslation('paymentSummaryMulti') : 'On %DATE% you have received %AMOUNT% in %COUNT% payments'; if (summary.count <= 1) text = getTranslation('paymentSummarySingle') ? getTranslation('paymentSummarySingle') : 'On %DATE% you have received %AMOUNT%'; text = text.replace(/%DATE%/g, summary.date); text = text.replace(/%COUNT%/g, summary.count); text = text.replace(/%AMOUNT%/g, getReadableCoin(stats, summary.amount)); - return '' + text + ''; + return '' + text + ''; } // Render payments -function workerstats_RenderPayments(paymentsResults, stats){ +function workerstats_RenderPayments (paymentsResults, stats) { var $paymentsRows = $(`#paymentsReport_rows_${stats.config.coin}`); var lastPaymentDate = null; - var summaryData = { date: null, time: null, count: 0, amount: 0 }; - for (var i = 0; i < paymentsResults.length; i += 2){ + var summaryData = { + date: null, + time: null, + count: 0, + amount: 0 + }; + for (var i = 0; i < paymentsResults.length; i += 2) { var payment = workerstats_ParsePayment(paymentsResults[i + 1], paymentsResults[i]); var paymentJson = JSON.stringify(payment); var paymentElement = workerstats_GetPaymentRowElement(payment, paymentJson, stats); - var paymentDate = new Date(parseInt(payment.time) * 1000).toLocaleDateString(); + var paymentDate = new Date(parseInt(payment.time) * 1000) + .toLocaleDateString(); if (!lastPaymentDate || lastPaymentDate && paymentDate != lastPaymentDate) { - summaryData = { date: paymentDate, time: payment.time, count: 0, amount: 0 }; + summaryData = { + date: paymentDate, + time: payment.time, + count: 0, + amount: 0 + }; } var existingRow = document.getElementById(`paymentRow${stats.config.coin}${payment.time}`); - if (existingRow && existingRow.getAttribute('data-json') !== paymentJson){ - $(existingRow).replaceWith(workerstats_GetPaymentRowElement(payment, paymentJson, stats)); - } - else if (!existingRow){ + if (existingRow && existingRow.getAttribute('data-json') !== paymentJson) { + $(existingRow) + .replaceWith(workerstats_GetPaymentRowElement(payment, paymentJson, stats)); + } else if (!existingRow) { var inserted = false; - var rows = $paymentsRows.children().get(); + var rows = $paymentsRows.children() + .get(); for (var f = 0; f < rows.length; f++) { var pTime = parseInt(rows[f].getAttribute('data-time')); - if (pTime && pTime < payment.time){ + if (pTime && pTime < payment.time) { inserted = true; - $(rows[f]).before(paymentElement); + $(rows[f]) + .before(paymentElement); break; } } @@ -2036,24 +2661,26 @@ function workerstats_RenderPayments(paymentsResults, stats){ } } - summaryData.count ++; - summaryData.amount += parseInt(payment.amount); + summaryData.count++; + summaryData.amount += parseFloat(payment.amount) + parseFloat(payment.fee); var summaryJson = JSON.stringify(summaryData); var summaryElement = workerstats_GetSummaryRowElement(summaryData, summaryJson, stats); var existingSummary = document.getElementById(`summaryRow${stats.config.coin}${summaryData.date}`); - if (existingSummary && existingSummary.getAttribute('data-json') !== summaryJson){ - $(existingSummary).replaceWith(summaryElement); - } - else if (!existingSummary){ + if (existingSummary && existingSummary.getAttribute('data-json') !== summaryJson) { + $(existingSummary) + .replaceWith(summaryElement); + } else if (!existingSummary) { var inserted = false; - var rows = $paymentsRows.children().get(); + var rows = $paymentsRows.children() + .get(); for (var f = 0; f < rows.length; f++) { var pTime = parseInt(rows[f].getAttribute('data-time')); - if (pTime && pTime === summaryData.time){ + if (pTime && pTime === summaryData.time) { inserted = true; - $(rows[f]).before(summaryElement); + $(rows[f]) + .before(summaryElement); break; } } @@ -2065,41 +2692,98 @@ function workerstats_RenderPayments(paymentsResults, stats){ } } -function workerstats_InitTemplate(ranOnce, addressTimeout, xhrAddressPoll, xhrGetPayments ) { - let coin = lastStats.config.coin - if ($(`#blocksTabs li:contains(${coin})`).length === 0) { - let template = $('#siblingTabTemplate').html(); - Mustache.parse(template) - let rendered = Mustache.render(template, {coin:lastStats.config.coin, symbol:`(${lastStats.config.symbol})`, active: 'active'}); - $('#blocksTabs').append(rendered) +// Render block_rewards - template = $('#siblingTemplate').html() - Mustache.parse(template) - rendered = Mustache.render(template, {coin:coin, active: 'active'}) - $('#tab-content').append(rendered) - workerstats_Setup(lastStats, api, addressTimeout, xhrAddressPoll, xhrGetPayments) +function workerstats_RenderBlockRewards(blockRewardsResults, stats) { + var $blockRewardsRows = $(`#recentBlock_rows_${stats.config.coin}`); + for (var i = 0; i < blockRewardsResults.length; i += 2) { + var block_reward = workerstats_ParseBlockReward(blockRewardsResults[i + 1], blockRewardsResults[i]); + var block_rewardJson = JSON.stringify(block_reward); + var paymentElement = workerstats_GetBlockRewardRowElement(block_reward, block_rewardJson, stats); + + + var existingRow = document.getElementById(`blockRewardRow${stats.config.coin}${block_reward.time}`); + if (existingRow && existingRow.getAttribute('data-json') !== block_rewardJson) { + $(existingRow) + .replaceWith(workerstats_GetBlockRewardRowElement(block_reward, block_rewardJson, stats)); + } else if (!existingRow) { + var inserted = false; + var rows = $blockRewardsRows.children() + .get(); + for (var f = 0; f < rows.length; f++) { + var pTime = parseInt(rows[f].getAttribute('data-time')); + if (pTime && pTime < block_reward.time) { + inserted = true; + $(rows[f]) + .before(paymentElement); + break; + } + } + if (!inserted) { + $blockRewardsRows.append(paymentElement); + } + } + } +} + +function workerstats_InitTemplate (ranOnce, addressTimeout, xhrAddressPoll, xhrGetPayments, xhrGetBlockRewards) { + let coin = lastStats.config.coin + if ($(`#blocksTabs li:contains(${coin})`) + .length === 0) { + let template = $('#siblingTabTemplate') + .html(); + Mustache.parse(template) + let rendered = Mustache.render(template, { + coin: lastStats.config.coin, + symbol: `(${lastStats.config.symbol})`, + active: 'active' + }); + $('#blocksTabs') + .append(rendered) + + template = $('#siblingTemplate') + .html() + Mustache.parse(template) + rendered = Mustache.render(template, { + coin: coin, + active: 'active' + }) + $('#tab-content') + .append(rendered) + workerstats_Setup(lastStats, api, addressTimeout, xhrAddressPoll, xhrGetPayments, xhrGetBlockRewards) } - Object.keys(mergedStats).forEach(key => { - if ($(`#blocksTabs li:contains(${key})`).length === 0) { - coin = key - let template = $('#siblingTabTemplate').html(); - Mustache.parse(template) - let rendered = Mustache.render(template, {coin:mergedStats[key].config.coin, symbol:`(${mergedStats[key].config.symbol})`}); - $('#blocksTabs').append(rendered) + Object.keys(mergedStats) + .forEach(key => { + if ($(`#blocksTabs li:contains(${key})`) + .length === 0) { + coin = key + let template = $('#siblingTabTemplate') + .html(); + Mustache.parse(template) + let rendered = Mustache.render(template, { + coin: mergedStats[key].config.coin, + symbol: `(${mergedStats[key].config.symbol})` + }); + $('#blocksTabs') + .append(rendered) - template = $('#siblingTemplate').html() - Mustache.parse(template) - rendered = Mustache.render(template, {coin:coin}) - $('#tab-content').append(rendered) - workerstats_Setup(mergedStats[key], mergedApis[key].api, addressTimeout, xhrAddressPoll, xhrGetPayments) - } - }) + template = $('#siblingTemplate') + .html() + Mustache.parse(template) + rendered = Mustache.render(template, { + coin: coin + }) + $('#tab-content') + .append(rendered) + workerstats_Setup(mergedStats[key], mergedApis[key].api, addressTimeout, xhrAddressPoll, xhrGetPayments, xhrGetBlockRewards) + } + }) sortElementList($(`#blocksTabs`), $(`#blocksTabs>li`), mergedStats) - if (!ranOnce) - ranOnce = RunOnce() + if (!ranOnce) + ranOnce = RunOnce() } @@ -2122,88 +2806,146 @@ let home_GraphSettings = { spotRadius: 3, chartRangeMin: 0, drawNormalOnTop: false, - tooltipFormat: '{{y}} – {{offset:names}}' + tooltipFormat: '
{{y}} – {{offset:names}}
', + tooltipFormatter: (sp, options, fields) => { + let format = $.spformat(options.mergedOptions.tooltipFormat) + if (options.get('tooltipValueLookups').type == 'hashrate') + fields.y = getReadableHashRateString(fields.y) + return format.render(fields, options.get('tooltipValueLookups'), options) + } }; -function home_CreateCharts(data) { +function home_CreateCharts (data) { if (data.hasOwnProperty("charts")) { var graphData = { - hashrate: home_GetGraphData(data.charts.hashrate), - diff: home_GetGraphData(data.charts.difficulty), - miners: home_GetGraphData(data.charts.miners), - workers: home_GetGraphData(data.charts.workers) + hashrate: { + data: [home_GetGraphData(data.charts.hashrate), home_GetGraphData(data.charts.hashrateSolo)], + options: { + lineColor: 'orange' + } + }, + diff: { + data: [home_GetGraphData(data.charts.difficulty)] + }, + miners: { + data: [home_GetGraphData(data.charts.miners), home_GetGraphData(data.charts.minersSolo)], + options: { + lineColor: 'orange' + } + }, + workers: { + data: [home_GetGraphData(data.charts.workers), home_GetGraphData(data.charts.workersSolo)], + options: { + lineColor: 'orange' + } + }, }; for(var graphType in graphData) { - if(graphData[graphType].values.length > 1) { - var settings = jQuery.extend({}, home_GraphSettings); - settings.tooltipValueLookups = {names: graphData[graphType].names}; - var $chart = $('[data-chart=' + graphType + '] .chart'); - $chart.closest('.poolChart').show(); - $chart.sparkline(graphData[graphType].values, settings); + if(graphData[graphType].data[0].values.length > 1) { + var settings = jQuery.extend({}, home_GraphSettings); + settings.tooltipValueLookups = {names: graphData[graphType].data[0].names, type: graphType}; + var $chart = $('[data-chart=' + graphType + '] .chart'); + $chart.closest('.poolChart').show(); + $chart.sparkline(graphData[graphType].data[0].values, settings); + if (graphData[graphType].data[1]) { + settings.composite = true + settings.lineColor = graphData[graphType].options.lineColor + $chart.sparkline(graphData[graphType].data[1].values, settings); + } + } } - } + } } // Get chart data -function home_GetGraphData(rawData, fixValueToCoins) { +function home_GetGraphData (rawData, fixValueToCoins) { var graphData = { names: [], values: [] }; - if(rawData) { + if (rawData) { for (var i = 0, xy; xy = rawData[i]; i++) { - graphData.names.push(new Date(xy[0]*1000).toLocaleString()); + graphData.names.push(new Date(xy[0] * 1000) + .toLocaleString()); graphData.values.push(fixValueToCoins ? getReadableCoin(lastStats, xy[1], null, true) : xy[1]); } } - return graphData; } -function home_GenerateNetworkStats(key, symbol) { - if ($(`#networkStats${key}`).length == 0) { - let template = $('#siblingTemplate').html() +function home_GenerateNetworkStats (key, symbol) { + if ($(`#networkStats${key}`) + .length == 0) { + let template = $('#siblingTemplate') + .html() if (template) { Mustache.parse(template) - let rendered = Mustache.render(template, {coin:key, symbol: symbol}) - $(`#networkStats`).append(rendered) + let rendered = Mustache.render(template, { + coin: key, + symbol: symbol + }) + $(`#networkStats`) + .append(rendered) } } } -function sortElementList(container, siblings, stats) { - let sorted = (a,b) => { +function sortElementList (container, siblings, stats) { + let sorted = (a, b) => { return ((a.id.toLowerCase() < b.id.toLowerCase()) ? -1 : ((a.id.toLowerCase() > b.id.toLowerCase()) ? 1 : 0)) } - if (stats && siblings.length -1 === Object.keys(stats).length) { - siblings.sort(sorted).appendTo(container) + if (stats && siblings.length - 1 === Object.keys(stats) + .length) { + siblings.sort(sorted) + .appendTo(container) } } -function home_InitTemplate(parentStats, siblingStats) { - $('#networkLastBlockFound').timeago('update', new Date(parentStats.lastblock.timestamp * 1000).toISOString()); +function home_InitTemplate (parentStats, siblingStats) { + $('#networkLastBlockFound') + .timeago('update', new Date(parentStats.lastblock.timestamp * 1000) + .toISOString()); let coin = parentStats.config.coin let minerInfo = [] let efforts = [] + let effortsSolo = [] - if ($(`#networkStats${coin}`).length == 0) { - minerInfo.push({blocks: parentStats.pool.totalBlocks.toString(), - blocksSolo: parentStats.pool.totalBlocksSolo.toString(), - coin: coin, - symbol: parentStats.config.symbol, - miners: parentStats.pool.miners.toString(), - minersSolo: parentStats.pool.minersSolo.toString()}) - - efforts.push({coin: coin, effort: `${(parentStats.pool.roundHashes / parentStats.network.difficulty * 100).toFixed(1)}%`,symbol: parentStats.config.symbol}) - - let template = $('#siblingTemplate').html() + if ($(`#networkStats${coin}`) + .length == 0) { + minerInfo.push({ + blocks: parentStats.pool.totalBlocks.toString(), + blocksSolo: parentStats.pool.totalBlocksSolo.toString(), + coin: coin, + symbol: parentStats.config.symbol, + miners: parentStats.pool.miners.toString(), + minersSolo: parentStats.pool.minersSolo.toString() + }) + + efforts.push({ + coin: coin, + effort: `${(parentStats.pool.roundHashes / parentStats.network.difficulty * 100).toFixed(1)}%`, + symbol: parentStats.config.symbol + }) + + effortsSolo.push({ + coin: coin, + effort: `${(parentStats.pool.roundHashesSolo / parentStats.network.difficulty * 100).toFixed(1)}%`, + symbol: parentStats.config.symbol + }) + + let template = $('#siblingTemplate') + .html() Mustache.parse(template) - let rendered = Mustache.render(template, {coin: coin, symbol: parentStats.config.symbol}) - $(`#networkStats`).append(rendered) + let rendered = Mustache.render(template, { + coin: coin, + symbol: parentStats.config.symbol + }) + $(`#networkStats`) + .append(rendered) } let lastBlockFound = null @@ -2211,63 +2953,112 @@ function home_InitTemplate(parentStats, siblingStats) { lastBlockFound = parseInt(parentStats.pool.lastBlockFound); } + let lastBlockFoundSolo = null + if (parentStats.pool.lastBlockFoundSolo) { + lastBlockFoundSolo = parseInt(parentStats.pool.lastBlockFoundSolo); + } - updateText(`networkHashrate${coin}`, getReadableHashRateString(parentStats.network.difficulty / parentStats.config.coinDifficultyTarget) + '/sec'); + + updateText(`networkHashrate${coin}`, `${getReadableHashRateString(parentStats.network.networkhashps)}/sec`) updateText(`networkDifficulty${coin}`, formatNumber(parentStats.network.difficulty.toString(), ' ')); updateText(`blockchainHeight${coin}`, formatNumber(parentStats.network.height.toString(), ' ')); - updateText(`networkLastReward${coin}`, getReadableCoin(parentStats, parentStats.lastblock.reward)); + let rewardMinusNetworkFee = parentStats.lastblock.reward - (parentStats.lastblock.reward * (parentStats.config.networkFee ? parentStats.config.networkFee / 100 : 0)) + updateText(`networkLastReward${coin}`, getReadableCoin(parentStats, rewardMinusNetworkFee)); - Object.keys(siblingStats).forEach(key => { - home_GenerateNetworkStats(key, siblingStats[key].config.symbol) - - minerInfo.push({blocks: siblingStats[key].pool.totalBlocks.toString(), - blocksSolo: siblingStats[key].pool.totalBlocksSolo.toString(), - coin: key, - symbol: siblingStats[key].config.symbol, - miners: siblingStats[key].pool.miners.toString(), - minersSolo: siblingStats[key].pool.minersSolo.toString()}) - - efforts.push({coin: key, effort: `${(siblingStats[key].pool.roundHashes / siblingStats[key].network.difficulty * 100).toFixed(1)}%`, symbol: siblingStats[key].config.symbol}); + Object.keys(siblingStats) + .forEach(key => { + home_GenerateNetworkStats(key, siblingStats[key].config.symbol) - if (siblingStats[key].pool.lastBlockFound) { - let lastChildBlockFound = parseInt(siblingStats[key].pool.lastBlockFound) - if (lastChildBlockFound > lastBlockFound) - lastBlockFound = lastChildBlockFound - } + minerInfo.push({ + blocks: siblingStats[key].pool.totalBlocks.toString(), + blocksSolo: siblingStats[key].pool.totalBlocksSolo.toString(), + coin: key, + symbol: siblingStats[key].config.symbol, + miners: siblingStats[key].pool.miners.toString(), + minersSolo: siblingStats[key].pool.minersSolo.toString() + }) - updateText(`networkHashrate${key}`, getReadableHashRateString(siblingStats[key].network.difficulty / siblingStats[key].config.coinDifficultyTarget) + '/sec'); - updateText(`networkDifficulty${key}`, formatNumber(siblingStats[key].network.difficulty.toString(), ' ')); - updateText(`blockchainHeight${key}`, formatNumber(siblingStats[key].network.height.toString(), ' ')); - updateText(`networkLastReward${key}`, getReadableCoin(siblingStats[key], siblingStats[key].lastblock.reward)); - updateText(`poolMiners${key}`, `${siblingStats[key].pool.miners}/${siblingStats[key].pool.minersSolo}`); - updateText(`blocksTotal${key}`, `${siblingStats[key].pool.totalBlocks}/${siblingStats[key].pool.totalBlocksSolo}`); - updateText(`currentEffort${key}`, (siblingStats[key].pool.roundHashes / siblingStats[key].network.difficulty * 100).toFixed(1) + '%'); - }) + efforts.push({ + coin: key, + effort: `${(siblingStats[key].pool.roundHashes / siblingStats[key].network.difficulty * 100).toFixed(1)}%`, + symbol: siblingStats[key].config.symbol + }); + + effortsSolo.push({ + coin: key, + effort: `${(siblingStats[key].pool.roundHashesSolo / siblingStats[key].network.difficulty * 100).toFixed(1)}%`, + symbol: siblingStats[key].config.symbol + }); + + if (siblingStats[key].pool.lastBlockFound) { + let lastChildBlockFound = parseInt(siblingStats[key].pool.lastBlockFound) + if (lastChildBlockFound > lastBlockFound) + lastBlockFound = lastChildBlockFound + } + + updateText(`networkHashrate${key}`, getReadableHashRateString(siblingStats[key].network.difficulty / siblingStats[key].config.coinDifficultyTarget) + '/sec'); + updateText(`networkDifficulty${key}`, formatNumber(siblingStats[key].network.difficulty.toString(), ' ')); + updateText(`blockchainHeight${key}`, formatNumber(siblingStats[key].network.height.toString(), ' ')); + // updateText(`networkLastReward${key}`, getReadableCoin(siblingStats[key], siblingStats[key].lastblock.reward)); + updateText(`poolMiners${key}`, `${siblingStats[key].pool.miners}/${siblingStats[key].pool.minersSolo}`); + updateText(`blocksTotal${key}`, `${siblingStats[key].pool.totalBlocks}/${siblingStats[key].pool.totalBlocksSolo}`); + updateText(`currentEffort${key}`, `PROP: ${(siblingStats[key].pool.roundHashes / siblingStats[key].network.difficulty * 100).toFixed(1)}%`) + updateText(`currentEffortSolo${key}`, `SOLO: ${(siblingStats[key].pool.roundHashesSolo / siblingStats[key].network.difficulty * 100).toFixed(1)}%`) + }) sortElementList($(`#networkStats`), $(`#networkStats>div`), siblingStats) - - if ($(`#poolDetails > div`).length == 0) { - let template = $('#poolDetailTemplate').html() + + if ($(`#poolDetails > div`) + .length == 0) { + let template = $('#poolDetailTemplate') + .html() Mustache.parse(template) - let rendered = Mustache.render(template, {coin:parentStats.config.coin, symbol: parentStats.config.symbol, blocks: minerInfo}) - $(`#poolDetails`).append(rendered) + let rendered = Mustache.render(template, { + coin: parentStats.config.coin, + symbol: parentStats.config.symbol, + blocks: minerInfo + }) + $(`#poolDetails`) + .append(rendered) } - if ($(`#mainPoolStats > div`).length == 0) { - let template = $('#mainPoolTemplate').html() + if ($(`#mainPoolStats > div`) + .length == 0) { + let template = $('#mainPoolTemplate') + .html() Mustache.parse(template) - let rendered = Mustache.render(template, {coin:parentStats.config.coin, blocks: minerInfo, efforts: efforts}) - $(`#mainPoolStats`).append(rendered) + let rendered = Mustache.render(template, { + coin: parentStats.config.coin, + blocks: minerInfo, + efforts: efforts, + effortsSolo: effortsSolo + }) + $(`#mainPoolStats`) + .append(rendered) } - if (lastBlockFound) { - $('#poolLastBlockFound').timeago('update', new Date(lastBlockFound).toISOString()); + $('#poolLastBlockFound') + .timeago('update', new Date(lastBlockFound) + .toISOString()); + } else { + $('#poolLastBlockFound') + .removeAttr('title') + .data('ts', '') + .update('Never'); } - else { - $('#poolLastBlockFound').removeAttr('title').data('ts', '').update('Never'); + + if (lastBlockFoundSolo) { + $('#poolLastBlockFoundSolo') + .timeago('update', new Date(lastBlockFoundSolo) + .toISOString()); + } else { + $('#poolLastBlockFoundSolo') + .removeAttr('title') + .data('ts', '') + .update('Never'); } let lastHash = updateText('lastHash', parentStats.lastblock.hash) @@ -2279,10 +3070,10 @@ function home_InitTemplate(parentStats, siblingStats) { updateText('poolHashrateSolo', `SOLO: ${getReadableHashRateString(parentStats.pool.hashrateSolo)}/sec`); - var hashPowerSolo = parentStats.pool.hashrateSolo / (parentStats.network.difficulty / parentStats.config.coinDifficultyTarget) * 100; - updateText ('hashPowerSolo', hashPowerSolo.toFixed(2) + '%'); + var hashPowerSolo = parentStats.pool.hashrateSolo / parentStats.network.networkhashps * 100; + updateText('hashPowerSolo', hashPowerSolo.toFixed(2) + '%'); - var hashPower = parentStats.pool.hashrate / (parentStats.network.difficulty / parentStats.config.coinDifficultyTarget) * 100; + var hashPower = parentStats.pool.hashrate / parentStats.network.networkhashps * 100; updateText('hashPower', hashPower.toFixed(2) + '%'); @@ -2291,20 +3082,27 @@ function home_InitTemplate(parentStats, siblingStats) { var totalFee = parentStats.config.fee; - if (Object.keys(parentStats.config.donation).length) { + var soloFee = parentStats.config.soloFee; + if (Object.keys(parentStats.config.donation) + .length) { var totalDonation = 0; - for(var i in parentStats.config.donation) { + for (var i in parentStats.config.donation) { totalDonation += parentStats.config.donation[i]; } totalFee += totalDonation; + soloFee += totalDonation; } - updateText('poolFee', (totalFee > 0 && totalFee != 100 ? floatToString(totalFee) : (totalFee == 100 ? '100' : '0')) + '%'); + updateText('finderReward', parentStats.config.finderReward + '%'); + + updateText('poolFee', (totalFee > 0 && totalFee != 100 ? totalFee.toFixed(2): (totalFee == 100 ? '100' : '0')) + '%/' + soloFee.toFixed(2) + '%'); updateText('paymentsInterval', getReadableTime(parentStats.config.paymentsInterval)); - updateText('paymentsMinimum', getReadableCoin(parentStats, parentStats.config.minPaymentThreshold)); + updateText('paymentsMinimum', getReadableCoin(parentStats, parentStats.config.minPaymentThreshold, 2, true)); - updateText('blockSolvedTime', getReadableTime(parentStats.network.difficulty / parentStats.pool.hashrate)); + updateText('blockSolvedTime', `PROP: ${getReadableTime(parentStats.pool.blockSolvedTime)}`); + updateText('blockSolvedTimeSolo', `SOLO: ${getReadableTime(parentStats.pool.blockSolvedTimeSolo)}`); updateText(`currentEffort${coin}`, (parentStats.pool.roundHashes / parentStats.network.difficulty * 100).toFixed(1) + '%'); } +