Skip to content

Commit

Permalink
[#312] Remove SafeWebAuthnSigner
Browse files Browse the repository at this point in the history
  • Loading branch information
akshay-ap committed Apr 11, 2024
1 parent 6526d9a commit bb02eca
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 72 deletions.
48 changes: 0 additions & 48 deletions modules/passkey/contracts/SafeWebAuthnSigner.sol

This file was deleted.

21 changes: 18 additions & 3 deletions modules/passkey/contracts/SafeWebAuthnSignerProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,24 @@ import {IP256Verifier} from "./interfaces/IP256Verifier.sol";
* @dev A proxy contract that points to SafeWebAuthnSigner singleton.
*/
contract SafeWebAuthnSignerProxy {
uint256 internal immutable X;
uint256 internal immutable Y;
IP256Verifier internal immutable VERIFIER;
/**
* @notice The X coordinate of the P-256 public key of the WebAuthn credential.
*/
uint256 public immutable X;

/**
* @notice The Y coordinate of the P-256 public key of the WebAuthn credential.
*/
uint256 public immutable Y;

/**
* @notice The P-256 verifier used for ECDSA signature validation.
*/
IP256Verifier public immutable VERIFIER;

/*
* @notice The singleton contract address.
*/
address internal immutable SINGLETON;
constructor(address implementation, uint256 x, uint256 y, address verifier) {
SINGLETON = implementation;
Expand Down
6 changes: 3 additions & 3 deletions modules/passkey/contracts/SafeWebAuthnSignerSingleton.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.0;

import {SignatureValidatorProxy} from "./base/SignatureValidatorProxy.sol";
import {SignatureValidator} from "./base/SignatureValidator.sol";
import {IP256Verifier} from "./interfaces/IP256Verifier.sol";
import {WebAuthn} from "./libraries/WebAuthn.sol";
/**
* @title WebAuthn Safe Signature Validator Singleton
* @dev A contract that represents a WebAuthn signer.
* @custom:security-contact bounty@safe.global
*/
contract SafeWebAuthnSignerSingleton is SignatureValidatorProxy {
contract SafeWebAuthnSignerSingleton is SignatureValidator {
/**
* @inheritdoc SignatureValidatorProxy
* @inheritdoc SignatureValidator
*/
function _verifySignature(
bytes32 message,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {ERC1271} from "../libraries/ERC1271.sol";
* @dev A interface for smart contract Safe owners that supports multiple ERC-1271 `isValidSignature` versions.
* @custom:security-contact bounty@safe.global
*/
abstract contract SignatureValidatorProxy {
abstract contract SignatureValidator {
/**
* @dev Validates the signature for the given data.
* @param data The signed data bytes.
Expand Down
17 changes: 11 additions & 6 deletions modules/passkey/test/SafeWebAuthnSigner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,30 @@ import { deployments, ethers } from 'hardhat'
import * as ERC1271 from './utils/erc1271'
import { DUMMY_AUTHENTICATOR_DATA, base64UrlEncode, encodeWebAuthnSigningMessage, getSignatureBytes } from './utils/webauthn'

describe('SafeWebAuthnSigner', () => {
describe('SafeWebAuthnSignerProxy', () => {
const setupTests = deployments.createFixture(async () => {
const x = ethers.id('publicKey.x')
const y = ethers.id('publicKey.y')
const MockContract = await ethers.getContractFactory('MockContract')
const mockVerifier = await MockContract.deploy()
const SafeWebAuthnSigner = await ethers.getContractFactory('SafeWebAuthnSigner')
const signer = await SafeWebAuthnSigner.deploy(x, y, mockVerifier)
const singleton = await (await ethers.getContractFactory('SafeWebAuthnSignerSingleton')).deploy()
const SafeWebAuthnSignerProxy = await ethers.getContractFactory('SafeWebAuthnSignerProxy')
const signer = await ethers.getContractAt(
'SafeWebAuthnSignerSingleton',
(await SafeWebAuthnSignerProxy.deploy(singleton, x, y, mockVerifier)).target,
)

return { x, y, mockVerifier, signer }
})

describe('constructor', function () {
it('Should set immutables', async () => {
const { x, y, mockVerifier, signer } = await setupTests()
const signerProxy = await ethers.getContractAt('SafeWebAuthnSignerProxy', signer.target)

expect(await signer.X()).to.equal(x)
expect(await signer.Y()).to.equal(y)
expect(await signer.VERIFIER()).to.equal(mockVerifier.target)
expect(await signerProxy.X()).to.equal(x)
expect(await signerProxy.Y()).to.equal(y)
expect(await signerProxy.VERIFIER()).to.equal(mockVerifier.target)
})
})

Expand Down
17 changes: 9 additions & 8 deletions modules/passkey/test/SafeWebAuthnSignerFactory.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ import { deployments, ethers } from 'hardhat'
import * as ERC1271 from './utils/erc1271'
import { DUMMY_AUTHENTICATOR_DATA, base64UrlEncode, encodeWebAuthnSigningMessage, getSignatureBytes } from './utils/webauthn'

describe('SafeWebAuthnSignerFactory', () => {
describe('SafeWebAuthnSignerProxyFactory', () => {
const setupTests = deployments.createFixture(async () => {
const { SafeWebAuthnSignerFactory } = await deployments.fixture()
const factory = await ethers.getContractAt('SafeWebAuthnSignerFactory', SafeWebAuthnSignerFactory.address)
const { SafeWebAuthnSignerProxyFactory } = await deployments.fixture()

const factory = await ethers.getContractAt('SafeWebAuthnSignerProxyFactory', SafeWebAuthnSignerProxyFactory.address)

const singletonAddress = await factory.SINGLETON()
const MockContract = await ethers.getContractFactory('MockContract')
const mockVerifier = await MockContract.deploy()

return { factory, mockVerifier }
return { factory, mockVerifier, singletonAddress }
})

describe('getSigner', function () {
it('Should return the address that a signer will be created on', async () => {
const { factory, mockVerifier } = await setupTests()

const x = ethers.id('publicKey.x')
const y = ethers.id('publicKey.y')

Expand Down Expand Up @@ -51,15 +52,15 @@ describe('SafeWebAuthnSignerFactory', () => {

describe('createSigner', function () {
it('Should create a signer and return its deterministic address', async () => {
const { factory, mockVerifier } = await setupTests()
const { factory, mockVerifier, singletonAddress } = await setupTests()

const x = ethers.id('publicKey.x')
const y = ethers.id('publicKey.y')

const signer = await factory.createSigner.staticCall(x, y, mockVerifier)

const SafeWebAuthnSigner = await ethers.getContractFactory('SafeWebAuthnSigner')
const { data: initCode } = await SafeWebAuthnSigner.getDeployTransaction(x, y, mockVerifier)
const SafeWebAuthnSignerProxy = await ethers.getContractFactory('SafeWebAuthnSignerProxy')
const { data: initCode } = await SafeWebAuthnSignerProxy.getDeployTransaction(singletonAddress, x, y, mockVerifier)
expect(signer).to.equal(ethers.getCreate2Address(await factory.getAddress(), ethers.ZeroHash, ethers.keccak256(initCode)))

expect(ethers.dataLength(await ethers.provider.getCode(signer))).to.equal(0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ import { buildSafeTransaction, buildSafeTransactionData, SafeDomain } from '../u
*/
describe('Passkey Credential Creation for Safe Ownership [@userstory]', () => {
const setupTests = deployments.createFixture(async ({ deployments }) => {
const { SafeProxyFactory, SafeL2, FCLP256Verifier, SafeWebAuthnSignerFactory, CompatibilityFallbackHandler } = await deployments.run()
const { SafeProxyFactory, SafeL2, FCLP256Verifier, SafeWebAuthnSignerProxyFactory, CompatibilityFallbackHandler } =
await deployments.run()
const [user] = await ethers.getSigners()

const proxyFactory = await ethers.getContractAt(SafeProxyFactory.abi, SafeProxyFactory.address)
const singleton = await ethers.getContractAt(SafeL2.abi, SafeL2.address)
const fallbackHandler = await ethers.getContractAt(CompatibilityFallbackHandler.abi, CompatibilityFallbackHandler.address)
const signerFactory = await ethers.getContractAt('SafeWebAuthnSignerFactory', SafeWebAuthnSignerFactory.address)
const signerFactory = await ethers.getContractAt('SafeWebAuthnSignerProxyFactory', SafeWebAuthnSignerProxyFactory.address)
const verifier = await ethers.getContractAt('IP256Verifier', FCLP256Verifier.address)
const verifierAddress = await verifier.getAddress()

Expand Down Expand Up @@ -50,7 +51,7 @@ describe('Passkey Credential Creation for Safe Ownership [@userstory]', () => {
const publicKey = decodePublicKey(credential.response)
await signerFactory.createSigner(publicKey.x, publicKey.y, verifierAddress)
const signerAddress = await signerFactory.getSigner(publicKey.x, publicKey.y, verifierAddress)
const signer = await ethers.getContractAt('SafeWebAuthnSigner', signerAddress)
const signer = await ethers.getContractAt('SafeWebAuthnSignerProxy', signerAddress)

// Deploy Safe with the WebAuthn signer as a single owner.
const singletonAddress = await singleton.getAddress()
Expand Down

0 comments on commit bb02eca

Please sign in to comment.