Dexscreener MEV 地址标注

Dexscreener MEV 地址标注 & GMGN 链接替换

// ==UserScript==
// @name         Dexscreener MEV 地址标注
// @namespace    https://www.tampermonkey.net/
// @version      0.2.0
// @description  Dexscreener MEV 地址标注 & GMGN 链接替换
// @author       https://x.com/0xshimmer
// @match        https://dexscreener.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=dexscreener.com
// @grant        none
// @license MIT
// ==/UserScript==



(function() {
    'use strict';

    function addIconsToRow(row) {
        const addressCell = row.firstChild.children[6];
        const addressLink = addressCell.querySelector('a');
        if (!addressLink || addressCell.querySelector('.custom-icon')) return;

        const address = addressLink.href.split('/account/')[1];

        // const gmgnLink = document.createElement('a');
        // gmgnLink.href = `https://gmgn.ai/sol/address/${address}`;
        // gmgnLink.target = '_blank';
        // gmgnLink.innerHTML = '🔍';
        // gmgnLink.className = 'custom-icon';
        // gmgnLink.style.marginRight = '5px';
        // gmgnLink.style.textDecoration = 'none';

        addressLink.href = `https://gmgn.ai/sol/address/${address}`;

        const copyButton = document.createElement('span');
        copyButton.innerHTML = '📋';
        copyButton.className = 'custom-icon';
        copyButton.style.cursor = 'pointer';
        copyButton.style.marginRight = '5px';
        copyButton.onclick = () => {
            navigator.clipboard.writeText(address);
            copyButton.innerHTML = '✅';
            setTimeout(() => {
                copyButton.innerHTML = '📋';
            }, 1000);
        };

        // addressCell.insertBefore(gmgnLink, addressCell.firstChild);
        addressCell.insertBefore(copyButton, addressCell.firstChild);
    }

    function highlightAdjacentDuplicateRows() {

        const rows = document.querySelectorAll('tr[data-index]');
        if (!rows.length) return;

        for (let i = 0; i < rows.length - 1; i++) {
            const currentRow = rows[i];
            const nextRow = rows[i + 1];

            addIconsToRow(currentRow);
            addIconsToRow(nextRow);

            const type1 = currentRow.firstChild.children[1].textContent;
            const type2 = nextRow.firstChild.children[1].textContent;

            const address1 = currentRow.firstChild.children[6].textContent.slice(0, 6);
            const address2 = nextRow.firstChild.children[6].textContent.slice(0, 6);

            const time1 = currentRow.firstChild.children[0].textContent;
            const time2 = nextRow.firstChild.children[0].textContent;

            if (time1 === time2 && address1 === address2 && type1 != type2) {
                currentRow.style.backgroundColor = 'grey';
                nextRow.style.backgroundColor = 'grey';
                // currentRow.hidden = true;
                // nextRow.hidden = true;
                i++;
            }
        }
    }


    function setupTableObserver() {

        const firstRow = document.querySelector('tr[data-index]');
        if (!firstRow) {
            setTimeout(setupTableObserver, 1000);
            return;
        }

        let timeout;
        const observer = new MutationObserver((mutations) => {
            if (mutations.some(mutation =>
                mutation.addedNodes.length &&
                Array.from(mutation.addedNodes).some(node =>
                    node.classList && node.classList.contains('custom-icon')
                ))) {
                return;
            }

            clearTimeout(timeout);
            timeout = setTimeout(() => {
                console.log('Rows updated');
                highlightAdjacentDuplicateRows();
            }, 200);
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
        highlightAdjacentDuplicateRows();
    }


    const documentObserver = new MutationObserver(() => {
        const table = document.querySelector('table');
        if (table && !table._hasObserver) {
            console.log('Table found, initializing...');
            table._hasObserver = true;
            setupTableObserver();
        }
    });


    documentObserver.observe(document.body, {
        childList: true,
        subtree: true
    });
})();