diff --git a/.github/workflows/ui_tests.yml b/.github/workflows/ui_tests.yml
index 5715941337..05e51b42ee 100644
--- a/.github/workflows/ui_tests.yml
+++ b/.github/workflows/ui_tests.yml
@@ -36,10 +36,6 @@ on:
secrets:
NEXT_PUBLIC_PROJECT_ID:
required: true
- RELEASE_TOKEN_V2:
- required: true
- TFC_INFRA_TOKEN:
- required: true
TESTS_NEXTAUTH_SECRET:
required: false
TESTS_MAILSAC_API_KEY:
diff --git a/apps/laboratory/next.config.mjs b/apps/laboratory/next.config.mjs
index f7bc508f99..8121bbeba9 100644
--- a/apps/laboratory/next.config.mjs
+++ b/apps/laboratory/next.config.mjs
@@ -8,6 +8,8 @@ const SHAKRA_UI = `'sha256-e7MRMmTzLsLQvIy1iizO1lXf7VWYoQ6ysj5fuUzvRwE='`
const secureSiteDomain = process.env.NEXT_PUBLIC_SECURE_SITE_SDK_URL
? new URL(process.env.NEXT_PUBLIC_SECURE_SITE_SDK_URL).origin
: ''
+const verifyApiNestedIframesTestOuterDomain =
+ 'https://verify-api-nested-iframes-test-outer-domain.com'
const cspHeader = `
default-src 'self';
script-src 'self' ${SHAKRA_UI} ${process.env.NODE_ENV === 'production' ? '' : "'unsafe-eval'"};
@@ -15,11 +17,11 @@ const cspHeader = `
img-src * 'self' data: blob: https://walletconnect.org https://walletconnect.com https://secure.walletconnect.com https://secure.walletconnect.org https://tokens-data.1inch.io https://tokens.1inch.io https://ipfs.io https://appkit-lab.reown.org;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://react-wallet.walletconnect.com https://rpc.walletconnect.com https://rpc.walletconnect.org https://relay.walletconnect.com https://relay.walletconnect.org wss://relay.walletconnect.com wss://relay.walletconnect.org https://pulse.walletconnect.com https://pulse.walletconnect.org https://api.web3modal.com https://api.web3modal.org wss://www.walletlink.org https://o1095249.ingest.sentry.io https://quote-api.jup.ag;
- frame-src 'self' https://verify.walletconnect.com https://verify.walletconnect.org https://secure.walletconnect.com https://secure.walletconnect.org https://secure.reown.com https://widget.solflare.com/ ${secureSiteDomain}/;
+ frame-src 'self' https://verify.walletconnect.com https://verify.walletconnect.org https://secure.walletconnect.com https://secure.walletconnect.org https://secure.reown.com https://widget.solflare.com/ ${secureSiteDomain};
object-src 'none';
base-uri 'self';
form-action 'self';
- frame-ancestors 'none';
+ frame-ancestors ${verifyApiNestedIframesTestOuterDomain};
report-uri https://o1095249.ingest.sentry.io/api/4505685639364608/security/?sentry_key=36ff1e79c60877fce6c0273e94a8ed69;
report-to csp-endpoint
`
diff --git a/apps/laboratory/src/pages/library/ethers-verify-domain-mismatch.tsx b/apps/laboratory/src/pages/library/ethers-verify-domain-mismatch.tsx
new file mode 100644
index 0000000000..c2695c63f3
--- /dev/null
+++ b/apps/laboratory/src/pages/library/ethers-verify-domain-mismatch.tsx
@@ -0,0 +1,40 @@
+import { createAppKit } from '@reown/appkit/react'
+import { EthersAdapter } from '@reown/appkit-adapter-ethers'
+import { EthersTests } from '../../components/Ethers/EthersTests'
+import { AppKitButtons } from '../../components/AppKitButtons'
+import { ThemeStore } from '../../utils/StoreUtil'
+import { ConstantsUtil } from '../../utils/ConstantsUtil'
+import { EthersModalInfo } from '../../components/Ethers/EthersModalInfo'
+import { mainnet } from '@reown/appkit/networks'
+
+// Special project ID with verify enabled on localhost
+const projectId = 'e4eae1aad4503db9966a04fd045a7e4d'
+
+const modal = createAppKit({
+ adapters: [new EthersAdapter()],
+ networks: ConstantsUtil.EvmNetworks,
+ defaultNetwork: mainnet,
+ projectId,
+ metadata: {
+ name: 'AppKit',
+ description: 'AppKit Laboratory',
+ url: 'https://example.com',
+ icons: []
+ },
+ features: {
+ analytics: true
+ },
+ customWallets: ConstantsUtil.CustomWallets
+})
+
+ThemeStore.setModal(modal)
+
+export default function Ethers() {
+ return (
+ <>
+
+
+
+ >
+ )
+}
diff --git a/apps/laboratory/src/pages/library/ethers-verify-evil.tsx b/apps/laboratory/src/pages/library/ethers-verify-evil.tsx
new file mode 100644
index 0000000000..4208b635b7
--- /dev/null
+++ b/apps/laboratory/src/pages/library/ethers-verify-evil.tsx
@@ -0,0 +1,34 @@
+import { createAppKit } from '@reown/appkit/react'
+import { EthersAdapter } from '@reown/appkit-adapter-ethers'
+import { EthersTests } from '../../components/Ethers/EthersTests'
+import { AppKitButtons } from '../../components/AppKitButtons'
+import { ThemeStore } from '../../utils/StoreUtil'
+import { ConstantsUtil } from '../../utils/ConstantsUtil'
+import { EthersModalInfo } from '../../components/Ethers/EthersModalInfo'
+import { mainnet } from '@reown/appkit/networks'
+
+// Special project ID with https://malicious-app-verify-simulation.vercel.app/ as the verified domain and this domain is marked as a scam
+const projectId = '9d176efa3150a1df0a76c8c138b6b657'
+
+const modal = createAppKit({
+ adapters: [new EthersAdapter()],
+ networks: ConstantsUtil.EvmNetworks,
+ defaultNetwork: mainnet,
+ projectId,
+ features: {
+ analytics: true
+ },
+ customWallets: ConstantsUtil.CustomWallets
+})
+
+ThemeStore.setModal(modal)
+
+export default function Ethers() {
+ return (
+ <>
+
+
+
+ >
+ )
+}
diff --git a/apps/laboratory/src/pages/library/ethers-verify-valid.tsx b/apps/laboratory/src/pages/library/ethers-verify-valid.tsx
new file mode 100644
index 0000000000..3dcebd1d99
--- /dev/null
+++ b/apps/laboratory/src/pages/library/ethers-verify-valid.tsx
@@ -0,0 +1,34 @@
+import { createAppKit } from '@reown/appkit/react'
+import { EthersAdapter } from '@reown/appkit-adapter-ethers'
+import { EthersTests } from '../../components/Ethers/EthersTests'
+import { AppKitButtons } from '../../components/AppKitButtons'
+import { ThemeStore } from '../../utils/StoreUtil'
+import { ConstantsUtil } from '../../utils/ConstantsUtil'
+import { EthersModalInfo } from '../../components/Ethers/EthersModalInfo'
+import { mainnet } from '@reown/appkit/networks'
+
+// Special project ID with verify enabled on localhost
+const projectId = 'e4eae1aad4503db9966a04fd045a7e4d'
+
+const modal = createAppKit({
+ adapters: [new EthersAdapter()],
+ networks: ConstantsUtil.EvmNetworks,
+ defaultNetwork: mainnet,
+ projectId,
+ features: {
+ analytics: true
+ },
+ customWallets: ConstantsUtil.CustomWallets
+})
+
+ThemeStore.setModal(modal)
+
+export default function Ethers() {
+ return (
+ <>
+
+
+
+ >
+ )
+}
diff --git a/apps/laboratory/src/pages/library/verify-valid.tsx b/apps/laboratory/src/pages/library/wagmi-verify-domain-mismatch.tsx
similarity index 79%
rename from apps/laboratory/src/pages/library/verify-valid.tsx
rename to apps/laboratory/src/pages/library/wagmi-verify-domain-mismatch.tsx
index 3aae04fe56..74d290851d 100644
--- a/apps/laboratory/src/pages/library/verify-valid.tsx
+++ b/apps/laboratory/src/pages/library/wagmi-verify-domain-mismatch.tsx
@@ -1,23 +1,14 @@
import { createAppKit } from '@reown/appkit/react'
+import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'
import { AppKitButtons } from '../../components/AppKitButtons'
import { WagmiTests } from '../../components/Wagmi/WagmiTests'
import { ThemeStore } from '../../utils/StoreUtil'
import { WagmiModalInfo } from '../../components/Wagmi/WagmiModalInfo'
-import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'
import { ConstantsUtil } from '../../utils/ConstantsUtil'
import { mainnet } from '@reown/appkit/networks'
-const metadata = {
- name: 'AppKit',
- description: 'AppKit Laboratory',
- // Allow localhost
- url: 'http://localhost:3000',
- icons: ['https://avatars.githubusercontent.com/u/37784886'],
- verifyUrl: ''
-}
-
// Special project ID with verify enabled on localhost
const projectId = 'e4eae1aad4503db9966a04fd045a7e4d'
@@ -34,11 +25,14 @@ const wagmiAdapter = new WagmiAdapter({
const modal = createAppKit({
adapters: [wagmiAdapter],
networks,
- projectId,
defaultNetwork: mainnet,
- metadata,
- termsConditionsUrl: 'https://reown.com/terms-of-service',
- privacyPolicyUrl: 'https://reown.com/privacy-policy'
+ projectId,
+ metadata: {
+ name: 'AppKit',
+ description: 'AppKit Laboratory',
+ url: 'https://example.com',
+ icons: []
+ }
})
ThemeStore.setModal(modal)
diff --git a/apps/laboratory/src/pages/library/verify-evil.tsx b/apps/laboratory/src/pages/library/wagmi-verify-evil.tsx
similarity index 86%
rename from apps/laboratory/src/pages/library/verify-evil.tsx
rename to apps/laboratory/src/pages/library/wagmi-verify-evil.tsx
index 98ec057022..cd37df538f 100644
--- a/apps/laboratory/src/pages/library/verify-evil.tsx
+++ b/apps/laboratory/src/pages/library/wagmi-verify-evil.tsx
@@ -9,14 +9,6 @@ import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'
import { ConstantsUtil } from '../../utils/ConstantsUtil'
import { mainnet } from '@reown/appkit/networks'
-const metadata = {
- name: 'Evil AppKit',
- description: 'Evil AppKit Laboratory',
- url: 'https://malicious-app-verify-simulation.vercel.app/',
- icons: ['https://avatars.githubusercontent.com/u/37784886'],
- verifyUrl: ''
-}
-
// Special project ID with https://malicious-app-verify-simulation.vercel.app/ as the verified domain and this domain is marked as a scam
const projectId = '9d176efa3150a1df0a76c8c138b6b657'
@@ -35,7 +27,6 @@ const modal = createAppKit({
networks,
defaultNetwork: mainnet,
projectId,
- metadata,
termsConditionsUrl: 'https://reown.com/terms-of-service',
privacyPolicyUrl: 'https://reown.com/privacy-policy'
})
diff --git a/apps/laboratory/src/pages/library/verify-domain-mismatch.tsx b/apps/laboratory/src/pages/library/wagmi-verify-valid.tsx
similarity index 100%
rename from apps/laboratory/src/pages/library/verify-domain-mismatch.tsx
rename to apps/laboratory/src/pages/library/wagmi-verify-valid.tsx
index 12756c5c55..3605474cd2 100644
--- a/apps/laboratory/src/pages/library/verify-domain-mismatch.tsx
+++ b/apps/laboratory/src/pages/library/wagmi-verify-valid.tsx
@@ -1,11 +1,11 @@
import { createAppKit } from '@reown/appkit/react'
-import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'
import { AppKitButtons } from '../../components/AppKitButtons'
import { WagmiTests } from '../../components/Wagmi/WagmiTests'
import { ThemeStore } from '../../utils/StoreUtil'
import { WagmiModalInfo } from '../../components/Wagmi/WagmiModalInfo'
+import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'
import { ConstantsUtil } from '../../utils/ConstantsUtil'
import { mainnet } from '@reown/appkit/networks'
@@ -25,8 +25,8 @@ const wagmiAdapter = new WagmiAdapter({
const modal = createAppKit({
adapters: [wagmiAdapter],
networks,
- defaultNetwork: mainnet,
projectId,
+ defaultNetwork: mainnet,
termsConditionsUrl: 'https://reown.com/terms-of-service',
privacyPolicyUrl: 'https://reown.com/privacy-policy'
})
diff --git a/apps/laboratory/tests/README.md b/apps/laboratory/tests/README.md
index 1c64835d23..05c2dddae1 100644
--- a/apps/laboratory/tests/README.md
+++ b/apps/laboratory/tests/README.md
@@ -9,7 +9,7 @@ We use Playwright as our functional test runner. It's configured to try multiple
- Make sure your `.env.local` is set up (see `.env.example` for reference)
- Run `pnpm playwright:install` to install the browsers required to run the tests
-- Build AppKit by running `pnpm build` in the root directory
+- Build AppKit & the Lab by running `pnpm build:laboratory` in the root directory
## Running Tests
diff --git a/apps/laboratory/tests/shared/fixtures/w3m-ethers-verify-domain-mismatch-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-ethers-verify-domain-mismatch-fixture.ts
new file mode 100644
index 0000000000..f673489a0f
--- /dev/null
+++ b/apps/laboratory/tests/shared/fixtures/w3m-ethers-verify-domain-mismatch-fixture.ts
@@ -0,0 +1,12 @@
+import type { ModalFixture } from './w3m-fixture'
+import { ModalPage } from '../pages/ModalPage'
+import { timingFixture } from './timing-fixture'
+
+export const testMEthersVerifyDomainMismatch = timingFixture.extend({
+ library: ['ethers', { option: true }],
+ modalPage: async ({ page, library }, use) => {
+ const modalPage = new ModalPage(page, library, 'ethers-verify-domain-mismatch')
+ await modalPage.load()
+ await use(modalPage)
+ }
+})
diff --git a/apps/laboratory/tests/shared/fixtures/w3m-ethers-verify-evil-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-ethers-verify-evil-fixture.ts
new file mode 100644
index 0000000000..44bbd88634
--- /dev/null
+++ b/apps/laboratory/tests/shared/fixtures/w3m-ethers-verify-evil-fixture.ts
@@ -0,0 +1,12 @@
+import type { ModalFixture } from './w3m-fixture'
+import { ModalPage } from '../pages/ModalPage'
+import { timingFixture } from './timing-fixture'
+
+export const testMEthersVerifyEvil = timingFixture.extend({
+ library: ['ethers', { option: true }],
+ modalPage: async ({ page, library }, use) => {
+ const modalPage = new ModalPage(page, library, 'ethers-verify-evil')
+ await modalPage.load()
+ await use(modalPage)
+ }
+})
diff --git a/apps/laboratory/tests/shared/fixtures/w3m-ethers-verify-valid-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-ethers-verify-valid-fixture.ts
new file mode 100644
index 0000000000..a141d4a5e9
--- /dev/null
+++ b/apps/laboratory/tests/shared/fixtures/w3m-ethers-verify-valid-fixture.ts
@@ -0,0 +1,12 @@
+import type { ModalFixture } from './w3m-fixture'
+import { ModalPage } from '../pages/ModalPage'
+import { timingFixture } from './timing-fixture'
+
+export const testMEthersVerifyValid = timingFixture.extend({
+ library: ['ethers', { option: true }],
+ modalPage: async ({ page, library }, use) => {
+ const modalPage = new ModalPage(page, library, 'ethers-verify-valid')
+ await modalPage.load()
+ await use(modalPage)
+ }
+})
diff --git a/apps/laboratory/tests/shared/fixtures/w3m-verify-domain-mismatch-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-wagmi-verify-domain-mismatch-fixture.ts
similarity index 63%
rename from apps/laboratory/tests/shared/fixtures/w3m-verify-domain-mismatch-fixture.ts
rename to apps/laboratory/tests/shared/fixtures/w3m-wagmi-verify-domain-mismatch-fixture.ts
index e87f4a3707..539e19650d 100644
--- a/apps/laboratory/tests/shared/fixtures/w3m-verify-domain-mismatch-fixture.ts
+++ b/apps/laboratory/tests/shared/fixtures/w3m-wagmi-verify-domain-mismatch-fixture.ts
@@ -2,10 +2,10 @@ import type { ModalFixture } from './w3m-fixture'
import { ModalPage } from '../pages/ModalPage'
import { timingFixture } from './timing-fixture'
-export const testMVerifyDomainMismatch = timingFixture.extend({
+export const testMWagmiVerifyDomainMismatch = timingFixture.extend({
library: ['wagmi', { option: true }],
modalPage: async ({ page, library }, use) => {
- const modalPage = new ModalPage(page, library, 'verify-domain-mismatch')
+ const modalPage = new ModalPage(page, library, 'wagmi-verify-domain-mismatch')
await modalPage.load()
await use(modalPage)
}
diff --git a/apps/laboratory/tests/shared/fixtures/w3m-verify-evil-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-wagmi-verify-evil-fixture.ts
similarity index 67%
rename from apps/laboratory/tests/shared/fixtures/w3m-verify-evil-fixture.ts
rename to apps/laboratory/tests/shared/fixtures/w3m-wagmi-verify-evil-fixture.ts
index 9e65c6e300..db479b3df3 100644
--- a/apps/laboratory/tests/shared/fixtures/w3m-verify-evil-fixture.ts
+++ b/apps/laboratory/tests/shared/fixtures/w3m-wagmi-verify-evil-fixture.ts
@@ -2,10 +2,10 @@ import type { ModalFixture } from './w3m-fixture'
import { ModalPage } from '../pages/ModalPage'
import { timingFixture } from './timing-fixture'
-export const testMVerifyEvil = timingFixture.extend({
+export const testMWagmiVerifyEvil = timingFixture.extend({
library: ['wagmi', { option: true }],
modalPage: async ({ page, library }, use) => {
- const modalPage = new ModalPage(page, library, 'verify-evil')
+ const modalPage = new ModalPage(page, library, 'wagmi-verify-evil')
await modalPage.load()
await use(modalPage)
}
diff --git a/apps/laboratory/tests/shared/fixtures/w3m-verify-valid-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-wagmi-verify-valid-fixture.ts
similarity index 66%
rename from apps/laboratory/tests/shared/fixtures/w3m-verify-valid-fixture.ts
rename to apps/laboratory/tests/shared/fixtures/w3m-wagmi-verify-valid-fixture.ts
index 8b42c63bb0..749573f5ff 100644
--- a/apps/laboratory/tests/shared/fixtures/w3m-verify-valid-fixture.ts
+++ b/apps/laboratory/tests/shared/fixtures/w3m-wagmi-verify-valid-fixture.ts
@@ -2,10 +2,10 @@ import type { ModalFixture } from './w3m-fixture'
import { ModalPage } from '../pages/ModalPage'
import { timingFixture } from './timing-fixture'
-export const testMVerifyValid = timingFixture.extend({
+export const testMWagmiVerifyValid = timingFixture.extend({
library: ['wagmi', { option: true }],
modalPage: async ({ page, library }, use) => {
- const modalPage = new ModalPage(page, library, 'verify-valid')
+ const modalPage = new ModalPage(page, library, 'wagmi-verify-valid')
await modalPage.load()
await use(modalPage)
}
diff --git a/apps/laboratory/tests/shared/pages/ModalPage.ts b/apps/laboratory/tests/shared/pages/ModalPage.ts
index 08b072c508..d4462fac85 100644
--- a/apps/laboratory/tests/shared/pages/ModalPage.ts
+++ b/apps/laboratory/tests/shared/pages/ModalPage.ts
@@ -16,9 +16,12 @@ export type ModalFlavor =
| 'default'
| 'external'
| 'debug-mode'
- | 'verify-valid'
- | 'verify-domain-mismatch'
- | 'verify-evil'
+ | 'wagmi-verify-valid'
+ | 'wagmi-verify-domain-mismatch'
+ | 'wagmi-verify-evil'
+ | 'ethers-verify-valid'
+ | 'ethers-verify-domain-mismatch'
+ | 'ethers-verify-evil'
| 'no-email'
| 'no-socials'
| 'siwe'
@@ -28,9 +31,12 @@ function getUrlByFlavor(baseUrl: string, library: string, flavor: ModalFlavor) {
const urlsByFlavor: Partial> = {
default: `${baseUrl}library/${library}/`,
external: `${baseUrl}library/external/`,
- 'verify-valid': `${baseUrl}library/verify-valid/`,
- 'verify-domain-mismatch': `${baseUrl}library/verify-domain-mismatch/`,
- 'verify-evil': maliciousUrl
+ 'wagmi-verify-valid': `${baseUrl}library/wagmi-verify-valid/`,
+ 'wagmi-verify-domain-mismatch': `${baseUrl}library/wagmi-verify-domain-mismatch/`,
+ 'wagmi-verify-evil': maliciousUrl,
+ 'ethers-verify-valid': `${baseUrl}library/ethers-verify-valid/`,
+ 'ethers-verify-domain-mismatch': `${baseUrl}library/ethers-verify-domain-mismatch/`,
+ 'ethers-verify-evil': maliciousUrl
}
return urlsByFlavor[flavor] || `${baseUrl}library/${library}-${flavor}/`
@@ -57,8 +63,11 @@ export class ModalPage {
}
async load() {
- if (this.flavor === 'verify-evil') {
- await routeInterceptUrl(this.page, maliciousUrl, this.baseURL, '/library/verify-evil/')
+ if (this.flavor === 'wagmi-verify-evil') {
+ await routeInterceptUrl(this.page, maliciousUrl, this.baseURL, '/library/wagmi-verify-evil/')
+ }
+ if (this.flavor === 'ethers-verify-evil') {
+ await routeInterceptUrl(this.page, maliciousUrl, this.baseURL, '/library/ethers-verify-evil/')
}
await this.page.goto(this.url)
diff --git a/apps/laboratory/tests/shared/utils/project.ts b/apps/laboratory/tests/shared/utils/project.ts
index fe6f6c4b52..a1ddc28583 100644
--- a/apps/laboratory/tests/shared/utils/project.ts
+++ b/apps/laboratory/tests/shared/utils/project.ts
@@ -50,7 +50,8 @@ const SINGLE_ADAPTER_EVM_TESTS = [
'siwe.spec.ts',
'smart-account.spec.ts',
'wallet-features.spec.ts',
- 'wallet.spec.ts'
+ 'wallet.spec.ts',
+ 'verify.spec.ts'
]
const SINGLE_ADAPTER_EVM_MOBILE_TESTS = ['mobile-wallet-features.spec.ts']
diff --git a/apps/laboratory/tests/verify.spec.ts b/apps/laboratory/tests/verify.spec.ts
index 7f68b5f3af..b1ab8ce50b 100644
--- a/apps/laboratory/tests/verify.spec.ts
+++ b/apps/laboratory/tests/verify.spec.ts
@@ -1,19 +1,23 @@
-import { DEFAULT_CHAIN_NAME, DEFAULT_SESSION_PARAMS } from './shared/constants'
+import { BASE_URL, DEFAULT_CHAIN_NAME, DEFAULT_SESSION_PARAMS } from './shared/constants'
import { testM } from './shared/fixtures/w3m-fixture'
-import { testMVerifyDomainMismatch } from './shared/fixtures/w3m-verify-domain-mismatch-fixture'
-import { testMVerifyEvil } from './shared/fixtures/w3m-verify-evil-fixture'
-import { testMVerifyValid } from './shared/fixtures/w3m-verify-valid-fixture'
+import { testMWagmiVerifyDomainMismatch } from './shared/fixtures/w3m-wagmi-verify-domain-mismatch-fixture'
+import { testMWagmiVerifyEvil } from './shared/fixtures/w3m-wagmi-verify-evil-fixture'
+import { testMWagmiVerifyValid } from './shared/fixtures/w3m-wagmi-verify-valid-fixture'
+import { testMEthersVerifyDomainMismatch } from './shared/fixtures/w3m-ethers-verify-domain-mismatch-fixture'
+import { testMEthersVerifyEvil } from './shared/fixtures/w3m-ethers-verify-evil-fixture'
+import { testMEthersVerifyValid } from './shared/fixtures/w3m-ethers-verify-valid-fixture'
import { WalletPage } from './shared/pages/WalletPage'
import { ModalValidator } from './shared/validators/ModalValidator'
import { WalletValidator } from './shared/validators/WalletValidator'
-import { expect } from '@playwright/test'
+import test, { expect, type Page } from '@playwright/test'
+import { timingFixture } from './shared/fixtures/timing-fixture'
+import { ModalPage } from './shared/pages/ModalPage'
+import { routeInterceptUrl } from './shared/utils/verify'
testM(
'connection and signature requests from non-verified project should show as cannot verify',
async ({ modalPage, context }) => {
- if (modalPage.library === 'solana') {
- return
- }
+ test.skip(modalPage.library === 'solana')
const modalValidator = new ModalValidator(modalPage.page)
const walletPage = new WalletPage(await context.newPage())
@@ -40,12 +44,10 @@ testM(
}
)
-testMVerifyValid(
- 'connection and signature requests from non-scam verified domain should show as domain match',
+testMWagmiVerifyValid(
+ 'wagmi: connection and signature requests from non-scam verified domain should show as domain match',
async ({ modalPage, context }) => {
- if (modalPage.library === 'solana') {
- return
- }
+ test.skip(modalPage.library !== 'wagmi', 'fixture always uses wagmi')
const modalValidator = new ModalValidator(modalPage.page)
const walletPage = new WalletPage(await context.newPage())
@@ -60,7 +62,7 @@ testMVerifyValid(
await walletValidator.expectConnected()
await modalPage.sign()
- const chainName = modalPage.library === 'solana' ? 'Solana' : DEFAULT_CHAIN_NAME
+ const chainName = DEFAULT_CHAIN_NAME
await walletValidator.expectReceivedSign({ chainName })
await expect(walletPage.page.getByTestId('session-info-verified')).toBeVisible()
await walletPage.handleRequest({ accept: true })
@@ -72,12 +74,10 @@ testMVerifyValid(
}
)
-testMVerifyDomainMismatch(
- 'connection and signature requests from non-scam verified domain but on localhost should show as invalid domain',
+testMWagmiVerifyDomainMismatch(
+ 'wagmi: connection and signature requests from non-scam verified domain but on localhost should show as invalid domain',
async ({ modalPage, context }) => {
- if (modalPage.library === 'solana') {
- return
- }
+ test.skip(modalPage.library !== 'wagmi', 'fixture always uses wagmi')
const modalValidator = new ModalValidator(modalPage.page)
const walletPage = new WalletPage(await context.newPage())
@@ -92,7 +92,7 @@ testMVerifyDomainMismatch(
await walletValidator.expectConnected()
await modalPage.sign()
- const chainName = modalPage.library === 'solana' ? 'Solana' : DEFAULT_CHAIN_NAME
+ const chainName = DEFAULT_CHAIN_NAME
await walletValidator.expectReceivedSign({ chainName })
await expect(walletPage.page.getByText('Invalid Domain')).toBeVisible()
await walletPage.handleRequest({ accept: true })
@@ -104,12 +104,10 @@ testMVerifyDomainMismatch(
}
)
-testMVerifyEvil(
- 'connection and signature requests from scam verified domain should show as scam domain',
+testMWagmiVerifyEvil(
+ 'wagmi: connection and signature requests from scam verified domain should show as scam domain',
async ({ modalPage, context }) => {
- if (modalPage.library === 'solana') {
- return
- }
+ test.skip(modalPage.library !== 'wagmi', 'fixture always uses wagmi')
const modalValidator = new ModalValidator(modalPage.page)
const walletPage = new WalletPage(await context.newPage())
@@ -126,7 +124,7 @@ testMVerifyEvil(
await walletValidator.expectConnected()
await modalPage.sign()
- const chainName = modalPage.library === 'solana' ? 'Solana' : DEFAULT_CHAIN_NAME
+ const chainName = DEFAULT_CHAIN_NAME
await expect(walletPage.page.getByText('Website flagged')).toBeVisible()
await walletPage.page.getByText('Proceed anyway').click()
await walletValidator.expectReceivedSign({ chainName })
@@ -139,3 +137,170 @@ testMVerifyEvil(
await walletValidator.expectDisconnected()
}
)
+
+testMEthersVerifyValid(
+ 'ethers: connection and signature requests from non-scam verified domain should show as domain match',
+ async ({ modalPage, context }) => {
+ test.skip(modalPage.library !== 'ethers', 'fixture always uses ethers')
+
+ const modalValidator = new ModalValidator(modalPage.page)
+ const walletPage = new WalletPage(await context.newPage())
+ await walletPage.load()
+ const walletValidator = new WalletValidator(walletPage.page)
+
+ const uri = await modalPage.getConnectUri()
+ await walletPage.connectWithUri(uri)
+ await expect(walletPage.page.getByTestId('session-info-verified')).toBeVisible()
+ await walletPage.handleSessionProposal(DEFAULT_SESSION_PARAMS)
+ await modalValidator.expectConnected()
+ await walletValidator.expectConnected()
+
+ await modalPage.sign()
+ const chainName = DEFAULT_CHAIN_NAME
+ await walletValidator.expectReceivedSign({ chainName })
+ await expect(walletPage.page.getByTestId('session-info-verified')).toBeVisible()
+ await walletPage.handleRequest({ accept: true })
+ await modalValidator.expectAcceptedSign()
+
+ await modalPage.disconnect()
+ await modalValidator.expectDisconnected()
+ await walletValidator.expectDisconnected()
+ }
+)
+
+testMEthersVerifyDomainMismatch(
+ 'ethers: connection and signature requests from non-scam verified domain but on localhost should show as invalid domain',
+ async ({ modalPage, context }) => {
+ test.skip(modalPage.library !== 'ethers', 'fixture always uses ethers')
+
+ const modalValidator = new ModalValidator(modalPage.page)
+ const walletPage = new WalletPage(await context.newPage())
+ await walletPage.load()
+ const walletValidator = new WalletValidator(walletPage.page)
+
+ const uri = await modalPage.getConnectUri()
+ await walletPage.connectWithUri(uri)
+ await expect(walletPage.page.getByText('Invalid Domain')).toBeVisible()
+ await walletPage.handleSessionProposal(DEFAULT_SESSION_PARAMS)
+ await modalValidator.expectConnected()
+ await walletValidator.expectConnected()
+
+ await modalPage.sign()
+ const chainName = DEFAULT_CHAIN_NAME
+ await walletValidator.expectReceivedSign({ chainName })
+ await expect(walletPage.page.getByText('Invalid Domain')).toBeVisible()
+ await walletPage.handleRequest({ accept: true })
+ await modalValidator.expectAcceptedSign()
+
+ await modalPage.disconnect()
+ await modalValidator.expectDisconnected()
+ await walletValidator.expectDisconnected()
+ }
+)
+
+testMEthersVerifyEvil(
+ 'ethers: connection and signature requests from scam verified domain should show as scam domain',
+ async ({ modalPage, context }) => {
+ test.skip(modalPage.library !== 'ethers', 'fixture always uses ethers')
+
+ const modalValidator = new ModalValidator(modalPage.page)
+ const walletPage = new WalletPage(await context.newPage())
+ await walletPage.load()
+ const walletValidator = new WalletValidator(walletPage.page)
+
+ const uri = await modalPage.getConnectUri()
+ await walletPage.connectWithUri(uri)
+ await expect(walletPage.page.getByText('Website flagged')).toBeVisible()
+ await walletPage.page.getByText('Proceed anyway').click()
+ await expect(walletPage.page.getByText('Potential threat')).toBeVisible()
+ await walletPage.handleSessionProposal(DEFAULT_SESSION_PARAMS)
+ await modalValidator.expectConnected()
+ await walletValidator.expectConnected()
+
+ await modalPage.sign()
+ const chainName = DEFAULT_CHAIN_NAME
+ await expect(walletPage.page.getByText('Website flagged')).toBeVisible()
+ await walletPage.page.getByText('Proceed anyway').click()
+ await walletValidator.expectReceivedSign({ chainName })
+ await expect(walletPage.page.getByText('Potential threat')).toBeVisible()
+ await walletPage.handleRequest({ accept: true })
+ await modalValidator.expectAcceptedSign()
+
+ await modalPage.disconnect()
+ await modalValidator.expectDisconnected()
+ await walletValidator.expectDisconnected()
+ }
+)
+
+const prodVerifyServer = 'https://verify.walletconnect.org'
+
+// "https://verify-server-staging.walletconnect-v1-bridge.workers.dev"
+const altVerifyServer = null
+
+interface TimingFixtureWithLibrary {
+ library: string
+}
+
+timingFixture.extend({
+ library: ['wagmi', { option: true }]
+})('wagmi: AppKit in iframe + verify happy case', async ({ page: rootPage, context, library }) => {
+ test.skip(library !== 'wagmi', 'test always uses wagmi')
+
+ const verifyApiNestedIframesTestOuterDomain =
+ 'https://verify-api-nested-iframes-test-outer-domain.com'
+ const outerUrl = verifyApiNestedIframesTestOuterDomain
+ const innerUrl = `${BASE_URL}library/wagmi-verify-valid`
+ await rootPage.route(outerUrl, async route => {
+ await route.fulfill({
+ body: ``
+ })
+ })
+ if (altVerifyServer) {
+ await routeInterceptUrl(rootPage, prodVerifyServer, altVerifyServer, '/')
+ }
+ await rootPage.goto(outerUrl)
+
+ const frame = rootPage.frame({ name: 'innerFrame' })
+ if (frame === null) {
+ throw new Error('iframe not found')
+ }
+
+ /*
+ * Forcibly cast the Frame to a Page so ModalPage accepts it. It has the same necessary functions for this test case, so this is OK.
+ * Note we don't call `.load()` on the ModalPage since it would navigate the top-level page instead of the iframe.
+ * Tried using `Page | Frame` on the ModalPage constructor but we have other functions that depend on fields specific to Page.
+ */
+ const page = frame as unknown as Page
+
+ const modalPage = new ModalPage(page, 'wagmi', 'wagmi-verify-valid')
+ if (modalPage.library === 'solana') {
+ return
+ }
+
+ const modalValidator = new ModalValidator(modalPage.page)
+ const walletPagePage = await context.newPage()
+ if (altVerifyServer) {
+ await routeInterceptUrl(walletPagePage, prodVerifyServer, altVerifyServer, '/')
+ }
+ const walletPage = new WalletPage(walletPagePage)
+ await walletPage.load()
+ const walletValidator = new WalletValidator(walletPage.page)
+
+ const uri = await modalPage.getConnectUri()
+ await walletPage.connectWithUri(uri)
+ await expect(walletPage.page.getByTestId('session-info-verified')).toBeVisible()
+ await walletPage.handleSessionProposal(DEFAULT_SESSION_PARAMS)
+ await modalValidator.expectConnected()
+ await walletValidator.expectConnected()
+
+ await modalPage.sign()
+ const chainName = modalPage.library === 'solana' ? 'Solana' : DEFAULT_CHAIN_NAME
+ await walletValidator.expectReceivedSign({ chainName })
+ await expect(walletPage.page.getByTestId('session-info-verified')).toBeVisible()
+ await walletPage.handleRequest({ accept: true })
+ await modalValidator.expectAcceptedSign()
+
+ await modalPage.disconnect()
+ await modalValidator.expectDisconnected()
+ await walletValidator.expectDisconnected()
+})