Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Masternode list fix and rewards #119

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions assets/style/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,11 @@ button {
font-size: large;
height: 85%;
}
.masternode-rewards-list {
overflow: auto;
font-size: large;
height: 55%;
}

#staking-rectangle {
position: relative;
Expand Down Expand Up @@ -683,6 +688,7 @@ button {
margin-right: auto !important;
height: 220px;
margin: 30px 5px 10px;
display: inline-block;
}


Expand Down
21 changes: 20 additions & 1 deletion index.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,25 @@ <h4 class="stake-balances" style="background-color: #2c0044; border-radius: 10px
</h4>
<h2 id="mnLastSeen" class="stake-balances" style="overflow-wrap: anywhere; top: 50%; left: 50%; transform: translate(-50%, -50%); position: absolute; width: 100%; padding: 10px; font-size: xx-large;" id="mnStatus"></h2>
</div>
<div class="stake-box large-box col-md-4">
<h4 class="stake-balances" style="background-color: #2c0044; border-radius: 10px;">
Last Paid
</h4>
<h2 id="mnLastPaid" class="stake-balances" style="overflow-wrap: anywhere; top: 50%; left: 50%; transform: translate(-50%, -50%); position: absolute; width: 100%; padding: 10px; font-size: xx-large;" id="mnStatus"></h2>
</div>
<!-- // MASTERNODE REWARD LIST -->
<div class="stake-box large-box col-md-4">
<div id="masternode-rewards-title">
<h4 class="stake-balances" style="background-color: #2c0044; border-radius: 10px;"><span data-i18n="masternode">Masternode</span> <span data-i18n="rewards">Rewards</span></h4>
</div>
<div class="masternode-rewards-list">
<div id="masternode-rewards-content"></div>
<button type="button" id="masternodeLoadMore" onclick="MPW.updateMasternodeRewardsGUI()">
<span class="buttoni-icon" id="stakingLoadMoreIcon"><i class="fas fa-sync fa-tiny-margin"></i></span>
<span class="buttoni-text" data-i18n="masternodeLoadMore">Load more</span>
</button>
</div>
</div>
</div>

<br />
Expand All @@ -992,6 +1011,7 @@ <h2 id="mnLastSeen" class="stake-balances" style="overflow-wrap: anywhere; top:
</button>
</center>
</div>
</div>

