diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index afd0eb78..e966f66c 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -69,8 +69,6 @@ jobs: WITH_ANVIL: true URL: https://${{ steps.preview.outputs.preview_url }} RPC_URL: ${{ secrets.RPC_URL }} - GUARDIAN_UI_INFURA_API_KEY: ${{ secrets.GUARDIAN_UI_INFURA_API_KEY }} - GUARDIAN_UI_ALCHEMY_API_KEY: ${{ secrets.GUARDIAN_UI_ALCHEMY_API_KEY }} VERCEL_AUTOMATION_BYPASS_SECRET: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }} run: pnpm run e2e diff --git a/e2e/constants.ts b/e2e/constants.ts index 472f69b2..2bc38f49 100644 --- a/e2e/constants.ts +++ b/e2e/constants.ts @@ -1,3 +1,7 @@ +export const cookieNames = { + e2e: 'SW_e2e', +} + export const walletNames = { monitorAddress: 'monitorAddress', walletConnect: 'walletConnect', diff --git a/e2e/extendTest.ts b/e2e/extendTest.ts index 87195eae..9b3610e7 100644 --- a/e2e/extendTest.ts +++ b/e2e/extendTest.ts @@ -1,4 +1,4 @@ -import { test as base } from '@guardianui/test' +import { test as base } from '@playwright/test' import { api, @@ -7,16 +7,15 @@ import { swap, vault, queue, - anvil, wallet, osToken, graphql, element, helpers, settings, - guardian, transactions, } from './fixtures' +import { resetAllChains } from './fixtures/wallet/helpers' const baseTest = base.extend({ @@ -26,14 +25,12 @@ const baseTest = base.extend({ swap, queue, vault, - anvil, wallet, osToken, graphql, element, helpers, settings, - guardian, transactions, }) @@ -55,6 +52,10 @@ const log = { const getFileName = (value: string) => value.replace(/^.*\/(.*)\//gm, '$1/') +baseTest.beforeAll(async () => { + await resetAllChains() +}) + baseTest.afterEach(async ({}, testInfo) => { const { title, error, duration, file, retry } = testInfo diff --git a/e2e/fixtures/anvil/index.ts b/e2e/fixtures/anvil/index.ts deleted file mode 100644 index 79edcacd..00000000 --- a/e2e/fixtures/anvil/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { createSetBalance, SetBalance } from './setBalance' - - -export type AnvilFixture = { - setBalance: SetBalance -} - -const anvil: E2E.Fixture = async ({ page }, use) => { - await use({ - setBalance: createSetBalance({ page }), - }) -} - - -export default anvil diff --git a/e2e/fixtures/anvil/setBalance.ts b/e2e/fixtures/anvil/setBalance.ts deleted file mode 100644 index 899e9ecf..00000000 --- a/e2e/fixtures/anvil/setBalance.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { Contract, BaseContract, JsonRpcProvider } from 'ethers' - - -type Wrapper = E2E.FixtureMethod - -type Input = { - tokenAddress: string - amount: string -} - -type TransferContract = BaseContract & { - transfer: (address: string, amount: string, overrides: { from: string }) => Promise<{ hash: string }> -} - -export type SetBalance = (values: Input) => Promise - -const impersonateAccount = async (address: string) => { - try { - await provider.send('anvil_impersonateAccount', [ - address, - ]) - } - catch {} -} - -const provider = new JsonRpcProvider('http://localhost:8545', 1) - -const holders = { - osETH: '0x57ba429517c3473b6d34ca9acd56c0e735b94c02', -} - -const impersonatePromises = { - osETH: impersonateAccount(holders.osETH), -} - -const transferAbi = [ - { - inputs: [ - { - internalType: 'address', - name: 'recipient', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amount', - type: 'uint256', - }, - ], - name: 'transfer', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, -] - -// ATTN fallback for gui.setBalance, that doesn't work in CI -export const createSetBalance: Wrapper = ({ page }) => ( - async (values: Input) => { - const { tokenAddress, amount } = values - - const holder = holders.osETH - const impersonatePromise = impersonatePromises.osETH - - const getAddressPromise = page.evaluate('window.ethereum.signer.address') - - const setBalancePromise = provider.send('anvil_setBalance', [ - holder, - `0x${BigInt(100000000000000000000000).toString(16)}`, - ]) - - const [ address ] = await Promise.all([ - getAddressPromise, - impersonatePromise, - setBalancePromise, - ]) - - const signer = await provider.getSigner(holder) - const tokenContract = new Contract(tokenAddress, transferAbi).connect(signer) as TransferContract - - const receipt = await tokenContract.transfer(address as string, amount, { - from: holder, - }) - - await provider.waitForTransaction(receipt.hash, 6) - } -) diff --git a/e2e/fixtures/element/checkLink.ts b/e2e/fixtures/element/checkLink.ts index 86665580..fd0d4341 100644 --- a/e2e/fixtures/element/checkLink.ts +++ b/e2e/fixtures/element/checkLink.ts @@ -19,7 +19,7 @@ export const createCheckLink: Wrapper = ({ page }) => ( if (isPopup) { const [ newPage ] = await Promise.all([ - page.waitForEvent('popup'), + page.waitForEvent('popup', { timeout: 15_000 }), page.getByTestId(testId).click(), ]) @@ -33,7 +33,6 @@ export const createCheckLink: Wrapper = ({ page }) => ( await expect(page).toHaveURL(expectedURL) if (!skipPageHeadingCheck) { - await page.waitForLoadState('networkidle') await expect(page.getByTestId('page-heading')).toBeVisible() } } diff --git a/e2e/fixtures/element/checkVisibility.ts b/e2e/fixtures/element/checkVisibility.ts index e5686aad..1257447d 100644 --- a/e2e/fixtures/element/checkVisibility.ts +++ b/e2e/fixtures/element/checkVisibility.ts @@ -1,6 +1,3 @@ -import { expect } from '@playwright/test' - - type Wrapper = E2E.FixtureMethod type Input = { @@ -15,14 +12,8 @@ export const createCheckVisibility: Wrapper = ({ page }) => ( const { testId, isVisible = true } = values const selector = `[data-testid="${testId}"]` + const state = isVisible ? 'visible' : 'hidden' - if (isVisible) { - await page.waitForSelector(selector, { state: 'visible' }) - expect(await page.isVisible(selector)).toBe(true) - } - else { - await page.waitForSelector(selector, { state: 'hidden' }) - expect(await page.isVisible(selector)).toBe(false) - } + await page.waitForSelector(selector, { state }) } ) diff --git a/e2e/fixtures/guardian.ts b/e2e/fixtures/guardian.ts deleted file mode 100644 index b2a67419..00000000 --- a/e2e/fixtures/guardian.ts +++ /dev/null @@ -1,115 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { Wallet } from 'ethers' - - -const entryPoint = require.resolve('@guardianui/test') -const distDir = path.dirname(entryPoint) -const pkgRoot = path.dirname(distDir) - -const scriptPath = path.join(pkgRoot, 'dist', 'provider', 'provider.js') - -const fixScript = ` - const updateBigNumber = (data) => { - const result = {} - - Object.keys(data).forEach((key) => { - const value = data[key] - - result[key] = value?._isBigNumber ? value.toHexString() : value - }) - - return result - } - - // ATTN - this is a hack to fix the issue with update BigNumber, because getFeeData inwardly uses getBlock - const originalGetFeeDataResult = window.ethereum.provider.getFeeData() - window.ethereum.provider.getFeeData = () => { - return originalGetFeeDataResult.then(updateBigNumber) - } - - const originalGetBlock = window.ethereum.provider.getBlock - window.ethereum.provider.getBlock = function () { - return originalGetBlock.bind(this)(...arguments).then(updateBigNumber) - } - - const originalGetNetwork = window.ethereum.provider.getNetwork - window.ethereum.provider.getNetwork = function () { - return originalGetNetwork.bind(this)(...arguments).then(updateBigNumber) - } - - const originalGetTransaction = window.ethereum.provider.getTransaction - - window.ethereum.provider.getTransaction = function (txHash) { - return originalGetTransaction.bind(this)(txHash) - .then((tx) => { - if (tx.blockNumber) { - const updatedTx = updateBigNumber(tx) - - return { - ...updatedTx, - gasUsed: updatedTx.gasLimit, - cumulativeGasUsed: updatedTx.gasLimit, - logs: [], - status: 1, - } - } - - return new Promise((resolve) => setTimeout(resolve, 100)) - .then(() => window.ethereum.provider.getTransaction(txHash)) - }) - } -` - -const protectionScript = ` - (function() { - let originalEthereum = null - - Object.defineProperty(window, 'ethereum', { - get: function() { - return originalEthereum - }, - set: function(value) { - if (!originalEthereum) { - console.log('Setting window.ethereum:', value) - - originalEthereum = value - } - else { - console.warn('Blocked attempt to overwrite window.ethereum:', value) - } - }, - configurable: true - }) - })() -` - -const script = fs.readFileSync(scriptPath, 'utf-8') - .replace('__GUARDIANUI_MOCK__RPC', "http://127.0.0.1:8545") - .replace('__GUARDIANUI_MOCK__CHAIN_ID', '1') - .concat(`setTimeout(() => {${fixScript}}, 0)`) - -const cookieScript = `document.cookie = 'SW_e2e=true'` - -export type GuardianFixture = { - fixProvider: (privateKey?: string) => Promise -} - -const guardian: E2E.Fixture = async ({ page }, use) => { - - const fixProvider = async (privateKey?: string) => { - const currentKey = privateKey || Wallet.createRandom().privateKey - const scriptWithWallet = script.replace('__GUARDIANUI_MOCK__PRIVATE_KEY', currentKey) - - await page.addInitScript(cookieScript) - await page.addInitScript(protectionScript) - await page.addInitScript(scriptWithWallet) - } - - await use({ - fixProvider, - }) -} - - -export default guardian diff --git a/e2e/fixtures/index.ts b/e2e/fixtures/index.ts index f4af88b4..9602e046 100644 --- a/e2e/fixtures/index.ts +++ b/e2e/fixtures/index.ts @@ -4,14 +4,12 @@ export { default as user } from './user' export { default as swap } from './swap' export { default as vault } from './vault' export { default as queue } from './queue' -export { default as anvil } from './anvil' export { default as wallet } from './wallet' export { default as osToken } from './osToken' export { default as graphql } from './graphql' export { default as element } from './element' export { default as helpers } from './helpers' export { default as settings } from './settings' -export { default as guardian } from './guardian' export { default as transactions } from './transactions' @@ -21,12 +19,10 @@ export type { UserFixture } from './user' export type { SwapFixture } from './swap' export type { VaultFixture } from './vault' export type { QueueFixture } from './queue' -export type { AnvilFixture } from './anvil' export type { WalletFixture } from './wallet' export type { OsTokenFixture } from './osToken' export type { ElementFixture } from './element' export type { HelpersFixture } from './helpers' export type { GraphqlFixture } from './graphql' export type { SettingsFixture } from './settings' -export type { GuardianFixture } from './guardian' export type { TransactionsFixture } from './transactions' diff --git a/e2e/fixtures/sdk/deposit.ts b/e2e/fixtures/sdk/deposit.ts index d8aaf695..841d7071 100644 --- a/e2e/fixtures/sdk/deposit.ts +++ b/e2e/fixtures/sdk/deposit.ts @@ -1,7 +1,7 @@ import { parseEther } from 'ethers' -type Wrapper = E2E.FixtureMethod +type Wrapper = E2E.FixtureMethod export type Deposit = (values: Input) => Promise @@ -10,12 +10,10 @@ export type Input = { assets: string } -export const createDeposit: Wrapper = ({ page }) => ( +export const createDeposit: Wrapper = ({ page, wallet }) => ( async ({ vaultAddress, assets }: Input) => ( - page.evaluate(async ({ vaultAddress, depositAssets }) => { + page.evaluate(async ({ vaultAddress, depositAssets, userAddress }) => { const sdk = window.e2e.sdk - // @ts-ignore - const userAddress = window.ethereum.signer.address const assets = BigInt(depositAssets) const depositHash = await sdk.vault.deposit({ @@ -24,10 +22,15 @@ export const createDeposit: Wrapper = ({ page }) => ( assets, }) - await sdk.provider.waitForTransaction(depositHash) + const receipt = await sdk.provider.waitForTransaction(depositHash) + + if (!receipt || receipt.status !== 1) { + throw new Error(`deposit reverted: tx=${depositHash} status=${receipt?.status ?? 'no-receipt'}`) + } }, { vaultAddress, depositAssets: parseEther(assets).toString(), + userAddress: wallet.getAddress(), }) ) ) diff --git a/e2e/fixtures/sdk/index.ts b/e2e/fixtures/sdk/index.ts index 82e1ff3d..78c10ec8 100644 --- a/e2e/fixtures/sdk/index.ts +++ b/e2e/fixtures/sdk/index.ts @@ -7,10 +7,10 @@ export type SDKFixture = { deposit: Deposit } -const sdk: E2E.Fixture = async ({ page }, use) => { +const sdk: E2E.Fixture = async ({ page, wallet }, use) => { await use({ - mint: createMint({ page }), - deposit: createDeposit({ page }), + mint: createMint({ page, wallet }), + deposit: createDeposit({ page, wallet }), }) } diff --git a/e2e/fixtures/sdk/mint.ts b/e2e/fixtures/sdk/mint.ts index 33f0b220..ba25e1d3 100644 --- a/e2e/fixtures/sdk/mint.ts +++ b/e2e/fixtures/sdk/mint.ts @@ -1,7 +1,7 @@ import { formatEther, parseEther } from 'ethers' -type Wrapper = E2E.FixtureMethod +type Wrapper = E2E.FixtureMethod export type Mint = (values: Input) => Promise @@ -10,12 +10,10 @@ export type Input = { assets: string } -export const createMint: Wrapper = ({ page }) => ( +export const createMint: Wrapper = ({ page, wallet }) => ( async ({ vaultAddress, assets }: Input) => { - const shares = await page.evaluate(async ({ vaultAddress, stakeAssets }) => { + const shares = await page.evaluate(async ({ vaultAddress, stakeAssets, userAddress }) => { const sdk = window.e2e.sdk - // @ts-ignore - const userAddress = window.ethereum.signer.address const assets = BigInt(stakeAssets) const shares = await sdk.contracts.base.mintTokenController.convertToShares(assets) @@ -26,12 +24,25 @@ export const createMint: Wrapper = ({ page }) => ( shares, }) - await sdk.provider.waitForTransaction(mintHash) + const receipt = await sdk.provider.waitForTransaction(mintHash) + + if (!receipt || receipt.status !== 1) { + throw new Error(`mint reverted: tx=${mintHash} status=${receipt?.status ?? 'no-receipt'}`) + } + + const balance = await sdk.contracts.tokens.mintToken.balanceOf(userAddress) + + console.log(`[e2e mint] user=${userAddress} hash=${mintHash} status=${receipt.status} logs=${receipt.logs.length} balance=${balance}`) + + if (balance === 0n) { + throw new Error(`mint succeeded (status=1) but balance still 0: tx=${mintHash} user=${userAddress} logs=${receipt.logs.length}`) + } return shares.toString() }, { vaultAddress, stakeAssets: parseEther(assets).toString(), + userAddress: wallet.getAddress(), }) return formatEther(shares) diff --git a/e2e/fixtures/swap/actions/boost.ts b/e2e/fixtures/swap/actions/boost.ts index 7f23b5cd..0cdb78a4 100644 --- a/e2e/fixtures/swap/actions/boost.ts +++ b/e2e/fixtures/swap/actions/boost.ts @@ -42,8 +42,6 @@ export const createBoost: Wrapper = ({ page, transactions, api }) => ( checkNotifications: false, }) - await page.waitForLoadState('networkidle') - await transactions.checkTxCompletedModal({ action: 'boost', value: inputAmount, diff --git a/e2e/fixtures/swap/helpers/checkTokenDropdown.ts b/e2e/fixtures/swap/helpers/checkTokenDropdown.ts index c3e9174a..44c2a6c8 100644 --- a/e2e/fixtures/swap/helpers/checkTokenDropdown.ts +++ b/e2e/fixtures/swap/helpers/checkTokenDropdown.ts @@ -1,14 +1,25 @@ +import { expect } from '@playwright/test' + +import type { Locator } from '@playwright/test' + + type Wrapper = E2E.FixtureMethod export type CheckTokenDropdown = (network?: string) => Promise +const triggerTimeout = 15_000 + +const clickTrigger = async (trigger: Locator) => { + await expect(trigger).toBeEnabled({ timeout: triggerTimeout }) + await trigger.click() +} + export const createCheckTokenDropdown: Wrapper = ({ page, element }) => ( async (network?: string) => { const stakeToken = network === 'gnosis' ? 'GNO' : 'ETH' + const trigger = page.getByTestId('amount-input-token') - await page.getByTestId('amount-input-token').click() - - await page.waitForLoadState('networkidle') + await clickTrigger(trigger) await element.checkVisibility({ testId: 'amount-input-input' }) await element.checkVisibility({ testId: 'amount-input-option-USDT' }) @@ -17,10 +28,9 @@ export const createCheckTokenDropdown: Wrapper = ({ page, element }) => ( await element.checkText({ testId: 'amount-input-token', expectedText: 'USDT' }) - await page.getByTestId('amount-input-token').click() - - await page.waitForLoadState('networkidle') + await clickTrigger(trigger) + await element.checkVisibility({ testId: 'amount-input-input' }) await page.getByTestId('amount-input-input').fill(stakeToken) await element.checkVisibility({ testId: `amount-input-option-${stakeToken}` }) diff --git a/e2e/fixtures/swap/setSdkTransactions.ts b/e2e/fixtures/swap/setSdkTransactions.ts index 88a40875..8ad83b4e 100644 --- a/e2e/fixtures/swap/setSdkTransactions.ts +++ b/e2e/fixtures/swap/setSdkTransactions.ts @@ -31,7 +31,7 @@ export const createSetSdkTransactions: Wrapper = ({ page, sdk, graphql }) => ( await graphql.mockAllocatorsData(deposit) await page.reload() - await page.waitForLoadState('networkidle') + await page.waitForSelector('[data-testid="tab-stake"]') return shares } diff --git a/e2e/fixtures/user/setUnboostQueue.ts b/e2e/fixtures/user/setUnboostQueue.ts index de966697..0de1bd86 100644 --- a/e2e/fixtures/user/setUnboostQueue.ts +++ b/e2e/fixtures/user/setUnboostQueue.ts @@ -1,6 +1,8 @@ import { parseEther } from 'ethers' +const waitingDurationSeconds = 604800 + type Input = { exitingShares: string exitingRewards: string @@ -22,11 +24,11 @@ export const createSetUnboostQueue: Wrapper = ({ page }) => ( isClaimable: Boolean(isClaimable), exitingShares: parseEther(exitingShares), exitingAssets: parseEther(exitingRewards), - duration: isClaimable ? 0 : 210258902756807306422, + duration: isClaimable ? 0 : waitingDurationSeconds, position: isClaimable ? { timestamp: '1730206212', positionTicket: '210258902756807306422', - exitQueueIndex: isClaimable ? '1' : null, + exitQueueIndex: '1', } : null, } diff --git a/e2e/fixtures/vault/index.ts b/e2e/fixtures/vault/index.ts index 0619ced5..b74c05a2 100644 --- a/e2e/fixtures/vault/index.ts +++ b/e2e/fixtures/vault/index.ts @@ -5,9 +5,9 @@ export type VaultFixture = { setVaultData: SetVaultData } -const vault: E2E.Fixture = async ({ page }, use) => { +const vault: E2E.Fixture = async ({ page, wallet }, use) => { await use({ - setVaultData: createSetVaultData({ page }), + setVaultData: createSetVaultData({ page, wallet }), }) } diff --git a/e2e/fixtures/vault/setVaultData.ts b/e2e/fixtures/vault/setVaultData.ts index 873f348b..d7414356 100644 --- a/e2e/fixtures/vault/setVaultData.ts +++ b/e2e/fixtures/vault/setVaultData.ts @@ -7,23 +7,11 @@ export type SetVaultData = (data?: any) => Promise type Output = Store['vault']['base']['data'] -type Wrapper = E2E.FixtureMethod +type Wrapper = E2E.FixtureMethod -export const createSetVaultData: Wrapper = ({ page }) => ( +export const createSetVaultData: Wrapper = ({ page, wallet }) => ( async (data) => { - let admin = data?.admin - let address = ZeroAddress - - if (!admin) { - try { - admin = await page.evaluate('window.ethereum.signer.address') - } - catch {} - } - - if (admin) { - address = admin - } + const address = data?.admin || wallet.tryGetAddress() || ZeroAddress const vaultAddress = getAddress(data?.address || constants.metaVault) const capacity = data?.capacity || String(constants.maxUint256) diff --git a/e2e/fixtures/wallet/chains.ts b/e2e/fixtures/wallet/chains.ts new file mode 100644 index 00000000..a232540f --- /dev/null +++ b/e2e/fixtures/wallet/chains.ts @@ -0,0 +1,52 @@ +export enum Network { + Mainnet = 1, +} + +export type SupportedNetwork = Network.Mainnet + +type ChainHolders = Record + +export type ChainEntry = { + name: string + rpcUrl: string + hexadecimalChainId: string + defaultPrivateKey: string + holders: ChainHolders +} + +export const tokens = { + mainnet: { + mintToken: '0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38', + v2StakedToken: '0xFe2e637202056d30016725477c5da089Ab0A043A', + v2RewardToken: '0x20BC832ca081b91433ff6c17f85701B6e92486c5', + }, +} + +const defaultPrivateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' + +const ethereumHolders: ChainHolders = { + [tokens.mainnet.mintToken]: '0x927709711794F3De5DdBF1D176bEE2D55Ba13c21', + [tokens.mainnet.v2StakedToken]: '0x0A2504b0B4a9d08b699BeaA72D53F0267bCFfFbb', + [tokens.mainnet.v2RewardToken]: '0x0A2504b0B4a9d08b699BeaA72D53F0267bCFfFbb', +} + +export const chains: Record = { + [Network.Mainnet]: { + defaultPrivateKey, + name: 'Ethereum', + hexadecimalChainId: '0x1', + rpcUrl: 'http://127.0.0.1:8545', + holders: ethereumHolders, + }, +} + +export const defaultChainId: SupportedNetwork = Network.Mainnet + +export const getAvailableChains = () => { + const entries = Object.values(chains).map((entry) => [ + entry.hexadecimalChainId, + { rpcUrl: entry.rpcUrl, name: entry.name }, + ]) + + return Object.fromEntries(entries) +} diff --git a/e2e/fixtures/wallet/checkWalletList.ts b/e2e/fixtures/wallet/checkWalletList.ts index 53409315..b25510ba 100644 --- a/e2e/fixtures/wallet/checkWalletList.ts +++ b/e2e/fixtures/wallet/checkWalletList.ts @@ -1,9 +1,9 @@ import * as constants from '../../constants' -type Wrapper = E2E.FixtureMethod +type Wrapper = E2E.FixtureMethod -export type checkWalletList = (isMobile?: boolean, withWalletConnect?: boolean) => Promise +export type CheckWalletList = (isMobile?: boolean, withWalletConnect?: boolean) => Promise const walletList = [ { @@ -40,12 +40,12 @@ const mobileList = [ constants.walletNames.coinbase, constants.walletNames.walletConnect, constants.walletNames.monitorAddress, -] as string[] +] const mobileWallets = walletList.filter(({ id }) => mobileList.includes(id)) const desktopWallets = walletList.filter(({ id }) => id !== constants.walletNames.dAppBrowser) -export const createcheckWalletList: Wrapper = ({ page, element }) => ( +export const createCheckWalletList: Wrapper = ({ page, element }) => ( async (isMobile?: boolean, withWalletConnect = true) => { let currentList = isMobile ? mobileWallets : desktopWallets diff --git a/e2e/fixtures/wallet/connectWithBalance.ts b/e2e/fixtures/wallet/connectWithBalance.ts index 265ed811..c96154ae 100644 --- a/e2e/fixtures/wallet/connectWithBalance.ts +++ b/e2e/fixtures/wallet/connectWithBalance.ts @@ -1,33 +1,30 @@ import * as constants from '../../constants' -import { createSetBalance, Token } from './setBalance' +import type { SetBalance, Token } from './setBalance' -type Wrapper = E2E.FixtureMethod - type Input = Partial> export type ConnectWithBalance = (tokens: Input) => Promise -export const createConnectWithBalance: Wrapper = ({ page, helpers, gui, anvil, graphql }) => ( - async (tokens: Input) => { - const promises: Promise[] = [] - - const setBalance = createSetBalance({ gui, anvil, graphql }) - - Object.keys(tokens).forEach((token) => { - const amount = tokens[token as Token] +type Deps = { + page: E2E.ExtendedTest['page'] + helpers: E2E.ExtendedTest['helpers'] + setBalance: SetBalance +} - if (amount) { - promises.push( - setBalance(amount, token as Token) - ) - } - }) +export const createConnectWithBalance = ({ page, helpers, setBalance }: Deps): ConnectWithBalance => ( + async (tokens) => { + const entries = Object.entries(tokens) as [Token, string | undefined][] - await Promise.all(promises) + await Promise.all( + entries + .filter(([ , amount ]) => Boolean(amount)) + .map(([ token, amount ]) => setBalance({ token, amount: amount! })) + ) await page.getByTestId('connect-button').click() + await page.getByTestId('metaMask-connector-button').waitFor({ state: 'visible' }) await page.getByTestId('metaMask-connector-button').click() await helpers.checkNotification(`Successfully connected with ${constants.walletTitles.metaMask}`) diff --git a/e2e/fixtures/wallet/helpers/balance.ts b/e2e/fixtures/wallet/helpers/balance.ts new file mode 100644 index 00000000..0d5a3019 --- /dev/null +++ b/e2e/fixtures/wallet/helpers/balance.ts @@ -0,0 +1,77 @@ +import { Contract, JsonRpcProvider, parseEther, toBeHex } from 'ethers' + +import { chains } from '../chains' +import type { SupportedNetwork } from '../chains' +import { impersonate } from './impersonate' +import type { State } from '../init' + + +type Input = { + token: string + amount: bigint + chainId?: SupportedNetwork +} + +export type Balance = (input: Input) => Promise + +const transferAbi = [ + { + inputs: [ + { internalType: 'address', name: 'recipient', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'transfer', + outputs: [ { internalType: 'bool', name: '', type: 'bool' } ], + stateMutability: 'nonpayable', + type: 'function', + }, +] + +type Wrapper = (deps: { state: State }) => Balance + +const holderEthHex = toBeHex(parseEther('100000')) + +export const createBalance: Wrapper = ({ state }) => ( + async ({ token, amount, chainId }) => { + if (!state.address) { + throw new Error('Wallet not initialized - call wallet.init() first') + } + + const targetChainId = chainId || state.chainId + const chainEntry = chains[targetChainId] + const holder = chainEntry.holders[token] + + if (!holder) { + throw new Error( + `No known holder for token ${token} on chain ${targetChainId}. Add it to chains.ts holders map.` + ) + } + + const rpc = new JsonRpcProvider(chainEntry.rpcUrl) + + try { + await impersonate({ rpc, rpcUrl: chainEntry.rpcUrl, address: holder }) + await rpc.send('anvil_setBalance', [ holder, holderEthHex ]) + + const signer = await rpc.getSigner(holder) + const contract = new Contract(token, transferAbi, signer) + + try { + const tx = await contract.transfer(state.address, amount) + + await rpc.waitForTransaction(tx.hash, 1, 30_000) + } + catch (error) { + const message = error instanceof Error ? error.message : String(error) + + throw new Error( + `balance: transfer failed (token=${token}, holder=${holder}, recipient=${state.address}, chainId=${targetChainId}): ${message}`, + { cause: error } + ) + } + } + finally { + rpc.destroy() + } + } +) diff --git a/e2e/fixtures/wallet/helpers/eip1193-provider.js b/e2e/fixtures/wallet/helpers/eip1193-provider.js new file mode 100644 index 00000000..55e3f24f --- /dev/null +++ b/e2e/fixtures/wallet/helpers/eip1193-provider.js @@ -0,0 +1,289 @@ +/* eslint-env browser */ +/* eslint-disable no-undef */ +(function() { + const chains = __MOCK_CHAINS_JSON__ + const defaultChainIdHex = '__MOCK_DEFAULT_CHAIN_ID_HEX__' + const address = '__MOCK_ADDRESS__' + let currentChainIdHex = defaultChainIdHex + + const rpcTimeoutMs = 30_000 + const pendingTxMaxAttempts = 300 // 100ms * 300 = 30s total budget + + const listeners = Object.create(null) + + const emit = (event, ...args) => { + (listeners[event] || []).slice().forEach((cb) => { + try { + cb(...args) + } + catch (error) { + console.error(`[e2e wallet] listener for "${event}" threw:`, error) + } + }) + } + + const on = (event, cb) => { + listeners[event] = listeners[event] || [] + listeners[event].push(cb) + } + + const removeListener = (event, cb) => { + const arr = listeners[event] || [] + const index = arr.indexOf(cb) + + if (index !== -1) { + arr.splice(index, 1) + } + } + + const blockIdToTag = (blockId) => { + if (blockId == null) { + return 'latest' + } + + if (typeof blockId === 'string') { + return blockId + } + + return `0x${blockId.toString(16)}` + } + + let rpcId = 0 + + async function rpcCall(method, params) { + const url = (chains[currentChainIdHex] || chains[defaultChainIdHex]).rpcUrl + const controller = new AbortController() + const timeoutId = setTimeout(() => controller.abort(), rpcTimeoutMs) + + let response + try { + response = await fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: ++rpcId, + method, + params: params || [], + }), + signal: controller.signal, + }) + } + catch (error) { + const isTimeout = error?.name === 'AbortError' + const reason = isTimeout + ? `timed out after ${rpcTimeoutMs}ms` + : error?.message || 'network failure' + + throw new Error(`RPC ${method} ${reason} [${url}]`) + } + finally { + clearTimeout(timeoutId) + } + + if (!response.ok) { + throw new Error(`RPC ${method} HTTP ${response.status} [${url}]`) + } + + let json + try { + json = await response.json() + } + catch (error) { + throw new Error(`RPC ${method} invalid JSON: ${error.message} [${url}]`) + } + + if (json.error) { + const err = new Error(`RPC ${method}: ${json.error.message || 'error'}`) + err.code = json.error.code + err.data = json.error.data + throw err + } + + return json.result + } + + const mineImmediately = async (label) => { + try { + await rpcCall('anvil_mine', [ '0x1' ]) + } + catch (error) { + console.warn(`[e2e wallet] anvil_mine after ${label} failed:`, error?.message || error) + } + } + + const compatProvider = { + get connection() { + return { url: chains[currentChainIdHex].rpcUrl } + }, + + async getBlock(blockId) { + return rpcCall('eth_getBlockByNumber', [ blockIdToTag(blockId), false ]) + }, + + async getFeeData() { + const [ gasPrice, block ] = await Promise.all([ + rpcCall('eth_gasPrice', []), + rpcCall('eth_getBlockByNumber', [ 'latest', false ]), + ]) + + return { + gasPrice, + maxFeePerGas: block?.baseFeePerGas, + maxPriorityFeePerGas: '0x3b9aca00', + } + }, + + async getNetwork() { + const chainId = await rpcCall('eth_chainId', []) + + return { + chainId: parseInt(chainId, 16), + name: chains[chainId]?.name || 'unknown', + } + }, + + async getTransaction(txHash, attempt = 0) { + const tx = await rpcCall('eth_getTransactionByHash', [ txHash ]) + + if (tx?.blockNumber) { + const receipt = await rpcCall('eth_getTransactionReceipt', [ txHash ]) + + return { + ...tx, + gasUsed: receipt?.gasUsed || tx.gas, + cumulativeGasUsed: receipt?.cumulativeGasUsed || tx.gas, + logs: receipt?.logs || [], + status: receipt?.status || '0x1', + } + } + + if (attempt >= pendingTxMaxAttempts) { + throw new Error(`getTransaction: ${txHash} not mined after ${pendingTxMaxAttempts * 100}ms`) + } + + await new Promise((resolve) => setTimeout(resolve, 100)) + + return compatProvider.getTransaction(txHash, attempt + 1) + }, + } + + const provider = { + isMetaMask: true, + isConnected: () => true, + providers: [], + + get chainId() { + return currentChainIdHex + }, + get selectedAddress() { + return address + }, + get networkVersion() { + return String(parseInt(currentChainIdHex, 16)) + }, + + signer: { address }, + + provider: compatProvider, + + on, + removeListener, + + async request(args) { + const method = args?.method + const params = args?.params || [] + + switch (method) { + case 'eth_accounts': + case 'eth_requestAccounts': + return [ address ] + + case 'eth_chainId': + return currentChainIdHex + + case 'net_version': + return String(parseInt(currentChainIdHex, 16)) + + // skip 4902 check for gnosis tests + case 'wallet_switchEthereumChain': { + currentChainIdHex = params[0]?.chainId + emit('chainChanged', currentChainIdHex) + + return null + } + + case 'wallet_addEthereumChain': { + return null + } + + case 'eth_sendTransaction': { + const tx = { ...params[0] } + + if (!tx.from) { + tx.from = address + } + + const hash = await rpcCall('eth_sendTransaction', [ tx ]) + + await mineImmediately('eth_sendTransaction') + + return hash + } + + case 'eth_sendRawTransaction': { + const hash = await rpcCall('eth_sendRawTransaction', params) + + await mineImmediately('eth_sendRawTransaction') + + return hash + } + + case 'personal_sign': { + const [ message, addr ] = params + + return window.__sw_e2e_personalSign(addr || address, message) + } + + case 'eth_sign': { + const [ addr, message ] = params + + return window.__sw_e2e_personalSign(addr || address, message) + } + + case 'eth_signTypedData': + case 'eth_signTypedData_v1': { + throw new Error(`${method} is not supported - use eth_signTypedData_v4`) + } + + case 'eth_signTypedData_v3': + case 'eth_signTypedData_v4': { + const [ addr, data ] = params + + return window.__sw_e2e_signTypedData(addr || address, data, method) + } + + default: + return rpcCall(method, params) + } + }, + + send(method, params) { + if (typeof method === 'string') { + return provider.request({ method, params }) + } + + return provider.sendAsync(method, params) + }, + + sendAsync(payload, callback) { + provider.request({ method: payload.method, params: payload.params }) + .then((result) => callback(null, { id: payload.id, jsonrpc: '2.0', result })) + .catch((error) => callback(error, null)) + }, + } + + window.ethereum = provider + + window.dispatchEvent(new Event('ethereum#initialized')) +})() diff --git a/e2e/fixtures/wallet/helpers/impersonate.ts b/e2e/fixtures/wallet/helpers/impersonate.ts new file mode 100644 index 00000000..483e91ca --- /dev/null +++ b/e2e/fixtures/wallet/helpers/impersonate.ts @@ -0,0 +1,30 @@ +import type { JsonRpcProvider } from 'ethers' + + +type Input = { + rpc: JsonRpcProvider + rpcUrl: string + address: string +} + +const cache: Record> = {} + +export const impersonate = async ({ rpc, rpcUrl, address }: Input) => { + const addressKey = address.toLowerCase() + + if (!cache[rpcUrl]) { + cache[rpcUrl] = {} + } + + if (cache[rpcUrl][addressKey]) { + return + } + + await rpc.send('anvil_impersonateAccount', [ address ]) + + cache[rpcUrl][addressKey] = true +} + +export const clearImpersonatedCache = (rpcUrl: string) => { + delete cache[rpcUrl] +} diff --git a/e2e/fixtures/wallet/helpers/index.ts b/e2e/fixtures/wallet/helpers/index.ts new file mode 100644 index 00000000..f49f65ed --- /dev/null +++ b/e2e/fixtures/wallet/helpers/index.ts @@ -0,0 +1,5 @@ +export { createBalance } from './balance' +export type { Balance } from './balance' +export { initProvider } from './initProvider' +export { impersonate, clearImpersonatedCache } from './impersonate' +export { resetAllChains } from './resetAllChains' diff --git a/e2e/fixtures/wallet/helpers/initProvider.ts b/e2e/fixtures/wallet/helpers/initProvider.ts new file mode 100644 index 00000000..9ff1d435 --- /dev/null +++ b/e2e/fixtures/wallet/helpers/initProvider.ts @@ -0,0 +1,119 @@ +import fs from 'fs' +import path from 'path' +import { Wallet, JsonRpcProvider, getBytes, isHexString, parseEther, toBeHex } from 'ethers' +import type { Page } from '@playwright/test' + +import * as constants from '../../../constants' +import { impersonate } from './impersonate' +import { chains, getAvailableChains } from '../chains' +import type { SupportedNetwork } from '../chains' + + +const providerScriptPath = path.join(__dirname, 'eip1193-provider.js') +const providerScriptTemplate = fs.readFileSync(providerScriptPath, 'utf-8') + +const initialEthHex = toBeHex(parseEther('10000')) + +const cookieScript = `document.cookie = '${constants.cookieNames.e2e}=true'` + +type InitProviderInput = { + page: Page + chainId: SupportedNetwork + address?: string + privateKey?: string +} + +const buildProviderScript = (address: string, chainId: SupportedNetwork) => { + const chainMap = getAvailableChains() + + return providerScriptTemplate + .replace('__MOCK_CHAINS_JSON__', () => JSON.stringify(chainMap)) + .replace('__MOCK_DEFAULT_CHAIN_ID_HEX__', () => chains[chainId].hexadecimalChainId) + .replace('__MOCK_ADDRESS__', () => address) +} + +const exposeSigner = async (page: Page, privateKey: string) => { + const wallet = new Wallet(privateKey) + + const exposals: Array<[string, (...args: any[]) => Promise]> = [ + [ + '__sw_e2e_signTypedData', + async (_address: string, data: string) => { + const { domain, types, message } = JSON.parse(data) + const { EIP712Domain: _, ...cleanTypes } = types + + return wallet.signTypedData(domain, cleanTypes, message) + }, + ], + [ + '__sw_e2e_personalSign', + async (_address: string, message: string) => { + const payload = isHexString(message) ? getBytes(message) : message + + return wallet.signMessage(payload) + }, + ], + ] + + for (const [ name, fn ] of exposals) { + try { + await page.exposeFunction(name, fn) + } + catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error) + + if (!/already registered/i.test(errorMessage)) { + throw error + } + } + } +} + +const impersonateOnChain = async (rpcUrl: string, address: string) => { + const rpc = new JsonRpcProvider(rpcUrl) + + try { + await impersonate({ rpc, rpcUrl, address }) + await rpc.send('anvil_setBalance', [ address, initialEthHex ]) + } + finally { + rpc.destroy() + } +} + +export const initProvider = async (input: InitProviderInput) => { + const { page, chainId } = input + + if (!chains[chainId]) { + throw new Error(`Unknown chainId: ${chainId}`) + } + + let address = input.address + + if (!address) { + if (!input.privateKey) { + throw new Error('initProvider: either address or privateKey must be provided') + } + + address = new Wallet(input.privateKey).address + } + + const script = buildProviderScript(address, chainId) + + const impersonationTasks = Object.values(chains).map((entry) => ( + impersonateOnChain(entry.rpcUrl, address) + )) + + const tasks = [ ...impersonationTasks ] + + if (input.privateKey) { + tasks.push(exposeSigner(page, input.privateKey)) + } + + await Promise.all(tasks) + + await page.addInitScript(cookieScript) + await page.addInitScript(script) + + return { address } +} diff --git a/e2e/fixtures/wallet/helpers/resetAllChains.ts b/e2e/fixtures/wallet/helpers/resetAllChains.ts new file mode 100644 index 00000000..085b7af4 --- /dev/null +++ b/e2e/fixtures/wallet/helpers/resetAllChains.ts @@ -0,0 +1,62 @@ +import { JsonRpcProvider } from 'ethers' + +import { chains, Network } from '../chains' +import type { SupportedNetwork } from '../chains' +import { impersonate, clearImpersonatedCache } from './impersonate' + + +const forkUrls: Record = { + [Network.Mainnet]: process.env.RPC_URL, +} + +const rpcTimeoutMs = 30_000 + +const withTimeout = (promise: Promise, ms: number, label: string): Promise => ( + Promise.race([ + promise, + new Promise((_, reject) => ( + setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms) + )), + ]) +) + +const resetChain = async (chainId: SupportedNetwork) => { + const chainEntry = chains[chainId] + const forkUrl = forkUrls[chainId] + + if (!forkUrl) { + throw new Error(`Fork URL missing for chain ${chainId} - set RPC_URL in CI secrets`) + } + + const rpc = new JsonRpcProvider(chainEntry.rpcUrl) + + try { + await withTimeout( + rpc.send('anvil_reset', [ { forking: { jsonRpcUrl: forkUrl } } ]), + rpcTimeoutMs, + `anvil_reset chain=${chainId}` + ) + + clearImpersonatedCache(chainEntry.rpcUrl) + + for (const holder of Object.values(chainEntry.holders)) { + try { + await impersonate({ rpc, rpcUrl: chainEntry.rpcUrl, address: holder }) + } + catch (error) { + const message = error instanceof Error ? error.message : String(error) + + console.warn(`[anvil.reset] impersonate ${holder} on chain ${chainId} failed: ${message}`) + } + } + } + finally { + rpc.destroy() + } +} + +export const resetAllChains = async () => { + const ids = Object.keys(chains).map((id) => Number(id) as SupportedNetwork) + + await Promise.all(ids.map(resetChain)) +} diff --git a/e2e/fixtures/wallet/index.ts b/e2e/fixtures/wallet/index.ts index 637c37d9..bae260df 100644 --- a/e2e/fixtures/wallet/index.ts +++ b/e2e/fixtures/wallet/index.ts @@ -1,28 +1,58 @@ import { createConnect, Connect } from './connect' import { createDisconnect, Disconnect } from './disconnect' import { createSetBalance, SetBalance } from './setBalance' +import { createSetEthBalance, SetEthBalance } from './setEthBalance' +import { createBalance } from './helpers' import { createMonitorAddress, MonitorAddress } from './monitorAddress' -import { createcheckWalletList, checkWalletList } from './checkWalletList' +import { createCheckWalletList, CheckWalletList } from './checkWalletList' import { createConnectWithBalance, ConnectWithBalance } from './connectWithBalance' +import { createInit, createState, Init } from './init' +import { createSwitchChain, SwitchChain } from './switchChain' export type WalletFixture = { + init: Init + getAddress: () => string + tryGetAddress: () => string | null + switchChain: SwitchChain connect: Connect disconnect: Disconnect setBalance: SetBalance + setEthBalance: SetEthBalance monitorAddress: MonitorAddress - checkWalletList: checkWalletList + checkWalletList: CheckWalletList connectWithBalance: ConnectWithBalance } -const wallet: E2E.Fixture = async ({ gui, page, anvil, graphql, helpers, element }, use) => { +const wallet: E2E.Fixture = async ({ page, helpers, element, graphql }, use) => { + const state = createState() + + const balance = createBalance({ state }) + const setEthBalance = createSetEthBalance({ state }) + const setBalance = createSetBalance({ balance, setEthBalance, graphql }) + + const tryGetAddress = () => state.address || null + + const getAddress = () => { + if (!state.address) { + throw new Error('Wallet not initialized - call wallet.init() first') + } + + return state.address + } + await use({ + init: createInit({ page, state }), + getAddress, + tryGetAddress, + switchChain: createSwitchChain({ page, state }), connect: createConnect({ page, helpers }), - monitorAddress: createMonitorAddress({ page }), disconnect: createDisconnect({ page, helpers }), - setBalance: createSetBalance({ anvil, gui, graphql }), - checkWalletList: createcheckWalletList({ page, element }), - connectWithBalance: createConnectWithBalance({ gui, page, anvil, graphql, helpers }), + monitorAddress: createMonitorAddress({ page }), + checkWalletList: createCheckWalletList({ page, element }), + connectWithBalance: createConnectWithBalance({ page, helpers, setBalance }), + setEthBalance, + setBalance, }) } diff --git a/e2e/fixtures/wallet/init.ts b/e2e/fixtures/wallet/init.ts new file mode 100644 index 00000000..b41628d9 --- /dev/null +++ b/e2e/fixtures/wallet/init.ts @@ -0,0 +1,49 @@ +import { Wallet } from 'ethers' + +import { defaultChainId } from './chains' +import { initProvider } from './helpers' + +import type { SupportedNetwork } from './chains' + + +type Input = { + privateKey?: string + address?: string + chainId?: SupportedNetwork +} + +export type Init = (input?: Input) => Promise + +type State = { + address: string | null + chainId: SupportedNetwork +} + +type Wrapper = (deps: { page: E2E.ExtendedTest['page']; state: State }) => Init + +export const createInit: Wrapper = ({ page, state }) => ( + async (input) => { + const params = { + page, + chainId: input?.chainId || defaultChainId, + address: input?.address, + privateKey: input?.privateKey, + } + + if (!params.address && !params.privateKey) { + params.privateKey = Wallet.createRandom().privateKey + } + + const { address } = await initProvider(params) + + state.address = address + state.chainId = params.chainId + } +) + +export const createState = (): State => ({ + address: null, + chainId: defaultChainId, +}) + +export type { State } diff --git a/e2e/fixtures/wallet/setBalance.ts b/e2e/fixtures/wallet/setBalance.ts index acba9694..a19c4b35 100644 --- a/e2e/fixtures/wallet/setBalance.ts +++ b/e2e/fixtures/wallet/setBalance.ts @@ -1,44 +1,53 @@ import { parseEther } from 'ethers' +import { tokens } from './chains' +import type { SupportedNetwork } from './chains' +import type { Balance } from './helpers' +import type { SetEthBalance } from './setEthBalance' -type Wrapper = E2E.FixtureMethod export type Token = 'ETH' | 'osETH' -export type SetBalance = (amount: string, token: Token) => Promise +type Input = { + token: Token + amount: string + chainId?: SupportedNetwork +} + +export type SetBalance = (input: Input) => Promise -const tokenAddresses = { - 'osETH': '0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38', +const tokenAddresses: Partial> = { + osETH: tokens.mainnet.mintToken, } -export const createSetBalance: Wrapper = ({ gui, anvil, graphql }) => ( - async (amount: string, token: Token) => { +type Wrapper = (deps: { + balance: Balance + setEthBalance: SetEthBalance + graphql: E2E.ExtendedTest['graphql'] +}) => SetBalance + +export const createSetBalance: Wrapper = ({ balance, setEthBalance, graphql }) => ( + async ({ token, amount, chainId }) => { const amountWei = parseEther(amount) if (token === 'ETH') { - await gui.setEthBalance(amountWei) + await setEthBalance({ amount: amountWei, chainId }) + + return + } + + const tokenAddress = tokenAddresses[token] + + if (!tokenAddress) { + throw new Error(`setBalance: missing address mapping for token ${token}`) } - else { - const tokenAddress = tokenAddresses[token as keyof typeof tokenAddresses] - - const isAnvil = token !== 'osETH' || process.env.CI - - const promises = [ - isAnvil - ? anvil.setBalance({ - amount: amountWei.toString(), - tokenAddress, - }) - : gui.setBalance(tokenAddress, amountWei), - ] - - if (token === 'osETH') { - promises.push( - graphql.mockMintTokenBalance(amount) - ) - } - - await Promise.all(promises) + + const promises: Promise[] = [ balance({ token: tokenAddress, amount: amountWei, chainId }) ] + + if (token === 'osETH') { + promises.push(graphql.mockMintTokenBalance(amount)) } + + await Promise.all(promises) } ) diff --git a/e2e/fixtures/wallet/setEthBalance.ts b/e2e/fixtures/wallet/setEthBalance.ts new file mode 100644 index 00000000..a8550a8e --- /dev/null +++ b/e2e/fixtures/wallet/setEthBalance.ts @@ -0,0 +1,33 @@ +import { JsonRpcProvider, toBeHex } from 'ethers' + +import { chains } from './chains' +import type { SupportedNetwork } from './chains' +import type { State } from './init' + + +type Input = { + amount: bigint + chainId?: SupportedNetwork +} + +export type SetEthBalance = (input: Input) => Promise + +type Wrapper = (deps: { state: State }) => SetEthBalance + +export const createSetEthBalance: Wrapper = ({ state }) => ( + async ({ amount, chainId }) => { + if (!state.address) { + throw new Error('Wallet not initialized - call wallet.init() first') + } + + const targetChainId = chainId || state.chainId + const rpc = new JsonRpcProvider(chains[targetChainId].rpcUrl) + + try { + await rpc.send('anvil_setBalance', [ state.address, toBeHex(amount) ]) + } + finally { + rpc.destroy() + } + } +) diff --git a/e2e/fixtures/wallet/switchChain.ts b/e2e/fixtures/wallet/switchChain.ts new file mode 100644 index 00000000..a3f31ac4 --- /dev/null +++ b/e2e/fixtures/wallet/switchChain.ts @@ -0,0 +1,32 @@ +import type { Page } from '@playwright/test' + +import { chains } from './chains' +import type { State } from './init' +import type { SupportedNetwork } from './chains' + + +type EthereumProvider = { + request: (args: { method: string, params: unknown[] }) => Promise +} + +export type SwitchChain = (chainId: SupportedNetwork) => Promise + +type Wrapper = (deps: { page: Page; state: State }) => SwitchChain + +export const createSwitchChain: Wrapper = ({ page, state }) => ( + async (chainId) => { + await page.evaluate( + async (chainIdHex) => { + const { ethereum } = window as unknown as { ethereum: EthereumProvider } + + await ethereum.request({ + method: 'wallet_switchEthereumChain', + params: [ { chainId: chainIdHex } ], + }) + }, + chains[chainId].hexadecimalChainId + ) + + state.chainId = chainId + } +) diff --git a/e2e/tests/balance.spec.ts b/e2e/tests/balance.spec.ts index 922170d7..cf0eaffa 100644 --- a/e2e/tests/balance.spec.ts +++ b/e2e/tests/balance.spec.ts @@ -1,9 +1,8 @@ import test from '../extendTest' -test.beforeEach(async ({ gui, guardian }) => { - await guardian.fixProvider() - await gui.initializeChain(1) +test.beforeEach(async ({ wallet }) => { + await wallet.init() }) test('Enabled claim', async ({ wallet, swap, queue, user }) => { diff --git a/e2e/tests/boost.spec.ts b/e2e/tests/boost.spec.ts index f81129ae..b604f375 100644 --- a/e2e/tests/boost.spec.ts +++ b/e2e/tests/boost.spec.ts @@ -3,9 +3,8 @@ import { expect } from '@playwright/test' import test from '../extendTest' -test.beforeEach(async ({ gui, guardian }) => { - await guardian.fixProvider() - await gui.initializeChain(1) +test.beforeEach(async ({ wallet }) => { + await wallet.init() }) test('Connect button', async ({ swap }) => { diff --git a/e2e/tests/burn.spec.ts b/e2e/tests/burn.spec.ts index 891c4213..ebdbc43b 100644 --- a/e2e/tests/burn.spec.ts +++ b/e2e/tests/burn.spec.ts @@ -3,9 +3,8 @@ import { expect } from '@playwright/test' import test from '../extendTest' -test.beforeEach(async ({ gui, guardian }) => { - await guardian.fixProvider() - await gui.initializeChain(1) +test.beforeEach(async ({ wallet }) => { + await wallet.init() }) test('Connect button', async ({ swap }) => { diff --git a/e2e/tests/loader.spec.ts b/e2e/tests/loader.spec.ts index 8b8c0ca0..ff399d61 100644 --- a/e2e/tests/loader.spec.ts +++ b/e2e/tests/loader.spec.ts @@ -4,9 +4,8 @@ import * as constants from '../constants' import test from '../extendTest' -test('Connect wallet | Disconnect wallet', async ({ page, wallet, swap, gui, guardian }) => { - await guardian.fixProvider() - await gui.initializeChain(1) +test('Connect wallet | Disconnect wallet', async ({ page, wallet, swap }) => { + await wallet.init() await page.goto('/') await swap.helpers.checkSwapRender() diff --git a/e2e/tests/mint.spec.ts b/e2e/tests/mint.spec.ts index a049b05a..ea8b6f62 100644 --- a/e2e/tests/mint.spec.ts +++ b/e2e/tests/mint.spec.ts @@ -3,9 +3,8 @@ import { expect } from '@playwright/test' import test from '../extendTest' -test.beforeEach(async ({ gui, guardian }) => { - await guardian.fixProvider() - await gui.initializeChain(1) +test.beforeEach(async ({ wallet }) => { + await wallet.init() }) test('Connect button', async ({ swap }) => { diff --git a/e2e/tests/stake.spec.ts b/e2e/tests/stake.spec.ts index 07cb671a..5abeea1f 100644 --- a/e2e/tests/stake.spec.ts +++ b/e2e/tests/stake.spec.ts @@ -4,9 +4,8 @@ import { expect } from '@playwright/test' import test from '../extendTest' -test.beforeEach(async ({ gui, guardian }) => { - await guardian.fixProvider() - await gui.initializeChain(1) +test.beforeEach(async ({ wallet }) => { + await wallet.init() }) test('Connect button', async ({ swap }) => { @@ -22,13 +21,14 @@ test('Token dropdown', async ({ swap, wallet }) => { await swap.helpers.checkTokenDropdown() }) -test('Max balance minus gas', async ({ swap, wallet, graphql }) => { +test('Max balance minus gas', async ({ swap, wallet }) => { await swap.openPage() await wallet.connectWithBalance({ ETH: '100' }) await swap.input.fill() - await graphql.waitForResponse('HarvestParams') - await graphql.waitForResponse('HarvestParams') + + await expect.poll(async () => Number(await swap.input.value()), { timeout: 10_000 }) + .toBeGreaterThan(0) const value = await swap.input.value() diff --git a/e2e/tests/unboost.spec.ts b/e2e/tests/unboost.spec.ts index e5b2b57c..3aa21c55 100644 --- a/e2e/tests/unboost.spec.ts +++ b/e2e/tests/unboost.spec.ts @@ -3,9 +3,8 @@ import { expect } from '@playwright/test' import test from '../extendTest' -test.beforeEach(async ({ gui, guardian }) => { - await guardian.fixProvider() - await gui.initializeChain(1) +test.beforeEach(async ({ wallet }) => { + await wallet.init() }) test('Connect button', async ({ swap }) => { diff --git a/e2e/tests/unstake.spec.ts b/e2e/tests/unstake.spec.ts index 083a8365..4e190625 100644 --- a/e2e/tests/unstake.spec.ts +++ b/e2e/tests/unstake.spec.ts @@ -3,9 +3,8 @@ import { expect } from '@playwright/test' import test from '../extendTest' -test.beforeEach(async ({ gui, guardian }) => { - await guardian.fixProvider() - await gui.initializeChain(1) +test.beforeEach(async ({ wallet }) => { + await wallet.init() }) test('Connect button', async ({ swap }) => { diff --git a/e2e/types.d.ts b/e2e/types.d.ts index e0139472..1a39ecde 100644 --- a/e2e/types.d.ts +++ b/e2e/types.d.ts @@ -1,5 +1,4 @@ import type { BrowserContext, Page, TestFixture } from '@playwright/test' -import type { GUI } from '@guardianui/test/dist/models/GUI' import type { ApiFixture, @@ -8,14 +7,12 @@ import type { SwapFixture, QueueFixture, VaultFixture, - AnvilFixture, WalletFixture, OsTokenFixture, ElementFixture, HelpersFixture, GraphqlFixture, SettingsFixture, - GuardianFixture, TransactionsFixture, } from './fixtures' @@ -25,7 +22,6 @@ declare global { namespace E2E { interface ExtendedTest { - gui: GUI page: Page api: ApiFixture sdk: SDKFixture @@ -33,7 +29,6 @@ declare global { swap: SwapFixture queue: QueueFixture vault: VaultFixture - anvil: AnvilFixture wallet: WalletFixture osToken: OsTokenFixture context: BrowserContext @@ -41,7 +36,6 @@ declare global { helpers: HelpersFixture graphql: GraphqlFixture settings: SettingsFixture - guardian: GuardianFixture transactions: TransactionsFixture } @@ -56,6 +50,6 @@ declare global { } interface Window { - e2e: any + e2e: Record } } diff --git a/package.json b/package.json index 84a57296..c7c19450 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ }, "devDependencies": { "@eslint/js": "9.28.0", - "@guardianui/test": "1.0.4", "@next/eslint-plugin-next": "16.0.10", "@playwright/test": "1.57.0", "@typechain/ethers-v6": "0.5.1", diff --git a/playwright.config.ts b/playwright.config.ts index d10720f4..3fc7bdc8 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -46,14 +46,16 @@ const config: PlaywrightTestConfig = { }, }, ], - webServer: process.env.WITH_ANVIL - ? [ - { - command: './scripts/fork-ci.sh', - url: 'http://localhost:8545', - }, - ] - : [], + webServer: [], +} + +if (process.env.WITH_ANVIL) { + config.webServer = [ + { + command: './scripts/fork-ci.sh', + url: 'http://localhost:8545', + }, + ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 851f1a85..f3caf88c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -136,9 +136,6 @@ importers: '@eslint/js': specifier: 9.28.0 version: 9.28.0 - '@guardianui/test': - specifier: 1.0.4 - version: 1.0.4 '@next/eslint-plugin-next': specifier: 16.0.10 version: 16.0.10 @@ -464,150 +461,60 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@ethersproject/abi@5.7.0': - resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} - '@ethersproject/abi@5.8.0': resolution: {integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==} - '@ethersproject/abstract-provider@5.7.0': - resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==} - '@ethersproject/abstract-provider@5.8.0': resolution: {integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==} - '@ethersproject/abstract-signer@5.7.0': - resolution: {integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==} - '@ethersproject/abstract-signer@5.8.0': resolution: {integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==} - '@ethersproject/address@5.7.0': - resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} - '@ethersproject/address@5.8.0': resolution: {integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==} - '@ethersproject/base64@5.7.0': - resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} - '@ethersproject/base64@5.8.0': resolution: {integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==} - '@ethersproject/basex@5.7.0': - resolution: {integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==} - - '@ethersproject/bignumber@5.7.0': - resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} - '@ethersproject/bignumber@5.8.0': resolution: {integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==} - '@ethersproject/bytes@5.7.0': - resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} - '@ethersproject/bytes@5.8.0': resolution: {integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==} - '@ethersproject/constants@5.7.0': - resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} - '@ethersproject/constants@5.8.0': resolution: {integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==} - '@ethersproject/contracts@5.7.0': - resolution: {integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==} - - '@ethersproject/hash@5.7.0': - resolution: {integrity: sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==} - '@ethersproject/hash@5.8.0': resolution: {integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==} - '@ethersproject/hdnode@5.7.0': - resolution: {integrity: sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==} - - '@ethersproject/json-wallets@5.7.0': - resolution: {integrity: sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==} - - '@ethersproject/keccak256@5.7.0': - resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} - '@ethersproject/keccak256@5.8.0': resolution: {integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==} - '@ethersproject/logger@5.7.0': - resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} - '@ethersproject/logger@5.8.0': resolution: {integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==} - '@ethersproject/networks@5.7.1': - resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} - '@ethersproject/networks@5.8.0': resolution: {integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==} - '@ethersproject/pbkdf2@5.7.0': - resolution: {integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==} - - '@ethersproject/properties@5.7.0': - resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} - '@ethersproject/properties@5.8.0': resolution: {integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==} - '@ethersproject/providers@5.7.2': - resolution: {integrity: sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==} - - '@ethersproject/random@5.7.0': - resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} - - '@ethersproject/rlp@5.7.0': - resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} - '@ethersproject/rlp@5.8.0': resolution: {integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==} - '@ethersproject/sha2@5.7.0': - resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} - - '@ethersproject/signing-key@5.7.0': - resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} - '@ethersproject/signing-key@5.8.0': resolution: {integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==} - '@ethersproject/solidity@5.7.0': - resolution: {integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==} - - '@ethersproject/strings@5.7.0': - resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} - '@ethersproject/strings@5.8.0': resolution: {integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==} - '@ethersproject/transactions@5.7.0': - resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} - '@ethersproject/transactions@5.8.0': resolution: {integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==} - '@ethersproject/units@5.7.0': - resolution: {integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==} - - '@ethersproject/wallet@5.7.0': - resolution: {integrity: sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==} - - '@ethersproject/web@5.7.1': - resolution: {integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==} - '@ethersproject/web@5.8.0': resolution: {integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==} - '@ethersproject/wordlists@5.7.0': - resolution: {integrity: sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==} - '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} @@ -635,9 +542,6 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@guardianui/test@1.0.4': - resolution: {integrity: sha512-vd62SRyyfZujsF5Ns8BrGi1cfI34deI9L7Jt1JaSmfo+5ORQXiTDEsrG3Oy+zq1otlfD8x2P4ww6BN5PDYLeAA==} - '@headlessui/react@2.2.4': resolution: {integrity: sha512-lz+OGcAH1dK93rgSMzXmm1qKOJkBUqZf1L4M8TWLNplftQD3IkoEDdUFNfAn4ylsN6WOTVtWaLmvmaHOUk1dTA==} engines: {node: '>=10'} @@ -1690,9 +1594,6 @@ packages: resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} engines: {node: '>=0.8'} - aes-js@3.0.0: - resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} - aes-js@4.0.0-beta.5: resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} @@ -1917,9 +1818,6 @@ packages: resolution: {integrity: sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==} hasBin: true - bech32@1.1.4: - resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} - big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -2389,9 +2287,6 @@ packages: electron-to-chromium@1.5.267: resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} - elliptic@6.5.4: - resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} - elliptic@6.6.1: resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} @@ -2608,9 +2503,6 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - ethers@5.7.2: - resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} - ethers@6.14.3: resolution: {integrity: sha512-qq7ft/oCJohoTcsNPFaXSQUm457MA5iWqkf1Mb11ujONdg7jBI6sAOrHaTi3j0CBqIGFSCeR/RMc+qwRRub7IA==} engines: {node: '>=14.0.0'} @@ -2865,11 +2757,11 @@ packages: glob@7.1.7: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me global-modules@2.0.0: resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} @@ -4530,9 +4422,6 @@ packages: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} - scrypt-js@3.0.1: - resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} - semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -4876,6 +4765,7 @@ packages: tar@7.5.2: resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} engines: {node: '>=18'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me terser-webpack-plugin@5.3.14: resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} @@ -5268,18 +5158,6 @@ packages: resolution: {integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==} engines: {node: '>=4'} - ws@7.4.6: - resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - ws@7.5.10: resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} engines: {node: '>=8.3.0'} @@ -5785,18 +5663,6 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@ethersproject/abi@5.7.0': - dependencies: - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/abi@5.8.0': dependencies: '@ethersproject/address': 5.8.0 @@ -5809,16 +5675,6 @@ snapshots: '@ethersproject/properties': 5.8.0 '@ethersproject/strings': 5.8.0 - '@ethersproject/abstract-provider@5.7.0': - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/networks': 5.7.1 - '@ethersproject/properties': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/web': 5.7.1 - '@ethersproject/abstract-provider@5.8.0': dependencies: '@ethersproject/bignumber': 5.8.0 @@ -5829,14 +5685,6 @@ snapshots: '@ethersproject/transactions': 5.8.0 '@ethersproject/web': 5.8.0 - '@ethersproject/abstract-signer@5.7.0': - dependencies: - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/abstract-signer@5.8.0': dependencies: '@ethersproject/abstract-provider': 5.8.0 @@ -5845,14 +5693,6 @@ snapshots: '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.8.0 - '@ethersproject/address@5.7.0': - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/address@5.8.0': dependencies: '@ethersproject/bignumber': 5.8.0 @@ -5861,72 +5701,24 @@ snapshots: '@ethersproject/logger': 5.8.0 '@ethersproject/rlp': 5.8.0 - '@ethersproject/base64@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/base64@5.8.0': dependencies: '@ethersproject/bytes': 5.8.0 - '@ethersproject/basex@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/properties': 5.7.0 - - '@ethersproject/bignumber@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - bn.js: 5.2.2 - '@ethersproject/bignumber@5.8.0': dependencies: '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.8.0 bn.js: 5.2.2 - '@ethersproject/bytes@5.7.0': - dependencies: - '@ethersproject/logger': 5.7.0 - '@ethersproject/bytes@5.8.0': dependencies: '@ethersproject/logger': 5.8.0 - '@ethersproject/constants@5.7.0': - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/constants@5.8.0': dependencies: '@ethersproject/bignumber': 5.8.0 - '@ethersproject/contracts@5.7.0': - dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/transactions': 5.7.0 - - '@ethersproject/hash@5.7.0': - dependencies: - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/base64': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/hash@5.8.0': dependencies: '@ethersproject/abstract-signer': 5.8.0 @@ -5939,128 +5731,26 @@ snapshots: '@ethersproject/properties': 5.8.0 '@ethersproject/strings': 5.8.0 - '@ethersproject/hdnode@5.7.0': - dependencies: - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/pbkdf2': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/wordlists': 5.7.0 - - '@ethersproject/json-wallets@5.7.0': - dependencies: - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/hdnode': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/pbkdf2': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/random': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - aes-js: 3.0.0 - scrypt-js: 3.0.1 - - '@ethersproject/keccak256@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - js-sha3: 0.8.0 - '@ethersproject/keccak256@5.8.0': dependencies: '@ethersproject/bytes': 5.8.0 js-sha3: 0.8.0 - '@ethersproject/logger@5.7.0': {} - '@ethersproject/logger@5.8.0': {} - '@ethersproject/networks@5.7.1': - dependencies: - '@ethersproject/logger': 5.7.0 - '@ethersproject/networks@5.8.0': dependencies: '@ethersproject/logger': 5.8.0 - '@ethersproject/pbkdf2@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/sha2': 5.7.0 - - '@ethersproject/properties@5.7.0': - dependencies: - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties@5.8.0': dependencies: '@ethersproject/logger': 5.8.0 - '@ethersproject/providers@5.7.2': - dependencies: - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/base64': 5.7.0 - '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/networks': 5.7.1 - '@ethersproject/properties': 5.7.0 - '@ethersproject/random': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/web': 5.7.1 - bech32: 1.1.4 - ws: 7.4.6 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@ethersproject/random@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - - '@ethersproject/rlp@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/rlp@5.8.0': dependencies: '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.8.0 - '@ethersproject/sha2@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - hash.js: 1.1.7 - - '@ethersproject/signing-key@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - bn.js: 5.2.2 - elliptic: 6.5.4 - hash.js: 1.1.7 - '@ethersproject/signing-key@5.8.0': dependencies: '@ethersproject/bytes': 5.8.0 @@ -6070,39 +5760,12 @@ snapshots: elliptic: 6.6.1 hash.js: 1.1.7 - '@ethersproject/solidity@5.7.0': - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/strings': 5.7.0 - - '@ethersproject/strings@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/strings@5.8.0': dependencies: '@ethersproject/bytes': 5.8.0 '@ethersproject/constants': 5.8.0 '@ethersproject/logger': 5.8.0 - '@ethersproject/transactions@5.7.0': - dependencies: - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@ethersproject/transactions@5.8.0': dependencies: '@ethersproject/address': 5.8.0 @@ -6115,38 +5778,6 @@ snapshots: '@ethersproject/rlp': 5.8.0 '@ethersproject/signing-key': 5.8.0 - '@ethersproject/units@5.7.0': - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 - - '@ethersproject/wallet@5.7.0': - dependencies: - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/hdnode': 5.7.0 - '@ethersproject/json-wallets': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/random': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/wordlists': 5.7.0 - - '@ethersproject/web@5.7.1': - dependencies: - '@ethersproject/base64': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/web@5.8.0': dependencies: '@ethersproject/base64': 5.8.0 @@ -6155,14 +5786,6 @@ snapshots: '@ethersproject/properties': 5.8.0 '@ethersproject/strings': 5.8.0 - '@ethersproject/wordlists@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@floating-ui/core@1.7.3': dependencies: '@floating-ui/utils': 0.2.10 @@ -6196,15 +5819,6 @@ snapshots: '@floating-ui/utils@0.2.10': {} - '@guardianui/test@1.0.4': - dependencies: - '@playwright/test': 1.57.0 - dotenv: 16.5.0 - ethers: 5.7.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - '@headlessui/react@2.2.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@floating-ui/react': 0.26.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -7269,8 +6883,6 @@ snapshots: adler-32@1.3.1: {} - aes-js@3.0.0: {} - aes-js@4.0.0-beta.5: {} ajv-formats@2.1.1(ajv@8.17.1): @@ -7516,8 +7128,6 @@ snapshots: baseline-browser-mapping@2.9.14: {} - bech32@1.1.4: {} - big.js@5.2.2: {} bignumber.js@9.3.0: {} @@ -7999,16 +7609,6 @@ snapshots: electron-to-chromium@1.5.267: {} - elliptic@6.5.4: - dependencies: - bn.js: 4.12.2 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - elliptic@6.6.1: dependencies: bn.js: 4.12.2 @@ -8367,42 +7967,6 @@ snapshots: esutils@2.0.3: {} - ethers@5.7.2: - dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/base64': 5.7.0 - '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/contracts': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/hdnode': 5.7.0 - '@ethersproject/json-wallets': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/networks': 5.7.1 - '@ethersproject/pbkdf2': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/providers': 5.7.2 - '@ethersproject/random': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@ethersproject/solidity': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/units': 5.7.0 - '@ethersproject/wallet': 5.7.0 - '@ethersproject/web': 5.7.1 - '@ethersproject/wordlists': 5.7.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - ethers@6.14.3: dependencies: '@adraffy/ens-normalize': 1.10.1 @@ -10345,8 +9909,6 @@ snapshots: ajv-formats: 2.1.1(ajv@8.17.1) ajv-keywords: 5.1.0(ajv@8.17.1) - scrypt-js@3.0.1: {} - semver@5.7.2: {} semver@6.3.1: {} @@ -11375,8 +10937,6 @@ snapshots: dependencies: mkdirp: 0.5.6 - ws@7.4.6: {} - ws@7.5.10: {} ws@8.17.1: {} diff --git a/scripts/fork-ci.sh b/scripts/fork-ci.sh index f0a2e72a..72134ca6 100755 --- a/scripts/fork-ci.sh +++ b/scripts/fork-ci.sh @@ -1,3 +1,3 @@ #!/bin/sh -anvil --fork-url=$RPC_URL --block-time=5 --port=8545 --chain-id=1 --host=0.0.0.0 +anvil --compute-units-per-second=100 --fork-url=$RPC_URL --block-time=5 --port=8545 --chain-id=1 --host=0.0.0.0 diff --git a/src/helpers/methods/apiUrls/index.ts b/src/helpers/methods/apiUrls/index.ts index 042bca67..456d165f 100644 --- a/src/helpers/methods/apiUrls/index.ts +++ b/src/helpers/methods/apiUrls/index.ts @@ -1,9 +1,15 @@ import { Network } from 'sdk' +import getRpcForE2E from '../getRpcForE2E' + import data from './data' -const getWeb3Url = (network: Network) => data[network].web3 +const getWeb3Url = (network: Network) => { + const e2eRpc = getRpcForE2E() + + return e2eRpc || data[network].web3 +} const getBackendUrl = (network: Network) => data[network].backend diff --git a/src/helpers/methods/getRpcForE2E.ts b/src/helpers/methods/getRpcForE2E.ts new file mode 100644 index 00000000..12d2aba0 --- /dev/null +++ b/src/helpers/methods/getRpcForE2E.ts @@ -0,0 +1,16 @@ +import cookie from 'helpers/cookie' +import * as constants from 'helpers/constants' + + +const getRpcForE2E = () => { + if (typeof window === 'undefined') { + return null + } + + const e2eCookieValue = cookie.get(constants.cookieNames.e2e) + + return e2eCookieValue ? 'http://localhost:8545' : null +} + + +export default getRpcForE2E