Code Monkey home page Code Monkey logo

theinterceptor's Introduction

The cutest dino

The Interceptor Alpha

Introducing The Interceptor - the ultimate browser extension for Ethereum! Say goodbye to the confusion of making transactions with our intuitive tool that provides clear explanations of the type of Ethereum transactions you're making. The Interceptor can be used alongside with Metamask or as a standalone transaction simulation tool. With Metamask integration, you can easily send transactions by forwarding them for signing. But what really sets The Interceptor apart is its Simulation Mode. This powerful feature allows you to simulate multiple transactions and see exactly what they will do - even using DApps for free! Our extension is currently available on Chrome, Firefox, and Brave, and supports Ethereum Mainnet, Sepolia and Görli networks. Experience seamless Ethereum transactions like never before with The Interceptor.

Install for Firefox or Chrome

Features

  • Simulation mode, send transactions for free and see what they do
  • Impersonation mode, be Vitalik or anyone else and see the dApps with the eyes of anyone
  • Rich mode, browse dapps with extra 200 000 ETH in your pocket!
  • Simulate your transactions before sending them to be sure on what they do
  • Avoid common token pitfalls such as sending tokens to tokens contract address
  • And more!

You can also watch Interceptor introduction video from Youtube to see The Interceptor in action!

The cutest dino

The cutest dino

Privacy

We value your privacy highly. The Interceptor is designed to minimize privacy leakage: We don't query external sites for anything. However, The Interceptor Alpha is currently connecting to Ethereum RPC nodes operated by Dark Florists (us) because we utilize some custom tooling on the backend. Work is underway to get our custom tooling standardized across clients so Interceptor will work with any standards compliant Ethereum client.

Development

Setup

Install: npm ci --ignore-scripts

Build: npm run setup-chrome for Chrome or npm run setup-firefox for firefox

Then depending on your browser:

  • Chrome: Browse to chrome://extensions/ and click Load unpacked and point to \app\manifest.json.
  • Firefox: Browse to about:debugging and click Load Temporary Add-on and point to \app\manifest.json.
  • Brave: Browse to brave://extensions/ and click Load unpacked and point to \app\manifest.json.

Contact Us!

You can reach us Dark Florsts via Discord and twitter @DarkFlorist!

theinterceptor's People

Contributors

killaridev avatar jubalm avatar epheph avatar micahzoltu avatar 0xjimmy avatar zarifpour avatar sambacha avatar

Stargazers

Adil Kazani avatar M.Emin Taş avatar  avatar  avatar Leonid Logvinov avatar Matthew Stevens avatar  avatar greysign avatar  avatar yson avatar Leeward Bound avatar zachi.eth avatar Yuza avatar RegEdit | whonion.app avatar Viki Val avatar  avatar Shaun avatar  avatar jpgonzalezra avatar Etch avatar  avatar  avatar Ivo Georgiev avatar  avatar Impulse avatar Alfred Gaillard avatar Christoph Richter avatar Asharib Ali avatar  avatar ChiHaoLu avatar Pasha Iepimakhov avatar 0xNick avatar  avatar Phu Minh (Catto) avatar vukasin gostovic avatar  avatar Frank Hu avatar  avatar  avatar  avatar  avatar 0xTopaz avatar  avatar  avatar khazra avatar Geert avatar Evgeny Nasretdinov avatar Olivia Thet avatar x86NOP.eth avatar  avatar laibe avatar Caijiji avatar Ryota Sakai avatar  avatar Nick Mura avatar Apoorv Lathey avatar am avatar lola avatar gbaleeee avatar Kaiziron avatar 0x xj jda avatar  avatar nael avatar okeyzero avatar DavidB avatar Since™️  avatar Brian Stanback avatar evan avatar NormanRain avatar tree avatar Bacon avatar  avatar Yong avatar rs485 avatar  avatar gregs avatar  avatar Harshad Dewangan avatar Abhishek avatar Christina Vongphit avatar George Kushnir avatar Alessio Frateily avatar Tadashi avatar Memphis avatar Aleksandr Pasevin avatar Oswald avatar Ben avatar Jared Bass avatar Jonny Dubowsky avatar  avatar RagePit avatar Thiago Faria Alencar avatar marc avatar meowy avatar Alec Gutman, Chip avatar Minho Ryang avatar Aliaksei avatar dr. mia stein, phd avatar Chopper avatar Michael Demarais avatar

