V2EX Solana Token Checker

在 V2EX 用户首页和评论列表中显示 $V2EX 代币持仓量

当前为 2025-07-29 提交的版本,查看 最新版本

// ==UserScript==
// @name         V2EX Solana Token Checker
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  在 V2EX 用户首页和评论列表中显示 $V2EX 代币持仓量
// @match        https://*.v2ex.com/member/*
// @match        https://v2ex.com/member/*
// @match        https://*.v2ex.com/t/*
// @match        https://v2ex.com/t/*
// @grant        none
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(async function () {
  'use strict';

  const TOKEN_MINT = "9raUVuzeWUk53co63M4WXLWPWE4Xc6Lpn7RS9dnkpump";

  async function getSplTokenAmountAndPubkey(owner, mint) {
    const url = "https://solana-rpc.publicnode.com";
    const payload = {
      "jsonrpc": "2.0",
      "id": 1,
      "method": "getTokenAccountsByOwner",
      "params": [
        owner,
        { "mint": mint },
        { "encoding": "jsonParsed" }
      ]
    };

    const res = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(payload)
    });

    const data = await res.json();

    try {
      const value = data.result.value;
      if (value === null || value.length === 0) {
        return {
          amount: "0.0",
          pubkey: ""
        };
      } else {
        let amount = value[0].account.data.parsed.info.tokenAmount.uiAmount;
        amount = amount == 0 ? "0.0" : amount;
        return {
          amount: amount,
          pubkey: value[0].pubkey
        };
      }
    } catch (e) {
      return null;
    }
  }

  if (window.location.pathname.startsWith('/member/')) {
    const scripts = Array.from(document.querySelectorAll('script'));
    let address = null;

    for (const script of scripts) {
      const text = script.textContent.trim();
      const match = text.match(/const\s+address\s*=\s*"([^"]+)"/);
      if (match) {
        address = match[1];
        break;
      }
    }

    if (!address) {
      return;
    }

    const result = await getSplTokenAmountAndPubkey(address, TOKEN_MINT);
    if (result === null) {
      return;
    }

    const balance = result.amount;
    const linkAddress = result.pubkey ? address : result.pubkey;
    const newHtml = `
      <div class="sep5"></div>
      <div class="flex-one-row" style="display: inline-flex; gap: 5px;">
          <div class="badges">
              <div class="badge" style="background-color: #000; color: #fff;">$V2EX</div>
          </div>
          <span>持有 </span>
          <a href="https://solscan.io/account/${linkAddress}" target="_blank">${balance}</a>
      </div>
  `;

    let targetElement = document.querySelector('a[href="/top/dau"]');
    if (targetElement) {
      targetElement.insertAdjacentHTML('afterend', newHtml);
    } else {
      const span = [...document.querySelectorAll('span.gray')].find(el =>
        el.textContent.includes('号会员,加入于')
      );
      if (span) {
        span.insertAdjacentHTML('beforeend', newHtml);
      }
    }
  } else {
    document.querySelectorAll('div.thank_area').forEach(div => {
      if (/^thank_area_\w+$/.test(div.id)) {
        const a = document.createElement('a');
        a.href = '#;';
        a.className = 'thank';
        a.innerHTML = '查看 $V2EX 持仓';
        a.addEventListener('click', async (e) => {
          e.preventDefault();

          const td = div.closest('td');
          if (!td) {
            a.innerHTML = '加载失败';
            return;
          }

          const userLink = td.querySelector('a.dark[href^="/member/"]');
          if (userLink) {
            a.innerHTML = '加载中...';
            try {
              const res = await fetch(userLink.href);
              const html = await res.text();
              const match = html.match(/<script>\s*const address = "(.*?)";\s*<\/script>/);
              if (match && match[1]) {
                const result = await getSplTokenAmountAndPubkey(match[1], TOKEN_MINT);
                if (result === null) {
                  a.innerHTML = '加载失败';
                } else {
                  a.innerHTML = `持有 ${result.amount}`;
                }
              } else {
                a.innerHTML = '未绑定 Solana 钱包';
              }
            } catch (err) {
              a.innerHTML = '加载失败';
            }
          } else {
            a.innerHTML = '加载失败';
          }
        });

        div.insertAdjacentHTML('beforeend', '&nbsp;&nbsp;');
        div.insertAdjacentElement('beforeend', a);
      }
    });
  }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址