// A token that the spoof rule refuses never shows in the balance list, even // tracked at zero balance with "Show tracked tokens with zero balance" on, and // the two add-token screens refuse to track one // (https://git.eeqj.de/sneak/AutistMask/issues/705). Driven through the real // popup over a stored profile. const { bootPopup, cleanupPopup, unversionedValidProfile, TOKEN_ADDRESS, } = require("./support/popupBoot"); // Claims the symbol of the bundled USDT from another contract. const FAKE_USDT = { address: TOKEN_ADDRESS, symbol: "USDT", decimals: 6, name: "Tether USD", }; // A Sepolia contract that reports USDT. The bundled list holds Ethereum Mainnet // contracts, so the spoof rule does not check this symbol on Sepolia // (https://git.eeqj.de/sneak/AutistMask/issues/632). const SEPOLIA_USDT = { address: TOKEN_ADDRESS, symbol: "USDT", decimals: 6, name: "Test USDT", }; // A symbol the bundled list does not have, so the spoof rule passes it. const TEST_TOKEN = { address: "0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", symbol: "TST", decimals: 18, name: "Test Token", }; const REFUSED_FLASH = "Not added: this token fakes a known symbol."; afterEach(() => { cleanupPopup(); }); test("on Ethereum Mainnet, a fake token tracked at zero balance is not listed while zero balances are shown", async () => { const boot = await bootPopup( unversionedValidProfile({ networkId: "mainnet", currentView: "address", selectedWallet: 0, selectedAddress: 0, trackedTokens: [FAKE_USDT, TEST_TOKEN], showZeroBalanceTokens: true, }), ); const rows = boot.node("address-balances").innerHTML; expect(rows).toContain(`data-token="${TEST_TOKEN.address.toLowerCase()}"`); expect(rows).not.toContain( `data-token="${FAKE_USDT.address.toLowerCase()}"`, ); }); // Each screen is opened from AddressDetail by the buttons named, in order. describe.each([ [ "AddToken", ["btn-add-token"], "add-token", "add-token-address", "btn-add-token-confirm", ], [ "SettingsAddToken", ["btn-settings", "btn-settings-add-token"], "settings-addtoken", "settings-addtoken-address", "btn-settings-addtoken-manual", ], ])("%s", (_, opening, view, field, button) => { test("on Ethereum Mainnet, refuses a fake token by contract address", async () => { const boot = await bootPopup( unversionedValidProfile({ networkId: "mainnet", currentView: "address", selectedWallet: 0, selectedAddress: 0, }), ); for (const id of opening) await boot.click(id); expect(boot.visibleViews()).toEqual([view]); const { lookupTokenInfo } = require("../src/shared/balances"); lookupTokenInfo.mockResolvedValueOnce({ symbol: FAKE_USDT.symbol, decimals: FAKE_USDT.decimals, name: FAKE_USDT.name, }); boot.node(field).value = FAKE_USDT.address; await boot.click(button); expect(boot.text("flash-msg")).toBe(REFUSED_FLASH); expect(boot.visibleViews()).toEqual([view]); expect(boot.storage.read("autistmask").trackedTokens).toEqual([]); }); test("on Sepolia, adds a contract that reports USDT and lists it", async () => { const boot = await bootPopup( unversionedValidProfile({ networkId: "sepolia", currentView: "address", selectedWallet: 0, selectedAddress: 0, showZeroBalanceTokens: true, }), ); for (const id of opening) await boot.click(id); expect(boot.visibleViews()).toEqual([view]); const { lookupTokenInfo } = require("../src/shared/balances"); lookupTokenInfo.mockResolvedValueOnce({ symbol: SEPOLIA_USDT.symbol, decimals: SEPOLIA_USDT.decimals, name: SEPOLIA_USDT.name, }); boot.node(field).value = SEPOLIA_USDT.address; await boot.click(button); expect(boot.text("flash-msg")).not.toBe(REFUSED_FLASH); expect(boot.storage.read("autistmask").trackedTokens).toEqual([ expect.objectContaining(SEPOLIA_USDT), ]); // SettingsAddToken stays up after adding, so this draws AddressDetail. require("../src/popup/views/addressDetail").show(); expect(boot.node("address-balances").innerHTML).toContain( `data-token="${SEPOLIA_USDT.address.toLowerCase()}"`, ); }); });