Watchers

 avatar  avatar  avatar Kostas Georgiou avatar Shaun avatar Phu Minh (Catto) avatar

theinterceptor's Issues

Design a new address book

The current addressbook becomes quite difficult use if there's a lot addresses. We also want to support you to be able to rename addresses, and that would add a lot new addresses to the book.

We probably need the features:

  • search in address book
  • tag which addresses are addresses that you want to send stuff from
  • tag which addresses are addresses that you are only sending into
  • Tag addresses that are smart contracts that you are interacting, but interceptor doesn't know already about
  • Full page view instead of small popup
  • Star addresses that should always appear at top
  • Sort addreses by amount of use (?)

Clicking one side of the Simulating/Signing toggle shouldn't toggle, but set.

If you click on the left side of the Simulating | Signing toggle, it will switch you to Simulating mode. If you click in the same spot again it will switch you back to Signing. Given the way we have this element designed, I think clicking on one side should set the state to that side, rather than toggle. So to switch back to Signing you would need to click on the Signing side.

Alternatively, I think if we change the design so the words are outside of the toggle and the toggle is a UI element between them, then it would be more intuitive to have the toggle flip left/right with each click.

License file

Is this under MIT license? Couldn't find a LICENSE file in the repo but saw MIT mentioned elsewhere

Add support for ENS for addresses

