Skip to content

Commit

Permalink
✨ feat(metamask): Add support for personal_sign (#988)
Browse files Browse the repository at this point in the history
  • Loading branch information
duckception authored Nov 11, 2023
1 parent 489621c commit 7897535
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 6 deletions.
1 change: 1 addition & 0 deletions wallets/metamask/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"test:coverage": "vitest run --coverage",
"test:e2e:headful": "playwright test",
"test:e2e:headless": "HEADLESS=true playwright test",
"test:e2e:headless:ui": "HEADLESS=true playwright test --ui",
"test:watch": "vitest watch",
"types:check": "tsc --noEmit"
},
Expand Down
30 changes: 27 additions & 3 deletions wallets/metamask/src/metamask.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import type { BrowserContext, Page } from '@playwright/test'
import { CrashPage, HomePage, LockPage, NotificationPage, OnboardingPage } from './pages'

const NO_EXTENSION_ID_ERROR = new Error('MetaMask extensionId is not set')

export class MetaMask {
crashPage: CrashPage
onboardingPage: OnboardingPage
lockPage: LockPage
homePage: HomePage
notificationPage: NotificationPage

constructor(readonly context: BrowserContext, readonly page: Page, readonly password: string) {
constructor(
readonly context: BrowserContext,
readonly page: Page,
readonly password: string,
readonly extensionId?: string
) {
this.crashPage = new CrashPage()

this.onboardingPage = new OnboardingPage(page)
Expand All @@ -21,8 +28,11 @@ export class MetaMask {
await this.onboardingPage.importWallet(seedPhrase, this.password)
}

async connectToDapp(extensionId: string) {
await this.notificationPage.connectToDapp(extensionId)
async connectToDapp() {
if (!this.extensionId) {
throw NO_EXTENSION_ID_ERROR
}
await this.notificationPage.connectToDapp(this.extensionId)
}

async lock() {
Expand All @@ -32,4 +42,18 @@ export class MetaMask {
async unlock() {
await this.lockPage.unlock(this.password)
}

async confirmSignature() {
if (!this.extensionId) {
throw NO_EXTENSION_ID_ERROR
}
await this.notificationPage.signPersonalMessage(this.extensionId)
}

async rejectSignature() {
if (!this.extensionId) {
throw NO_EXTENSION_ID_ERROR
}
await this.notificationPage.rejectPersonalMessage(this.extensionId)
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './connectToDapp'
export * from './personalSign'
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { BrowserContext } from '@playwright/test'
import { getNotificationPage } from '../../../utils/getNotificationPage'
import Selectors from '../selectors'

const signPersonalMessage = async (context: BrowserContext, extensionId: string) => {
const notificationPage = await getNotificationPage(context, extensionId)

await notificationPage.locator(Selectors.SignaturePage.signButton).click()
}

const rejectPersonalMessage = async (context: BrowserContext, extensionId: string) => {
const notificationPage = await getNotificationPage(context, extensionId)

await notificationPage.locator(Selectors.SignaturePage.rejectButton).click()
}

export const personalSign = {
sign: signPersonalMessage,
reject: rejectPersonalMessage
}
10 changes: 9 additions & 1 deletion wallets/metamask/src/pages/NotificationPage/page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Page } from '@playwright/test'
import { connectToDapp } from './actions'
import { connectToDapp, personalSign } from './actions'

export class NotificationPage {
readonly page: Page
Expand All @@ -11,4 +11,12 @@ export class NotificationPage {
async connectToDapp(extensionId: string) {
await connectToDapp(this.page.context(), extensionId)
}

async signPersonalMessage(extensionId: string) {
await personalSign.sign(this.page.context(), extensionId)
}

async rejectPersonalMessage(extensionId: string) {
await personalSign.reject(this.page.context(), extensionId)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import SignaturePage from './signaturePage'

export default {
SignaturePage
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createDataTestSelector } from '../../../utils/selectors/createDataTestSelector'

export default {
signButton: `.request-signature__footer ${createDataTestSelector('request-signature__sign')}`,
rejectButton: '.request-signature__footer button.btn-secondary'
}
33 changes: 33 additions & 0 deletions wallets/metamask/test/e2e/metamask/confirmSignature.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { testWithSynpress } from 'fixtures'
import { MetaMask, unlockForFixture } from '../../../src'

import connectedSetup from '../wallet-setup/connected.setup'

const test = testWithSynpress(connectedSetup, unlockForFixture)

const { describe, expect } = test

describe('MetaMask.confirmSignature', () => {
test('should confirm `personal_sign`', async ({ context, metamaskPage, page, extensionId }) => {
const metamask = new MetaMask(context, metamaskPage, connectedSetup.walletPassword, extensionId)

await page.goto('https://metamask.github.io/test-dapp/')

await page.locator('#personalSign').click()

await metamask.confirmSignature()

await expect(page.locator('#personalSignResult')).toHaveText(
'0xf95b3efc808585303e20573e960993cde30c7f5a0f1c25cfab0379d5a14311d17898199814c8ebe66ec80b2b11690f840bde539f862ff4f04468d2a40f15178a1b'
)

await page.locator('#personalSignVerify').click()

await expect(page.locator('#personalSignVerifySigUtilResult')).toHaveText(
'0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
)
await expect(page.locator('#personalSignVerifyECRecoverResult')).toHaveText(
'0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
)
})
})
4 changes: 2 additions & 2 deletions wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ const { describe, expect } = test

describe('MetaMask.connectToDapp', () => {
test('should connect wallet to dapp', async ({ context, page, extensionId }) => {
const metamask = new MetaMask(context, page, basicSetup.walletPassword)
const metamask = new MetaMask(context, page, basicSetup.walletPassword, extensionId)

await page.goto('https://metamask.github.io/test-dapp/')

await page.locator('#connectButton').click()

await metamask.connectToDapp(extensionId)
await metamask.connectToDapp()

await expect(page.locator('#accounts')).toHaveText('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266')
})
Expand Down
25 changes: 25 additions & 0 deletions wallets/metamask/test/e2e/metamask/rejectSignature.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { testWithSynpress } from 'fixtures'
import { MetaMask, unlockForFixture } from '../../../src'

import connectedSetup from '../wallet-setup/connected.setup'

const test = testWithSynpress(connectedSetup, unlockForFixture)

const { describe, expect } = test

describe('MetaMask.rejectSignature', () => {
test('should reject `personal_sign`', async ({ context, metamaskPage, page, extensionId }) => {
const metamask = new MetaMask(context, metamaskPage, connectedSetup.walletPassword, extensionId)

await page.goto('https://metamask.github.io/test-dapp/')

await page.locator('#personalSign').click()

await metamask.rejectSignature()

await expect(page.locator('#personalSign')).toHaveText(
'Error: MetaMask Message Signature: User denied message signature.'
)
await expect(page.locator('#personalSignResult')).toHaveText('')
})
})
25 changes: 25 additions & 0 deletions wallets/metamask/test/e2e/wallet-setup/connected.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { defineWalletSetup } from 'core'
import { getExtensionId } from 'fixtures'
import { MetaMask } from '../../../src'

const SEED_PHRASE = 'test test test test test test test test test test test junk'

const PASSWORD = 'Tester@1234'

export default defineWalletSetup(PASSWORD, async (context, walletPage) => {
const extensionId = await getExtensionId(context, 'MetaMask')

const metamask = new MetaMask(context, walletPage, PASSWORD, extensionId)

await metamask.importWallet(SEED_PHRASE)

const page = await context.newPage()

await page.goto('https://metamask.github.io/test-dapp/')

await page.locator('#connectButton').click()

await metamask.connectToDapp()

await page.close()
})

0 comments on commit 7897535

Please sign in to comment.