From d9c06243c092313a331228a081a0c5f722905234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9lcio=20Franco?= Date: Sun, 15 Dec 2024 15:27:00 +0700 Subject: [PATCH] feat: skip EVM signature message (#443) --- .changeset/swift-knives-thank.md | 7 +++++ .github/workflows/pr.yaml | 4 +-- e2e-tests/runner/common/common.ts | 10 +++---- e2e-tests/runner/common/types.ts | 2 +- .../SolanaConnector/SolanaConnector.test.ts | 2 +- .../WalletConnectConnector.test.ts | 26 +++++++++++++++---- e2e-tests/runner/package.json | 7 +---- package.json | 2 +- .../ExternalDisclaimer/ExternalDisclaimer.tsx | 2 +- .../src/WalletConnectConnector.ts | 12 ++++++--- 10 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 .changeset/swift-knives-thank.md diff --git a/.changeset/swift-knives-thank.md b/.changeset/swift-knives-thank.md new file mode 100644 index 00000000..ec6a0e15 --- /dev/null +++ b/.changeset/swift-knives-thank.md @@ -0,0 +1,7 @@ +--- +"@fuel-connectors/walletconnect-connector": minor +"@e2e-tests/runner": minor +"@fuels/react": minor +--- + +Skip EVM signature step for previously signed accounts. diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index be50644c..5f5c2b55 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -29,7 +29,7 @@ jobs: uses: tj-actions/changed-files@v22.2 with: files: | - **/packages/connectors/** + **/packages/** validate-changeset: name: Validate PR Changeset @@ -43,7 +43,7 @@ jobs: fetch-depth: 0 - name: CI Setup - uses: FuelLabs/github-actions/setups/node@master + uses: FuelLabs/github-actions/setups/node@58bcd91d7246e40938e1971be0b0fe35b253dff0 with: node-version: 20.11.0 pnpm-version: 9.5.0 diff --git a/e2e-tests/runner/common/common.ts b/e2e-tests/runner/common/common.ts index 587c67cd..dbb21563 100644 --- a/e2e-tests/runner/common/common.ts +++ b/e2e-tests/runner/common/common.ts @@ -1,6 +1,6 @@ import { test } from '@fuels/playwright-utils'; import { type Page, expect } from '@playwright/test'; -import type { ApproveTransferFunction, ConnectorFunctions } from './types'; +import type { ConnectorFunctions } from './types'; // biome-ignore lint/suspicious/noExportsInTest: export const skipBridgeFunds = async (page: Page) => { @@ -13,7 +13,7 @@ export const skipBridgeFunds = async (page: Page) => { // biome-ignore lint/suspicious/noExportsInTest: export const sessionTests = async ( page: Page, - { connect }: ConnectorFunctions, + { connect, secondConnect = connect }: ConnectorFunctions, ) => { await connect(page); @@ -23,19 +23,19 @@ export const sessionTests = async ( await page.click('text=Disconnect'); await page.waitForSelector('text=/Connect Wallet/'); - await connect(page); + await secondConnect(page); await skipBridgeFunds(page); expect(await page.waitForSelector('text=/Your Fuel Address/')).toBeTruthy(); }); - await test.step('should connect, refresh and stay connected', async () => { + await test.step('should refresh and stay connected', async () => { await page.reload(); await skipBridgeFunds(page); await page.waitForSelector('text=/Your Fuel Address/'); }); - await test.step('should connect, disconnect, refresh and stay disconnected', async () => { + await test.step('should disconnect, refresh and stay disconnected', async () => { await skipBridgeFunds(page); await page.click('text=Disconnect'); await page.waitForSelector('text=/Connect Wallet/'); diff --git a/e2e-tests/runner/common/types.ts b/e2e-tests/runner/common/types.ts index bd804467..08a34df2 100644 --- a/e2e-tests/runner/common/types.ts +++ b/e2e-tests/runner/common/types.ts @@ -1,4 +1,3 @@ -// types.ts import type { Page } from '@playwright/test'; export type ConnectFunction = (page: Page) => Promise; @@ -10,6 +9,7 @@ export type ApproveTransferFunction = (page: Page) => Promise; */ export interface ConnectorFunctions { connect: ConnectFunction; + secondConnect?: ConnectFunction; approveTransfer: ApproveTransferFunction; keepSession?: boolean; } diff --git a/e2e-tests/runner/examples/connectors/SolanaConnector/SolanaConnector.test.ts b/e2e-tests/runner/examples/connectors/SolanaConnector/SolanaConnector.test.ts index 9b12b41b..8269cb63 100644 --- a/e2e-tests/runner/examples/connectors/SolanaConnector/SolanaConnector.test.ts +++ b/e2e-tests/runner/examples/connectors/SolanaConnector/SolanaConnector.test.ts @@ -21,7 +21,7 @@ test.describe('SolanaConnector', () => { const connectButton = getButtonByText(page, 'Connect Wallet', true); await connectButton.click(); await getByAriaLabel(page, 'Connect to Solana Wallets', true).click(); - await page.getByText('Proceed anyway').click(); + await page.getByText('Proceed').click(); await getButtonByText(page, 'Phantom').click(); try { await phantomExtended.acceptAccess(); diff --git a/e2e-tests/runner/examples/connectors/WalletConnectConnector/WalletConnectConnector.test.ts b/e2e-tests/runner/examples/connectors/WalletConnectConnector/WalletConnectConnector.test.ts index c58d7a63..20ca085a 100644 --- a/e2e-tests/runner/examples/connectors/WalletConnectConnector/WalletConnectConnector.test.ts +++ b/e2e-tests/runner/examples/connectors/WalletConnectConnector/WalletConnectConnector.test.ts @@ -34,23 +34,31 @@ test.describe('WalletConnectConnector', () => { await page.goto('/', { waitUntil: 'domcontentloaded' }); }); - const connect: ConnectorFunctions['connect'] = async (page) => { + const commonConnect: ConnectorFunctions['connect'] = async (page) => { const connectButton = getButtonByText(page, 'Connect Wallet', true); await connectButton.click(); await getByAriaLabel(page, 'Connect to Ethereum Wallets', true).click(); - await page.getByText('Proceed anyway').click(); + await page.getByText('Proceed').click(); await getButtonByText(page, 'MetaMask', true).click(); await metamask.connectToDapp(); await page.waitForTimeout(4000); + }; + + // First-time connection requires a message signature (to prove ownership of the wallet) + const connect: ConnectorFunctions['connect'] = async (page) => { + await commonConnect(page); await metamask.confirmSignature(); }; + // From here on, we'll skip the signature step + const secondConnect: ConnectorFunctions['connect'] = commonConnect; + const approveTransfer: ConnectorFunctions['approveTransfer'] = async () => { await metamask.confirmTransaction(); }; test('Ethereum session tests', async ({ page }) => { - await sessionTests(page, { connect, approveTransfer }); + await sessionTests(page, { connect, secondConnect, approveTransfer }); }); test('Ethereum transfer tests', async ({ page }) => { @@ -72,7 +80,15 @@ test.describe('WalletConnectConnector', () => { throw new Error('Address is null'); } - await transferTests(page, { connect, approveTransfer, keepSession: true }); - await incrementTests(page, { connect, approveTransfer, keepSession: true }); + await transferTests(page, { + connect, + approveTransfer, + keepSession: true, + }); + await incrementTests(page, { + connect, + approveTransfer, + keepSession: true, + }); }); }); diff --git a/e2e-tests/runner/package.json b/e2e-tests/runner/package.json index 382e39ae..b0669806 100644 --- a/e2e-tests/runner/package.json +++ b/e2e-tests/runner/package.json @@ -29,10 +29,5 @@ "dotenv": "16.4.5", "@phantom/synpress": "4.0.0-alpha.53", "fuels": "0.96.1" - }, - "engines": { - "node": ">=20.11.0", - "pnpm": "9.x" - }, - "packageManager": "pnpm@9.5.0" + } } diff --git a/package.json b/package.json index 460e0061..3101ec0b 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "vitest": "2.0.2" }, "engines": { - "node": ">=20.11.0", + "node": "20.x", "pnpm": "9.x" }, "pnpm": { diff --git a/packages/react/src/ui/Connect/components/ExternalDisclaimer/ExternalDisclaimer.tsx b/packages/react/src/ui/Connect/components/ExternalDisclaimer/ExternalDisclaimer.tsx index be63874f..ba0f37f4 100644 --- a/packages/react/src/ui/Connect/components/ExternalDisclaimer/ExternalDisclaimer.tsx +++ b/packages/react/src/ui/Connect/components/ExternalDisclaimer/ExternalDisclaimer.tsx @@ -97,7 +97,7 @@ export function ExternalDisclaimer() { _startConnection(connector)}> - Proceed anyway + Proceed back()}> Select a Native Wallet diff --git a/packages/walletconnect-connector/src/WalletConnectConnector.ts b/packages/walletconnect-connector/src/WalletConnectConnector.ts index 2e3733dd..a8bece3b 100644 --- a/packages/walletconnect-connector/src/WalletConnectConnector.ts +++ b/packages/walletconnect-connector/src/WalletConnectConnector.ts @@ -39,6 +39,7 @@ import { } from '@fuel-connectors/common'; import { PREDICATE_VERSIONS } from '@fuel-connectors/evm-predicates'; import { ApiController } from '@web3modal/core'; +import { stringToHex } from 'viem'; import { ETHEREUM_ICON, HAS_WINDOW, @@ -330,7 +331,10 @@ export class WalletConnectConnector extends PredicateConnector { async requestValidation(address?: string) { return new Promise(async (resolve, reject) => { - // Disconnect if user dosen't provide signature in time + const hasSignature = await this.accountHasValidation(address); + if (hasSignature) return resolve(true); + + // Disconnect if user doesn't provide signature in time const validationTimeout = setTimeout(() => { reject( new Error("User didn't provide signature in less than 1 minute"), @@ -358,11 +362,11 @@ export class WalletConnectConnector extends PredicateConnector { const wagmiConfig = this.getWagmiConfig(); if (!wagmiConfig) throw new Error('Wagmi config not found'); - const { addresses, connector, isConnected } = getAccount(wagmiConfig); + const { connector, isConnected } = getAccount(wagmiConfig); await disconnect(wagmiConfig, { connector, }); - addresses?.map((a) => this.storage.removeItem(`SIGNATURE_VALIDATION_${a}`)); + return isConnected || false; } @@ -440,7 +444,7 @@ export class WalletConnectConnector extends PredicateConnector { const message = `Sign this message to verify the connected account: ${currentAccount}`; const signature = (await ethProvider.request({ method: 'personal_sign', - params: [message, currentAccount], + params: [stringToHex(message), currentAccount], })) as string; if (!this.validateSignature(currentAccount, message, signature)) {