Allow user to add ENS addresses in their address book. Store the ENS address and resolve it again when its being used (don't store the address just once)

Interceptor .zip file checksum

Is it worth adding this to the notes for each release?

As reference, these are the hashes for latest v0.0.8.zip file that I generated from downloading via the repo page.

MD5 7eb299732c3c8e3d31bb52c10fd56c46
SHA-1 1a4a4be0864382c11d8e1741174116153015c0e1
SHA-256 318815bcebbbb485a39ab62e3e56b90734f438632114ee18cd5317c313575c4b
Vhash 88969d96d6a62d3041c882b94c3a813d

Brave - refused to execute inline script because it violates the following Content Security Policy directive

Brave version: Version 1.46.134 Chromium: 108.0.5359.94 (Official Build) (64-bit)

Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' blob: 'unsafe-eval'". Either the 'unsafe-inline' keyword, a hash ('sha256-Pno6VqOVhlRXSd0eVB22rNathycbNhTyHseqef92DaU='), or a nonce ('nonce-...') is required to enable inline execution.

<!DOCTYPE html>
<html>
	<head>
		<meta charset = 'utf-8'>
		<link rel = 'icon' type = 'image/x-icon' href = 'favicon.ico'>
	</head>
	<body style = 'width: 520px; height: 400px;'>
		<script async type = 'module' src = '../vendor/es-module-shims/es-module-shims.wasm.js'></script>
		<script type = 'importmap'>
		{
			"imports": {
				"ethers": "../vendor/ethers/ethers.esm.js",
				"webextension-polyfill": "../vendor/webextension-polyfill/browser-polyfill.js",
				"es-module-shims": "../vendor/es-module-shims/es-module-shims.js",
				"preact": "../vendor/preact/preact.module.js",
				"preact/jsx-runtime": "../vendor/preact/jsx-runtime/jsxRuntime.module.js",
				"preact/hooks": "../vendor/preact/hooks/hooks.module.js",
				"funtypes": "../vendor/funtypes/index.mjs",
				"node-fetch": "../vendor/node-fetch/index.mjs",
				"@zoltu/ethereum-abi-encoder": "../vendor/@zoltu/ethereum-abi-encoder/index.js",
				"@zoltu/ethereum-crypto": "../vendor/@zoltu/ethereum-crypto/index.js",
				"@zoltu/rlp-encoder": "../vendor/@zoltu/rlp-encoder/index.js",
				"@darkflorist/address-metadata": "../vendor/@darkflorist/address-metadata/index.js"
			}
		}
	</script>

		<main>Loading...</main>

		<script type = 'module' src = '../js/background/background.js'></script>
	</body>
</html>

image

Persona support

-- persona has website accesses not accounts
-- each persona has one simulation stack
-- all accounts in the persona are linked together (no access request asks between accounts inside persona)
-- when you add new persona to a website access, ask if you want personas linked
-- One persona can have the same account multiple times (warn that personas can be linked)
--when user switches persona, reset simulation

persona 1:

  • Vitalik.eth
  • account 1
  • account 2

persona 2:

  • Vitalik.eth
  • account 1
  • account 3
  • account 4

persona 3:

  • Vitalik.eth
  • acccount 5

Expand bad token targets list

export const BAD_TRANSFER_TARGETS = new Set<bigint>([
	WETH,
	USDC,
	USDT,
	DAI,
	WBTC,
	UNISWAP_V2_ROUTER_ADDRESS,
	SUSHISWAP_V2_ROUTER_ADDRESS,
	UNISWAP_V3_ROUTER
])

Currently following list is a banned list for token transfers, we should move this to metadata and also expand it

Investigate intercepting metamask's rpc connection

Interceptor is able to intercept transaction requests that come from the dapp and check for various issues/simulate prior to sending off to metamask. However, after sending off to Metamask, the user can make a mistake with the gas price (especially when replacing transaction). Additionally, to support bundles, the rpc provider must take the signed transaction and not forward it to the jsonrpc endpoint (instead, collecting multiple transactions, sending to private bundling relay like Flashbots relay).

Additionally, many users use Metamask to initiate transactions (and will often make mistakes related to destination, like sending to the contract address itself).

If we could add a jsonrpc proxy (listening on a real tcp port on the local machine) we could protect, simulate, and bundle transactions we otherwise would have no visibility. We could also get Metamask to participate in the "simulation stack" mode. "Make me rich" could ALSO make you rich in Metamask and would allow you to use Metamask to sign transactions that otherwise wouldn't be possible due to Metamask thinking you don't have enough ETH.

We could also allow Metamask to read RPC from one server, send transactions to another (or multiple) providers.

James found this: https://developer.chrome.com/docs/extensions/reference/sockets_tcpServer/

Figure out better way to communicate between background page and popups

Currently background page informs popups with popup_ messages that some data is updated, and then popup retrieves the updated data via await browser.runtime.getBackgroundPage(). Is there some other ways of doing this communication instead of using window.interceptor global?

We could use these popup messages to tell what has changed when popups are open, but the popups also need to get their current state when the popup open. They cannot have persistent state on their own.

set no-case-declaration flag

"no-case-declaration | Disallow let, class and enum in case blocks. These are visible within the whole switch statement body but not defined in other case clauses. The compiler currently doesn't warn about such uses. You should use a block to restrict the scope of the declarations"

microsoft/TypeScript#47160

renderbug

image

I clicked change address > add new address > added an address (no name), then went to change address again and this is what I saw.

Add sandboxing by account

Currently we support only one simulation stack. Make it so that each account have their own simulation stack

Brave - Error: Extension context invalidated.

Brave version: Version 1.46.134 Chromium: 108.0.5359.94 (Official Build) (64-bit)

image

"use strict";
function listenInContentScript() {
    /**
     * this script executed within the context of the active tab when the user clicks the extension bar button
     * this script serves as a _very thin_ proxy between the page scripts (dapp) and the extension, simply forwarding messages between the two
    */
    // the content script is a very thin proxy between the background script and the page script
    const extensionPort = browser.runtime.connect();
    // forward all message events to the background script, which will then filter and process them
    window.addEventListener('message', messageEvent => {
        try {
            // we only want the data element, if it exists, and postMessage will fail if it can't clone the object fully (and it cannot clone a MessageEvent)
            if (!('data' in messageEvent))
                return;
            extensionPort.postMessage({ data: messageEvent.data });
        }
        catch (error) {
            // CONSIDER: should we catch data clone error and then do `extensionPort.postMessage({data:JSON.parse(JSON.stringify(messageEvent.data))})`?
            console.error(error);
        }
    });
    // forward all messages we get from the background script to the window so the page script can filter and process them
    extensionPort.onMessage.addListener(response => {
        try {
            window.postMessage(response, '*');
        }
        catch (error) {
            console.error(error);
        }
    });
}
function injectScript(content) {
    try {
        const container = document.head || document.documentElement;
        const scriptTag = document.createElement('script');
        scriptTag.setAttribute('async', 'false');
        scriptTag.textContent = content;
        container.insertBefore(scriptTag, container.children[0]);
        container.removeChild(scriptTag);
        listenInContentScript();
    }
    catch (error) {
        console.error('Interceptor: Provider injection failed.', error);
    }
}
const injected_ts = `"use strict";
const METAMASK_ERROR_USER_REJECTED_REQUEST = 4001;
const METAMASK_ERROR_CHAIN_NOT_ADDED_TO_METAMASK = 4902;
class InterceptorFuture {
    constructor() {
        this.then = (onfulfilled, onrejected) => {
            return this.promise.then(onfulfilled, onrejected);
        };
        this.resolve = (value) => {
            this.resolveFunction(value);
        };
        this.reject = (reason) => {
            this.rejectFunction(reason);
        };
        let resolveFunction;
        let rejectFunction;
        this.promise = new Promise((resolve, reject) => {
            resolveFunction = resolve;
            rejectFunction = reject;
        });
        // the function passed to the Promise constructor is called before the constructor returns, so we can be sure the resolve and reject functions have been set by here even if the compiler can't verify
        this.resolveFunction = resolveFunction;
        this.rejectFunction = rejectFunction;
    }
}
class EthereumJsonRpcError extends Error {
    constructor(code, message, data) {
        super(message);
        this.code = code;
        this.data = data;
        this.name = this.constructor.name;
    }
}
window.interceptor = {
    interceptorInjected: false,
    connected: false,
    requestId: 0,
    outstandingRequests: new Map(),
    onMessageCallBack: (_message) => { },
    onConnectCallBack: (_connectInfo) => { },
    onAccountsChangedCallBack: (_accounts) => { },
    onDisconnectCallBack: (_error) => { },
    onChainChangedCallBack: (_chainId) => { },
};
function startListeningForMessages() {
    async function requestAccounts() {
        if (!('ethereum' in window) || !window.ethereum || !('oldRequest' in window.ethereum) || window.ethereum.oldRequest === undefined)
            return;
        const reply = await window.ethereum.oldRequest({ method: 'eth_requestAccounts', params: [] });
        if (Array.isArray(reply)) {
            window.postMessage({
                interceptorRequest: true,
                requestId: -1,
                options: {
                    method: 'eth_accounts_reply',
                    params: reply,
                },
                usingInterceptorWithoutSigner: window.ethereum.usingInterceptorWithoutSigner,
            }, '*');
        }
    }
    async function requestChainId() {
        if (!('ethereum' in window) || !window.ethereum || !('oldRequest' in window.ethereum) || window.ethereum.oldRequest === undefined)
            return;
        const reply = await window.ethereum.oldRequest({ method: 'eth_chainId', params: [] });
        if (typeof reply === 'string') {
            window.postMessage({
                interceptorRequest: true,
                requestId: -1,
                options: {
                    method: 'signer_chainChanged',
                    params: [reply],
                },
                usingInterceptorWithoutSigner: window.ethereum.usingInterceptorWithoutSigner,
            }, '*');
        }
    }
    function checkErrorForCode(error) {
        if (typeof error !== 'object')
            return false;
        if (error === null)
            return false;
        if (!('code' in error))
            return false;
        if (typeof error.code !== 'number')
            return false;
        return true;
    }
    async function requestChangeChain(chainId) {
        if (!('ethereum' in window) || !window.ethereum || !('oldRequest' in window.ethereum) || window.ethereum.oldRequest === undefined)
            return;
        try {
            const reply = await window.ethereum.oldRequest({ method: 'wallet_switchEthereumChain', params: [{ 'chainId': chainId }] });
            if (reply === null) {
                window.postMessage({
                    interceptorRequest: true,
                    requestId: -1,
                    options: {
                        method: 'wallet_switchEthereumChain_reply',
                        params: [{ accept: true, chainId: chainId }],
                    },
                    usingInterceptorWithoutSigner: window.ethereum.usingInterceptorWithoutSigner,
                }, '*');
            }
        }
        catch (error) {
            if (checkErrorForCode(error) && (error.code === METAMASK_ERROR_USER_REJECTED_REQUEST || error.code === METAMASK_ERROR_CHAIN_NOT_ADDED_TO_METAMASK)) {
                return window.postMessage({
                    interceptorRequest: true,
                    requestId: -1,
                    options: {
                        method: 'wallet_switchEthereumChain_reply',
                        params: [{ accept: false, chainId: chainId }],
                    },
                    usingInterceptorWithoutSigner: window.ethereum.usingInterceptorWithoutSigner,
                }, '*');
            }
            throw error;
        }
    }
    async function onMessage(messageEvent) {
        if (typeof messageEvent !== 'object'
            || messageEvent === null
            || !('data' in messageEvent)
            || typeof messageEvent.data !== 'object'
            || messageEvent.data === null
            || !('interceptorApproved' in messageEvent.data))
            return;
        if (!('ethereum' in window) || !window.ethereum)
            throw 'window.ethereum changed';
        if (!('requestId' in messageEvent.data || 'options' in messageEvent.data || 'method' in messageEvent.data.options || 'params' in messageEvent.data.options))
            throw 'missing fields';
        const forwardRequest = messageEvent.data; //use "as" here as we don't want to inject funtypes here
        if (forwardRequest.error !== undefined) {
            if (!window.interceptor.outstandingRequests.has(forwardRequest.requestId))
                throw new EthereumJsonRpcError(forwardRequest.error.code, forwardRequest.error.message);
            return window.interceptor.outstandingRequests.get(forwardRequest.requestId).reject(new EthereumJsonRpcError(forwardRequest.error.code, forwardRequest.error.message));
        }
        if (forwardRequest.result !== undefined) {
            // if interceptor direclty sent us the result, just forward that to the dapp, otherwise ask the signer for the result
            if (forwardRequest.subscription !== undefined) {
                return window.interceptor.onMessageCallBack({ type: 'eth_subscription', data: forwardRequest.result });
            }
            if (forwardRequest.options.method === 'accountsChanged') {
                return window.interceptor.onAccountsChangedCallBack(forwardRequest.result);
            }
            if (forwardRequest.options.method === 'connect') {
                window.interceptor.connected = true;
                return window.interceptor.onConnectCallBack({ chainId: forwardRequest.result });
            }
            if (forwardRequest.options.method === 'disconnect') {
                window.interceptor.connected = false;
                const resultArray = forwardRequest.result;
                return window.interceptor.onDisconnectCallBack({ name: 'disconnect', ...resultArray });
            }
            if (forwardRequest.options.method === 'chainChanged') {
                return window.interceptor.onChainChangedCallBack(forwardRequest.result);
            }
            if (forwardRequest.options.method === 'request_signer_to_eth_requestAccounts') {
                // when dapp requsts eth_requestAccounts, interceptor needs to reply to it, but we also need to try to sign to the signer
                return await requestAccounts();
            }
            if (forwardRequest.options.method === 'request_signer_to_wallet_switchEthereumChain') {
                return await requestChangeChain(forwardRequest.result);
            }
            if (forwardRequest.options.method === 'request_signer_chainId') {
                return await requestChainId();
            }
            return window.interceptor.outstandingRequests.get(forwardRequest.requestId).resolve(forwardRequest.result);
        }
        try {
            if (window.ethereum.usingInterceptorWithoutSigner)
                throw 'Interceptor is in wallet mode and should not forward to an external wallet';
            if (window.ethereum.oldRequest === undefined)
                throw 'Old provider missing';
            const reply = await window.ethereum.oldRequest(forwardRequest.options);
            window.interceptor.outstandingRequests.get(forwardRequest.requestId).resolve(reply);
        }
        catch (error) {
            // if it is an Error, add context to it if context doesn't already exist
            console.log(error);
            console.log(messageEvent);
            if (error instanceof Error) {
                if (!('code' in error))
                    error.code = -32603;
                if (!('data' in error) || error.data === undefined || error.data === null)
                    error.data = { request: forwardRequest.options };
                else if (!('request' in error.data))
                    error.data.request = forwardRequest.options;
                window.interceptor.outstandingRequests.get(forwardRequest.requestId).reject(error);
                return;
            }
            if (error.code !== undefined && error.message !== undefined) {
                window.interceptor.outstandingRequests.get(forwardRequest.requestId).reject(new EthereumJsonRpcError(error.code, error.message, { request: forwardRequest.options }));
                return;
            }
            // if the signer we are connected threw something besides an Error, wrap it up in an error
            window.interceptor.outstandingRequests.get(forwardRequest.requestId).reject(new EthereumJsonRpcError(-32603, \`Unexpected thrown value.\`, { error: error, request: forwardRequest.options }));
        }
    }
    window.addEventListener('message', onMessage);
}
function injectEthereumIntoWindow() {
    const request = async (options) => {
        window.interceptor.requestId++;
        const currentRequestId = window.interceptor.requestId;
        const future = new InterceptorFuture();
        window.interceptor.outstandingRequests.set(currentRequestId, future);
        try {
            // make a message that the background script will catch and reply us. We'll wait until the background script replies to us and return only after that
            window.postMessage({
                interceptorRequest: true,
                usingInterceptorWithoutSigner: window.ethereum.usingInterceptorWithoutSigner,
                requestId: currentRequestId,
                options: {
                    method: options.method,
                    params: options.params,
                }
            }, '*');
            const reply = await future; //TODO: we need to figure out somekind of timeout here, it needs to depend on the request type, eg. if we are asking user to sign something, maybe there shouldn't even be a timeout?
            return reply;
        }
        catch (error) {
            // if it is an Error, add context to it if context doesn't already exist
            if (error instanceof Error) {
                if (!('code' in error))
                    error.code = -32603;
                if (!('data' in error) || error.data === undefined || error.data === null)
                    error.data = { request: options };
                else if (!('request' in error.data))
                    error.data.request = options;
                throw error;
            }
            // if someone threw something besides an Error, wrap it up in an error
            throw new EthereumJsonRpcError(-32603, \`Unexpected thrown value.\`, { error: error, request: options });
        }
        finally {
            window.interceptor.outstandingRequests.delete(currentRequestId);
        }
    };
    // 🤬 Uniswap, among others, require \`send\` to be implemented even though it was never part of any final specification.
    // To make matters worse, some versions of send will have a first parameter that is an object (like \`request\`) and others will have a first and second parameter.
    // On top of all that, some applications have a mix of both!
    const send = async (method, params) => {
        if (typeof method === 'object') {
            return await request({ method: method.method, params: method.params });
        }
        else {
            return await request({ method, params });
        }
    };
    const sendAsync = async (payload, callback) => {
        request(payload)
            .then(result => callback(null, { jsonrpc: '2.0', id: payload.id, result }))
            // since \`request(...)\` only throws things shaped like \`JsonRpcError\`, we can rely on it having those properties.
            .catch(error => callback({ jsonrpc: '2.0', id: payload.id, error: { code: error.code, message: error.message, data: { ...error.data, stack: error.stack } } }, null));
    };
    const on = async (kind, callback) => {
        console.log(\`set on: \${kind}\`);
        switch (kind) {
            case 'accountsChanged':
                window.interceptor.onAccountsChangedCallBack = callback;
                return;
            case 'message':
                window.interceptor.onMessageCallBack = callback;
                return;
            case 'connect':
                window.interceptor.onConnectCallBack = callback;
                return;
            case 'close': //close is deprecated on eip-1193 by disconnect but its still used by dapps (MyEtherWallet)
                window.interceptor.onDisconnectCallBack = callback;
                return;
            case 'disconnect':
                window.interceptor.onDisconnectCallBack = callback;
                return;
            case 'chainChanged':
                window.interceptor.onChainChangedCallBack = callback;
                return;
            default:
        }
    };
    const isConnected = () => {
        return window.interceptor.connected;
    };
    const sendConnectedMessage = (signerName) => {
        if (!('ethereum' in window) || !window.ethereum)
            return;
        window.postMessage({
            interceptorRequest: true,
            requestId: -1,
            options: {
                method: 'connected_to_signer',
                params: [signerName],
            },
            usingInterceptorWithoutSigner: window.ethereum.usingInterceptorWithoutSigner,
        }, '*');
    };
    if (!('ethereum' in window) || !window.ethereum) {
        // no existing signer found
        window.ethereum = {
            request: request,
            on: on,
            send: send,
            sendAsync: sendAsync,
            usingInterceptorWithoutSigner: true,
            enable: () => request({ method: 'eth_requestAccounts' }),
            isConnected: isConnected,
        };
        window.interceptor.interceptorInjected = true;
        startListeningForMessages();
        sendConnectedMessage('NoSigner');
        return;
    }
    if ('ethereum' in window && 'interceptor' in window.ethereum) {
        return; // already injected
    }
    if (window.ethereum.isBraveWallet) {
        window.ethereum = {
            oldRequest: window.ethereum.request,
            oldOn: window.ethereum.on,
            request: request,
            on: on,
            send: send,
            sendAsync: sendAsync,
            usingInterceptorWithoutSigner: false,
            enable: () => request({ method: 'eth_requestAccounts' }),
            isConnected: isConnected,
        };
        sendConnectedMessage('Brave');
    }
    else {
        // we cannot inject window.ethereum alone here as it seems like window.ethereum is cached (maybe ethers.js does that?)
        window.ethereum.oldRequest = window.ethereum.request; // store the request object to access the signer later on
        window.ethereum.oldOn = window.ethereum.on; // store the on object to access the signer later on
        window.ethereum.request = request;
        window.ethereum.on = on;
        window.ethereum.send = send;
        window.ethereum.sendAsync = sendAsync;
        window.ethereum.usingInterceptorWithoutSigner = false;
        window.ethereum.enable = () => request({ method: 'eth_requestAccounts' });
        sendConnectedMessage(window.ethereum.isMetaMask ? 'MetaMask' : 'NotRecognizedSigner');
    }
    if (!window.interceptor.interceptorInjected) {
        startListeningForMessages();
    }
    window.interceptor.interceptorInjected = true;
    if (window.ethereum.oldOn) {
        // subscribe for signers events
        window.ethereum.oldOn('accountsChanged', (accounts) => {
            request({ method: 'eth_accounts_reply', params: accounts });
        });
        window.ethereum.oldOn('connect', (_connectInfo) => {
        });
        window.ethereum.oldOn('disconnect', (_error) => {
            request({ method: 'eth_accounts_reply', params: [] });
        });
        window.ethereum.oldOn('chainChanged', (chainId) => {
            request({ method: 'signer_chainChanged', params: [chainId] });
        });
    }
}
injectEthereumIntoWindow();
//# sourceMappingURL=inpage.js.map`;
const capturer = `
var interceptorCapturedDispatcher = window.dispatchEvent
window.dispatchEvent = function (event) {
    interceptorCapturedDispatcher(event)
    if (event.type === 'ethereum#initialized') {
		console.log('Interceptor: Detected MetaMask injection, reinject')
		injectEthereumIntoWindow()
		window.dispatchEvent = interceptorCapturedDispatcher
	}
}
`;
const inpageContent = capturer + injected_ts;
injectScript(inpageContent);
 

Gnosis Safe

If I load https://app.safe.global/ with Interceptor but not MetaMask in Brave, I do not get an interceptor pop-up to connect. If I add MetaMask and then refresh the page, I then get an Interceptor popup to connect.

My expectation is that when using interceptor with simulation only I would get a pop-up to connect just the same as if I have MM installed.

Brave - Manifest version 2 is deprecated

See below for message from Brave browser [Version 1.46.134 Chromium: 108.0.5359.94 (Official Build) (64-bit)]

Manifest version 2 is deprecated, and support will be removed in 2023. See https://developer.chrome.com/blog/mv2-transition/ for more details.

{
	"name": "Interceptor",
	"description": "Interceptor",
	"version": "0.0.0",
	"manifest_version": 2,
	"browser_action": {
		"default_popup": "html/popup.html",
		"default_icon": {
			"128": "img/head-not-active.png"
		}
	},
	"background": {
		"page": "html/background.html"
	},
	"icons": {
		"128": "img/head.png",
		"400": "img/LOGOA_400x400.png"
	},
	"permissions": [
		"activeTab",
		"<all_urls>",
		"storage",
		"webNavigation"
	],
	"web_accessible_resources": ["vendor/*", "js/*", "inpage/*"],
	"content_security_policy": "script-src 'self' blob: 'unsafe-eval'; object-src 'self';",
	"content_scripts": [
		{
			"matches": ["file://*/*", "http://*/*", "https://*/*"],
			"run_at": "document_start",
			"js": [
				"/vendor/webextension-polyfill/browser-polyfill.js",
				"/inpage/output/injected_document_start.js"
			],
			"all_frames": true
		}
	]
}

image

Transaction preview/simulation UI should be responsive.

If I resize the popup window horizontally, the UI remains fixed in the center, with a lot of the UI elements crammed into a limited amount of space.

Just removing the width/max-width on the body element seems to resolve the issue for the most part. We could do a bit better with layout, but it is an improvement over current.

Add ability to easily rename a signer-connected address.

When connecting to a signer, I just get an address. I wont to be able to easily name it rather than just having an address, but at the moment I have to copy it, go into my address book, create a new entry, paste in the address, give it a name, and then save. Would much rather have a little edit button.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.