<div id="Settings" class="tabcontent">
<label for="currency" data-i18n="settingsCurrency">Choose a display currency:</label>
Expand Down Expand Up @@ -1050,7 +1070,6 @@ <h2 id="mnLastSeen" class="stake-balances" style="overflow-wrap: anywhere; top:
</div>
</div>
</div>
</div>
<!--
Alert
-->
Expand Down
3 changes: 3 additions & 0 deletions locale/en/translation.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ export const en_translation = {
stakeUnstake:"Unstake", //
stakeLoadMore:"Load more", //

// Masternode
masternodeLoadMore:"Load more", //

// Governance
contestedProposalsTitle:"Contested Proposals",
contestedProposalsDesc:"These are proposals that received an overwhelming amount of downvotes, making it likely spam or a highly contestable proposal.",
Expand Down
3 changes: 3 additions & 0 deletions locale/template/translation.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ var translation = {
stakeUnstake:"", //Unstake
stakeLoadMore:"", //Load more

// Masternode
masternodeLoadMore:"", //Load more

// Governance
contestedProposalsTitle:"", //Contested Proposals
contestedProposalsDesc:"", //These are proposals that received an overwhelming amount of downvotes, making it likely spam or a highly contestable proposal.
Expand Down
3 changes: 3 additions & 0 deletions locale/uwu/translation.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ export const uwu_translation = {
stakeUnstake:"", //Unstake
stakeLoadMore:"Lowoad Mowore", //Load more

// Masternode
masternodeLoadMore:"Lowoad Mowore", //Load more

// Governance
contestedProposalsTitle:"Contwested Pwoposals",
contestedProposalsDesc:"Dees are pwoposals dat received an overwhelming ameownt of downwotes, making it likely spam or a highly contwestable pwoposal.",
Expand Down
52 changes: 52 additions & 0 deletions scripts/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export function start() {
domGuiBalanceBoxStaking: document.getElementById(
'guiBalanceBoxStaking'
),
domGuiMasternodeLoadMore: document.getElementById('masternodeLoadMore'),
domGuiDelegateAmount: document.getElementById('delegateAmount'),
domGuiUndelegateAmount: document.getElementById('undelegateAmount'),
domStakeTab: document.getElementById('stakeTab'),
Expand Down Expand Up @@ -125,6 +126,7 @@ export function start() {
domMnNetType: document.getElementById('mnNetType'),
domMnNetIP: document.getElementById('mnNetIP'),
domMnLastSeen: document.getElementById('mnLastSeen'),
domMnLastPaid: document.getElementById('mnLastPaid'),

domAccessWallet: document.getElementById('accessWallet'),
domImportWallet: document.getElementById('importWallet'),
Expand Down Expand Up @@ -154,6 +156,12 @@ export function start() {
domStakingRewardsTitle: document.getElementById(
'staking-rewards-title'
),
domMasternodeRewardsList: document.getElementById(
'masternode-rewards-content'
),
domMasternodeRewardsTitle: document.getElementById(
'masternode-rewards-title'
),
domMnemonicModalContent: document.getElementById(
'ModalMnemonicContent'
),
Expand Down Expand Up @@ -503,6 +511,41 @@ export async function updateStakingRewardsGUI() {
doms.domStakingRewardsList.innerHTML = strList;
}

export async function updateMasternodeRewardsGUI() {
const network = getNetwork();
const arrMasternodeRewards = await network.getMasternodeRewards();

if (network.areRewardsMasternodeComplete) {
// Hide the load more button
doms.domGuiMasternodeLoadMore.style.display = 'none';
}

//DOMS.DOM-optimised list generation
const strList = arrMasternodeRewards
.map(
(cReward) =>
`<i style="opacity: 0.75; cursor: pointer" onclick="window.open('${
cExplorer.url + '/tx/' + cReward.id
}', '_blank')">${new Date(
cReward.time * 1000
).toLocaleDateString()}</i> <b>+${cReward.amount} ${
cChainParams.current.TICKER
}</b>`
)
.join('<br>');
// Calculate total
const nRewards = arrMasternodeRewards.reduce(
(total, reward) => total + reward.amount,
0
);
if(nRewards.length != 0) {
// UpdateDOMS.DOM
doms.domMasternodeRewardsTitle.style.cssText = 'background-color:#2c0044;border-radius:10px;margin-top:1rem;margin-bottom:0.75rem;padding:5px;font-size:22px;font-weight:500;line-height:1.2;font-family:Montserrat,sans-serif!important;';
doms.domMasternodeRewardsTitle.innerHTML = `Masternode Rewards: ≥ ${nRewards} ${cChainParams.current.TICKER}`;
doms.domMasternodeRewardsList.innerHTML = strList;
}
}

/**
* Open the Explorer in a new tab for the loaded master public key
*/
Expand Down Expand Up @@ -1555,6 +1598,7 @@ export async function updateMasternodeTab() {

async function refreshMasternodeData(cMasternode, fAlert = false) {
const cMasternodeData = await cMasternode.getFullData();
const cMasternodeReward = await cMasternode.getNextMasternodePaymentInMinutes();
if (debug) console.log(cMasternodeData);

// If we have MN data available, update the dashboard
Expand All @@ -1571,6 +1615,14 @@ async function refreshMasternodeData(cMasternode, fAlert = false) {
doms.domMnLastSeen.innerText = new Date(
cMasternodeData.lastseen * 1000
).toLocaleTimeString();

if (cMasternodeReward > 30) {
doms.domMnLastPaid.innerText = "~" + cMasternodeReward + " blocks";
} else if (cMasternodeReward == 0) {
doms.domMnLastPaid.innerText = "Not yet paid";
} else {
doms.domMnLastPaid.innerText = "Coming soon";
}
}

if (cMasternodeData.status === 'MISSING') {
Expand Down
1 change: 1 addition & 0 deletions scripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export {
toggleBottomMenu,
createProposal,
updateStakingRewardsGUI,
updateMasternodeRewardsGUI,
} from './global.js';
export { generateWallet, getNewAddress, importWallet } from './wallet.js';
export { toggleTestnet, toggleDebug } from './settings.js';
Expand Down
51 changes: 49 additions & 2 deletions scripts/masternode.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default class Masternode {
}

/**
@return {Promise<Object>} The object containing masternode information for this masternode
* @return {Promise<Object>} The object containing masternode information for this masternode
*/
async getFullData() {
const strURL = `${cNode.url}/listmasternodes?params=${this.collateralTxId}`;
Expand All @@ -66,13 +66,60 @@ export default class Masternode {
}

/**
@return {Promise<string>} The status of this masternode.
* @return {Promise<string>} The status of this masternode.
*/
async getStatus() {
const cMasternode = await this.getFullData();
return cMasternode ? cMasternode.status : 'MISSING';
}

/**
*
* @returns The last paid time in seconds of the masternode.
*/
async getLastPaidTime() {
const lastPaidTime = await this.getFullData();
return lastPaidTime.lastpaid;
}

/**
*
* @returns The current masternode count on the network.
*/
async getMasternodeCount() {
const strURL = `${cNode.url}/getmasternodecount?params=`;
try {
const cMasternodeCount = await fetch(strURL);
return cMasternodeCount.total;
} catch (e) {
// Recatch when polling for service failure
console.error(e);
return 'EXPLORER_DOWN';
}
}

/**
*
* @returns Time in minutes to next payment for the masternode
*/
async getNextMasternodePaymentInMinutes() {
// Last paid time in seconds
const lastPaid = await this.getLastPaidTime();
if (lastPaid == 0) {
// return 0 for not yet paid status
return lastPaid;
}
// Masternode count
const mnCount = this.getMasternodeCount();
// Current time in seconds
const timeNow = Math.floor(Date.now() / 1000);
// Convert current time to minutes
const lastPaidInMinutes = (timeNow - lastPaid) / 60;
// MasternodeCount - Minutes since last paid (1 MN per minute average) equals time to next payment
const timeToNextPay = mnCount - lastPaidInMinutes;
return timeToNextPay;
}

/**
* @param {String} ip
* @param {Number} port
Expand Down
71 changes: 71 additions & 0 deletions scripts/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createAlert } from './misc.js';
import { Mempool, UTXO } from './mempool.js';
import { getEventEmitter } from './event_bus.js';
import { STATS, cStatKeys, cAnalyticsLevel } from './settings.js';
import Masternode from './masternode.js';

/**
* Virtual class rapresenting any network backend
Expand All @@ -19,6 +20,7 @@ export class Network {

this.lastWallet = 0;
this.areRewardsComplete = false;
this.areRewardsMasternodeComplete = false;
}

/**
Expand Down Expand Up @@ -103,7 +105,9 @@ export class ExplorerNetwork extends Network {
this.blocks = 0;

this.arrRewards = [];
this.arrMnRewards = [];
this.rewardsSyncing = false;
this.rewardsMasternodeSyncing = false;
}

error() {
Expand Down Expand Up @@ -339,6 +343,73 @@ export class ExplorerNetwork extends Network {
}
}

/**
* Fetches Masternode Rewards per Local Storage
* @returns Filtered array of Masternode rewards
*/
async getMasternodeRewards() {
if (this.rewardsMasternodeSyncing) {
return this.arrMnRewards;
}
if(localStorage.getItem('masternode')) {
const cMasternode = new Masternode(
JSON.parse(localStorage.getItem('masternode'))
);
const cMasternodeData = await cMasternode.getFullData();
if (this.rewardsMasternodeSyncing) {
return this.arrMnRewards;
}
try {
if (!this.enabled || this.areRewardsMasternodeComplete)
return this.arrMnRewards;
this.rewardsMasternodeSyncing = true;
const nHeight = this.arrMnRewards.length
? this.arrMnRewards[this.arrMnRewards.length - 1].blockHeight
: 0;
const mapPaths = new Map();
let cData;
cData = await (
await fetch(
`${
this.strUrl
}/api/v2/address/${cMasternodeData.addr}?details=txs&pageSize=500&to=${
nHeight ? nHeight - 1 : 0
}`
)
).json();
mapPaths.set(cMasternodeData.addr, ':)');
if (cData && cData.transactions) {
// Update rewards
this.arrMnRewards = this.arrMnRewards.concat(
cData.transactions
.filter(
(tx) => tx.vout[0].addresses[0] === 'CoinStake TX'
)
.map((tx) => {
return {
id: tx.txid,
time: tx.blockTime,
blockHeight: tx.blockHeight,
amount: tx.vout[2].value / COIN,
};
})
.filter((tx) => tx.amount != 0)
);

// If the results don't match the full 'max/requested results', then we know the rewards are complete
if (cData.transactions.length !== cData.itemsOnPage) {
this.areMasternodeRewardsComplete = true;
}
}
return this.arrMnRewards;
} catch (e) {
console.error(e);
} finally {
this.rewardsMasternodeSyncing = false;
}
}
}

setMasterKey(masterKey) {
this.masterKey = masterKey;
this.arrRewards = [];
Expand Down
2 changes: 2 additions & 0 deletions scripts/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
getBalance,
getStakingBalance,
updateStakingRewardsGUI,
updateMasternodeRewardsGUI,
} from './global.js';
import { fWalletLoaded, masterKey } from './wallet.js';
import { cChainParams } from './chain_params.js';
Expand Down Expand Up @@ -321,6 +322,7 @@ export function toggleTestnet() {
getBalance(true);
getStakingBalance(true);
updateStakingRewardsGUI();
updateMasternodeRewardsGUI();
}

export function toggleDebug() {
Expand Down