Greasy Fork is available in English.

DeFier

DeFier Helpers

// ==UserScript==
// @name         DeFier
// @namespace    https://chengxun.cc/
// @version      21
// @description  DeFier Helpers
// @author       chengxuncc
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ethereum.org
// @match        https://*.etherscan.io/*
// @match        https://*.arbiscan.io/*
// @match        https://*.blastscan.io/*
// @match        https://*.bscscan.com/*
// @match        https://*.basescan.org/*
// @match        https://*.polygonscan.com/*
// @match        https://*.snowtrace.io/*
// @match        https://*.snowscan.xyz/*
// @match        https://*.ftmscan.com/*
// @match        https://*.uniswap.org/*
// @match        https://*.1inch.io/*
// @match        https://*.sparkprotocol.io/*
// @match        https://*.spark.fi/*
// @match        https://*.arbitrum.io/*
// @match        https://*.debank.com/*
// @match        https://*.cronoscan.com/*
// @match        https://*.dedaub.com/*
// @grant        GM_webRequest
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// ==/UserScript==

function onElementInserted(containerSelector, elementSelector, callback) {
    let onMutationsObserved = function (mutations) {
        mutations.forEach(function (mutation) {
            if (mutation.addedNodes.length) {
                let elements = $(mutation.addedNodes).find(elementSelector);
                for (var i = 0, len = elements.length; i < len; i++) {
                    callback.bind(elements[i])();
                }
            }
        });
    };

    let target = $(containerSelector)[0];
    let config = {childList: true, subtree: true};
    let MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    let observer = new MutationObserver(onMutationsObserved);
    observer.observe(target, config);
}

function addJQuery(callback) {
    var script = document.createElement("script");
    script.setAttribute("src", "https://code.jquery.com/jquery-3.6.0.min.js");
    script.addEventListener('load', function () {
        callback();
    }, false);
    document.body.appendChild(script);
}

// waitForElm does not require jQuery
function waitForElm(selector) {
    return new Promise(resolve => {
        if (document.querySelector(selector)) {
            return resolve(document.querySelector(selector));
        }

        const observer = new MutationObserver(mutations => {
            if (document.querySelector(selector)) {
                observer.disconnect();
                resolve(document.querySelector(selector));
            }
        });

        // If you get "parameter 1 is not of type 'Node'" error, see https://stackoverflow.com/a/77855838/492336
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    });
}

