mmstick / Nexo Token Metrics

// ==UserScript==
// @name         Nexo Token Metrics
// @namespace    https://openuserjs.org/user/mmstick
// @description  Show Nexo price & required Nexo to achieve interest
// @version      0.1
// @author       Michael Aaron Murphy <mmstick@pm.me>
// @match        https://platform.nexo.io/
// @grant        none
// @run-at       document-idle
// @copyright    2020, Michael Aaron Murphy
// @license      MIT
// ==/UserScript==

async function nexo() {
  while (!connect_elements()) {
    await sleep(1000)
  }
}

/** Returns either null, undefined, or a collection of child nodes */
function fetch_tokens() {
  const table = document.getElementsByClassName("AssetList")
  if (!table) return null

  const tbody = table[0]
  if (!tbody) return null

  const tokens = tbody.childNodes[1]
  if (!tokens) return null

  return tokens.childNodes;
}

function connect_elements() {
  let tokens = fetch_tokens();
  if (!tokens) return false;

  for (const token of tokens) {
    const balance_el = token.childNodes[1]
    if (balance_el) balance_el.onchange = () => update_balance();
  }

  update_balance()

  return true
}

function update_balance() {
  let tokens = fetch_tokens();
  if (!tokens) return;

  let nexo_tokens = 0
  let nexo_balance = 0
  let total_balance = 0

  for (const token of tokens) {
    const [name_el, balance_el] = token.childNodes
    if (name_el && balance_el) {
      const balance = parseFloat(
        balance_el
        .firstChild
        .lastChild
        .innerText
        .slice(1)
        .replace(/,/g, '')
      )

      total_balance += balance;

      if (!nexo_balance && name_el.innerText === "Nexo Token") {
        nexo_balance = balance;
        nexo_tokens = parseFloat(balance_el.firstChild.firstChild.innerText.split(' ')[1].replace(/,/g, ''));
      }
    }
  }

  update_html(nexo_tokens, nexo_balance, total_balance);
}

function update_html(nexo_tokens, nexo_usd, total) {
  const nexo_per_usd = nexo_usd / nexo_tokens;
  const nexo_required = (total / 10) / nexo_per_usd;

  const html = `<div id="nexo_totals">
    <div>
        <span class="primary">$${total.toFixed(2)}</span>
        <h6>Total Assets</h6>
    </div>
    <div>
        <span class="special">$${nexo_usd} (${((nexo_usd / total) * 100).toFixed(2)}%)</span>
        <h6>Total NEXO (${nexo_tokens})</h6>
    </div>
    <div>
        <span class="special">$${nexo_per_usd.toFixed(4)}</span>
        <h6>Nexo Price</h6>
    </div>
    <div>
        <span class="success">${nexo_required.toFixed(2)}</span>
        <h6>Tokens Required</h6>
    </div>
    <div>
        <span class="success">${(nexo_tokens - nexo_required).toFixed(2)}</span>
        <h6>Excess Tokens</h6>
    </div>
    <style>
        #nexo_totals {
            display: flex;
            border: 0.0625rem solid #e4e7ec;
            border-radius: 0.25rem;
            padding: 0.625rem 1.25rem;
            margin-top: 1em;
        }

        #nexo_totals div {
            display: flex;
            flex-direction: column;
            flex-grow: 1;
            padding: 0 2.5rem;
        }

        #nexo_totals div span {
            font-size: 1.5rem;
            font-weight: 700;
        }

        #nexo_totals div+div {
          border-left: 0.0625rem solid #e4e7ec;
        }
    </style>
</div>`;

  const prev = document.getElementById("nexo_totals");
  if (prev) prev.parentNode.removeChild(prev);

  const element = document.getElementsByClassName("AccountFinancialOverview")[0];

  element.insertAdjacentHTML("afterEnd", html);
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

nexo()