Skip to content

Commit

Permalink
Merge branch 'main' of github.com:safe-global/safe-modules into feat/…
Browse files Browse the repository at this point in the history
…webauth-poc-app
  • Loading branch information
mmv08 committed Jan 16, 2024
2 parents 878f63c + 3853f34 commit 519fb7c
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 14 deletions.
13 changes: 9 additions & 4 deletions modules/4337/contracts/experimental/SafeSignerLaunchpad.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pragma solidity >=0.8.0 <0.9.0;
import {IAccount} from "@account-abstraction/contracts/interfaces/IAccount.sol";
import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol";
import {_packValidationData} from "@account-abstraction/contracts/core/Helpers.sol";
import {ISignatureValidator} from "@safe-global/safe-contracts/contracts/interfaces/ISignatureValidator.sol";
import {SafeStorage} from "@safe-global/safe-contracts/contracts/libraries/SafeStorage.sol";
import {SignatureValidatorConstants} from "./SignatureValidatorConstants.sol";

interface IUniqueSignerFactory {
/**
Expand All @@ -31,7 +31,7 @@ interface IUniqueSignerFactory {
* @param data The data whose signature should be verified.
* @param signature The signature bytes.
* @param signerData The signer data to verify signature for.
* @return magicValue Returns `ISignatureValidator.isValidSignature.selector` when the signature is valid. Reverting or returning any other value implies an invalid signature.
* @return magicValue Returns a legacy EIP-1271 magic value (`bytes4(keccak256(isValidSignature(bytes,bytes))`) when the signature is valid. Reverting or returning any other value implies an invalid signature.
*/
function isValidSignatureForSigner(
bytes calldata data,
Expand All @@ -44,7 +44,7 @@ interface IUniqueSignerFactory {
* @title SafeOpLaunchpad - A contract for Safe initialization with custom unique signers that would violate ERC-4337 factory rules.
* @dev The is intended to be set as a Safe proxy's implementation for ERC-4337 user operation that deploys the account.
*/
contract SafeSignerLaunchpad is IAccount, SafeStorage {
contract SafeSignerLaunchpad is IAccount, SafeStorage, SignatureValidatorConstants {
bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");

// keccak256("SafeSignerLaunchpad.initHash") - 1
Expand Down Expand Up @@ -171,11 +171,16 @@ contract SafeSignerLaunchpad is IAccount, SafeStorage {

bytes memory operationData = _getOperationData(userOpHash, validAfter, validUntil);
bytes4 magicValue = IUniqueSignerFactory(signerFactory).isValidSignatureForSigner(operationData, signature, signerData);
validationData = _packValidationData(magicValue != ISignatureValidator.isValidSignature.selector, validUntil, validAfter);
validationData = _packValidationData(magicValue != LEGACY_EIP1271_MAGIC_VALUE, validUntil, validAfter);

if (missingAccountFunds > 0) {
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
// The `pop` is necessary here because solidity 0.5.0
// enforces "strict" assembly blocks and "statements (elements of a block) are disallowed if they return something onto the stack at the end."
// This is not well documented, the quote is taken from here:
// https://github.com/ethereum/solidity/issues/1820
// The compiler will throw an error if we keep the success value on the stack
pop(call(gas(), caller(), missingAccountFunds, 0, 0, 0, 0))
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: LGPL-3.0-only
/* solhint-disable one-contract-per-file */
pragma solidity >=0.7.0 <0.9.0;

/**
* @title SignatureValidatorConstants
* @dev This contract defines the constants used for EIP-1271 signature validation.
*/
contract SignatureValidatorConstants {
// bytes4(keccak256("isValidSignature(bytes32,bytes)")
bytes4 internal constant EIP1271_MAGIC_VALUE = 0x1626ba7e;

// bytes4(keccak256("isValidSignature(bytes,bytes)")
bytes4 internal constant LEGACY_EIP1271_MAGIC_VALUE = 0x20c13b0b;
}
34 changes: 24 additions & 10 deletions modules/4337/contracts/experimental/WebAuthnSigner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pragma solidity >=0.8.0;

import {FCL_WebAuthn} from "../vendor/FCL/FCL_Webauthn.sol";
import {SignatureValidatorConstants} from "./SignatureValidatorConstants.sol";
import {IUniqueSignerFactory} from "./SafeSignerLaunchpad.sol";

struct SignatureData {
Expand All @@ -12,14 +13,14 @@ struct SignatureData {
uint256[2] rs;
}

function checkSignature(bytes memory data, bytes calldata signature, uint256 x, uint256 y) view returns (bytes4 magicValue) {
function checkSignature(bytes memory data, bytes calldata signature, uint256 x, uint256 y) view returns (bool valid) {
SignatureData calldata signaturePointer;
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
signaturePointer := signature.offset
}

if (
return
FCL_WebAuthn.checkSignature(
signaturePointer.authenticatorData,
0x01, // require user presence
Expand All @@ -29,17 +30,14 @@ function checkSignature(bytes memory data, bytes calldata signature, uint256 x,
signaturePointer.rs,
x,
y
)
) {
magicValue = WebAuthnSigner.isValidSignature.selector;
}
);
}

/**
* @title WebAuthnSigner
* @dev A contract that represents a WebAuthn signer.
*/
contract WebAuthnSigner {
contract WebAuthnSigner is SignatureValidatorConstants {
uint256 public immutable X;
uint256 public immutable Y;

Expand All @@ -60,15 +58,29 @@ contract WebAuthnSigner {
* @return magicValue The magic value indicating the validity of the signature.
*/
function isValidSignature(bytes memory data, bytes calldata signature) external view returns (bytes4 magicValue) {
return checkSignature(data, signature, X, Y);
if (checkSignature(data, signature, X, Y)) {
magicValue = LEGACY_EIP1271_MAGIC_VALUE;
}
}

/**
* @dev Validates the signature for a given data hash.
* @param dataHash The hash of the data to be validated.
* @param signature The signature to be validated.
* @return magicValue The magic value indicating the validity of the signature.
*/
function isValidSignature(bytes32 dataHash, bytes calldata signature) external view returns (bytes4 magicValue) {
if (checkSignature(abi.encode(dataHash), signature, X, Y)) {
magicValue = EIP1271_MAGIC_VALUE;
}
}
}

/**
* @title WebAuthnSignerFactory
* @dev A factory contract for creating and managing WebAuthn signers.
*/
contract WebAuthnSignerFactory is IUniqueSignerFactory {
contract WebAuthnSignerFactory is IUniqueSignerFactory, SignatureValidatorConstants {
/**
* @dev Retrieves the signer address based on the provided data.
* @param data Concatenated X and Y coordinates of the signer as bytes.
Expand Down Expand Up @@ -106,7 +118,9 @@ contract WebAuthnSignerFactory is IUniqueSignerFactory {
bytes calldata signerData
) external view override returns (bytes4 magicValue) {
(uint256 x, uint256 y) = abi.decode(signerData, (uint256, uint256));
magicValue = checkSignature(data, signature, x, y);
if (checkSignature(data, signature, x, y)) {
magicValue = LEGACY_EIP1271_MAGIC_VALUE;
}
}

/**
Expand Down

0 comments on commit 519fb7c

Please sign in to comment.