(function () {
    'use strict';
    let hostname = window.location.hostname.replace(/(.*\.)?([^.]+\..*)/mg, "$2");
    let rules = [];

    console.log("DeFier loaded for", hostname);

    switch (hostname) {
        case "etherscan.io":
        case "arbiscan.io":
        case "blastscan.io":
        case "bscscan.com":
        case "basescan.org":
        case "polygonscan.com":
        case "ftmscan.com":
        case "snowscan.xyz":
        case "cronoscan.com":
            let handleFunc = function () {
                let shouldSkip = (e) => {
                    if (!e) {
                        return false;
                    }
                    return $(e).hasClass("defier") || $(e).hasClass("page-link") || $(e).hasClass("card-footer") || $(e).hasClass("btn") || $(e).hasClass("dropdown-item");
                }
                let shouldSkipCopy = (e) => {
                    if (!e) {
                        return false;
                    }
                    return $(e).hasClass("js-clipboard");
                }
                if (shouldSkip($(this)) || shouldSkip($(this).next("a")) || shouldSkip($(this).parent().next("a"))) {
                    return;
                }
                if (!$(this).attr("href")) {
                    return;
                }
                let hexes = $(this).attr("href").match(/0x[0-9a-zA-Z]{40,64}/g);
                if (hexes) {
                    let hex = hexes[hexes.length - 1];
                    if (window.location.pathname.startsWith("/address/" + hex)) {
                        hex = hexes[0];
                    }
                    let randomId = "linkIcon-" + Math.random().toString(36).substring(7);

                    let extLink = (hex.length === 42 ? "/address/" : "/tx/") + hex;
                    let sib = $(this);
                    if (sib.parent().hasClass("text-truncate")) {
                        sib = sib.parent();
                    }
                    let skipCopy = false;
                    switch (true) {
                        case shouldSkipCopy($(this)):
                            skipCopy = true;
                            break;
                        case shouldSkipCopy($(this).next("a")):
                            skipCopy = true;
                            sib = $(this).next("a");
                            break;
                        case shouldSkipCopy($(this).parent().next("a")):
                            skipCopy = true;
                            sib = $(this).parent().next("a");
                            break;
                    }
                    if (!this.href.includes(extLink) && !window.location.pathname.includes(extLink)) {
                        $(`<a class="link-secondary defier" href="${extLink}" target="_blank"
                          data-bs-toggle="tooltip" title="${hex}">
                        <i id="${randomId}" class="far fa-fw fa-external-link"></i>
                       </a>`).insertAfter(sib);
                    }
                    if (!skipCopy) {
                        $(`<a class="js-clipboard link-secondary defier" href="javascript:;" data-clipboard-text="${hex}"
                        onclick="navigator.clipboard.writeText('${hex}')"
                        data-bs-toggle="tooltip"
                        data-hs-clipboard-options="{
                            &quot;type&quot;: &quot;tooltip&quot;,
                            &quot;successText&quot;: &quot;Copied!&quot;,
                            &quot;classChangeTarget&quot;: &quot;#${randomId}&quot;,
                            &quot;defaultClass&quot;: &quot;fa-copy&quot;,
                            &quot;successClass&quot;: &quot;fa-check&quot;
                        }" title="${hex}">
                            <i id="${randomId}" class="far fa-fw fa-copy"></i>
                       </a>`).insertAfter(sib);
                        $(this).addClass("me-1");
                    }
                }
            };
            $('a').each(handleFunc);
            onElementInserted('body', 'a', handleFunc);
            $(`[data-bs-toggle="tooltip"]`).each(function () {
                bootstrap.Tooltip.getOrCreateInstance(this);
            });
            HSCore.components.HSClipboard.init('.js-clipboard');
            break;
        case "uniswap.org":
            rules.push({selector: 'https://gateway.ipfs.io/ipns/unsupportedtokens.uniswap.org', action: 'cancel'});
            rules.push({
                selector: 'https://raw.githubusercontent.com/The-Blockchain-Association/sec-notice-list/master/ba-sec-list.json',
                action: 'cancel'
            });
            rules.push({
                selector: 'https://api.uniswap.org/v1/screen',
                action: 'cancel'
            });
            rules.push({selector: '*ipfs/QmUdN2tTpLXKaR1GD7ZSoafwVLBLuEHkjCXMQpxLVAdE6C/*', action: 'cancel'});
            break
        case "1inch.io":
            rules.push({
                selector: 'https://defi.1inch.io/blacklist/v1.0/check/1/*',
                action: {
                    redirect: {
                        from: "(.+)/0x[0-9a-zA-Z]+(.*)?",
                        to: '$1/0x083fc10cE7e97CaFBaE0fE332a9c4384c5f54E45$2'
                    }
                }
            });
            break;
        case "spark.fi":
            rules.push({selector: 'https://api.spark.fi/*/status*', action: 'cancel'});
            break;
        case "arbitrum.io":
            rules.push({selector: 'https://bridge.arbitrum.io/api/screenings?address=*', action: 'cancel'});
            break;
        case "debank.com":
            let shouldSkip = (e) => {
                if (!e) {
                    return false;
                }
                return $(e).hasClass("page-link") || $(e).hasClass("card-footer") || $(e).hasClass("btn") || $(e).hasClass("dropdown-item");
            }
            let shouldSkipCopy = (e) => {
                if (!e) {
                    return false;
                }
                return $(e).hasClass("js-clipboard");
            }
            onElementInserted('body', 'a', function () {
                if (shouldSkip($(this)) || shouldSkip($(this).next("a")) || shouldSkip($(this).parent().next("a"))) {
                    return;
                }
                if (!$(this).attr("href")) {
                    return;
                }
                let hexes = $(this).attr("href").match(/0x[0-9a-zA-Z]{40,64}/g);
                if (hexes) {
                    let hex = hexes[hexes.length - 1];
                    let sib = $(this);
                    let skipCopy = shouldSkipCopy($(this)) || shouldSkipCopy($(this).next("a")) || shouldSkipCopy($(this).parent().next("a"));
                    if (!skipCopy) {
                        $(`<a class="js-clipboard link-secondary" href="javascript:;" data-clipboard-text="${hex}"
                        onclick="navigator.clipboard.writeText('${hex}')"
                        style="margin-left: 4px;"
                        title="${hex}">
                            <svg width="20" height="20" viewBox="0 0 20 20" fill="none" style="cursor: pointer; color: var(--bg-default-color); width: 20px; height: 20px;"><g clip-path="url(#clip0_41337_131554)"><path d="M10 20C15.5228 20 20 15.5228 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20Z" fill="currentColor"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M9.39844 5.78906H11.8055C12.0503 5.78906 12.2865 5.87885 12.4696 6.0414L13.5269 6.98057C13.7406 7.17035 13.8628 7.44246 13.8628 7.72823V11.5871C13.8628 12.1394 13.4151 12.5871 12.8628 12.5871H9.39844C8.84615 12.5871 8.39844 12.1394 8.39844 11.5871V6.78906C8.39844 6.23678 8.84615 5.78906 9.39844 5.78906Z" stroke="#8B93A7"></path><path d="M11.2613 12.9045V13.4982C11.2613 14.1017 10.772 14.591 10.1684 14.591H6.88976C6.28617 14.591 5.79688 14.1017 5.79688 13.4982V8.88585C5.79688 8.28227 6.28617 7.79297 6.88976 7.79297H8.14342" stroke="#8B93A7"></path><path d="M11.4062 5.78906V7.63225C11.4062 7.85316 11.5853 8.03225 11.8062 8.03225H13.8574" stroke="#8B93A7"></path></g><defs></defs></svg>
                       </a>`).insertAfter(sib);
                    }
                }
            });
            break;
        case "snowtrace.io":
            window.location.replace(window.location.href.replace("snowtrace.io", "snowscan.xyz"));
            break
        case "dedaub.com":
            waitForElm("input.css-76nxxx").then((elm) => {
                addJQuery(function () {
                    if (!$) {
                        console.error("DeFier: jquery not loaded");
                        return;
                    }
                    setInterval(() => {
                        let addressInput = $("input.css-76nxxx");
                        if (addressInput[0] && !$._data(addressInput[0], "events")) {
                            addressInput.keypress(function (e) {
                                if (e.which === 13) {
                                    // [ENTER]
                                    let hex = $(this).val().trim();
                                    if (!hex.startsWith("0x")) {
                                        hex = "0x" + hex;
                                    }
                                    this.value = hex;
                                    $("#decompile-button").click();
                                }
                            });
                        }

                        let bytecodeInput = $("#bytecode-input");
                        if (bytecodeInput[0] && !$._data(bytecodeInput[0], "events")) {
                            bytecodeInput.keypress(function (e) {
                                if (e.which === 13) {
                                    // [ENTER]
                                    let hex = $(this).val().trim();
                                    if (hex.length === 0) {
                                        return;
                                    }
                                    if (!hex.startsWith("0x")) {
                                        hex = "0x" + hex;
                                    }
                                    $(this).val(hex);
                                    $("#decompile-button").click();
                                    e.preventDefault();
                                }
                            });
                        }
                    }, 500)
                })
            });
    }
    if (rules.length > 0) {
        GM_webRequest(rules, function (info, message, details) {
            console.log("DeFier:", info, details.url, details);
        });
    }
})();