diff --git a/.github/workflows/certora.yml b/.github/workflows/certora.yml index 6d7d1cd0c..70dde4818 100644 --- a/.github/workflows/certora.yml +++ b/.github/workflows/certora.yml @@ -36,7 +36,7 @@ jobs: with: { java-version: "17", java-package: jre, distribution: semeru } - name: Install certora cli - run: pip install -Iv certora-cli + run: pip install -Iv certora-cli==5.0.5 - name: Install solc run: | diff --git a/4337/.prettierignore b/4337/.prettierignore index f3147ff3a..4823dede4 100644 --- a/4337/.prettierignore +++ b/4337/.prettierignore @@ -1 +1 @@ -contracts/test/FCL/**/*.sol +contracts/vendor/FCL/**/*.sol diff --git a/4337/contracts/test/SafeSignerLaunchpad.sol b/4337/contracts/experimental/SafeSignerLaunchpad.sol similarity index 100% rename from 4337/contracts/test/SafeSignerLaunchpad.sol rename to 4337/contracts/experimental/SafeSignerLaunchpad.sol diff --git a/4337/contracts/test/WebAuthnSigner.sol b/4337/contracts/experimental/WebAuthnSigner.sol similarity index 60% rename from 4337/contracts/test/WebAuthnSigner.sol rename to 4337/contracts/experimental/WebAuthnSigner.sol index 74bf4f615..a1ed7195d 100644 --- a/4337/contracts/test/WebAuthnSigner.sol +++ b/4337/contracts/experimental/WebAuthnSigner.sol @@ -1,8 +1,9 @@ + // SPDX-License-Identifier: LGPL-3.0-only /* solhint-disable one-contract-per-file */ pragma solidity >=0.8.0; -import {FCL_WebAuthn} from "./FCL/FCL_Webauthn.sol"; +import {FCL_WebAuthn} from "../vendor/FCL/FCL_Webauthn.sol"; import {IUniqueSignerFactory} from "./SafeSignerLaunchpad.sol"; struct SignatureData { @@ -35,26 +36,55 @@ function checkSignature(bytes memory data, bytes calldata signature, uint256 x, } } +/** + * @title WebAuthnSigner + * @dev A contract that represents a WebAuthn signer. + */ contract WebAuthnSigner { uint256 public immutable X; uint256 public immutable Y; + /** + * @dev Constructor function. + * @param x The X coordinate of the signer's public key. + * @param y The Y coordinate of the signer's public key. + */ constructor(uint256 x, uint256 y) { X = x; Y = y; } + /** + * @dev Validates the signature for the given data. + * @param data The signed data bytes. + * @param signature The signature to be validated. + * @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); } } +/** + * @title WebAuthnSignerFactory + * @dev A factory contract for creating and managing WebAuthn signers. + */ contract WebAuthnSignerFactory is IUniqueSignerFactory { + /** + * @dev Retrieves the signer address based on the provided data. + * @param data Concatenated X and Y coordinates of the signer as bytes. + * @return signer The address of the signer. + */ function getSigner(bytes calldata data) public view returns (address signer) { (uint256 x, uint256 y) = abi.decode(data, (uint256, uint256)); signer = _getSigner(x, y); } + /** + * @dev Creates a new signer based on the provided data. + * @param data Concatenated X and Y coordinates of the signer as bytes. + * @return signer The address of the newly created signer. + */ function createSigner(bytes calldata data) external returns (address signer) { (uint256 x, uint256 y) = abi.decode(data, (uint256, uint256)); signer = _getSigner(x, y); @@ -64,6 +94,13 @@ contract WebAuthnSignerFactory is IUniqueSignerFactory { } } + /** + * @dev Checks if the provided signature is valid for the given signer. + * @param data The signed data as bytes. + * @param signature The signature to be verified. + * @param signerData The data used to identify the signer. In this case, the X and Y coordinates of the signer. + * @return magicValue The magic value indicating the validity of the signature. + */ function isValidSignatureForSigner( bytes memory data, bytes calldata signature, @@ -73,11 +110,22 @@ contract WebAuthnSignerFactory is IUniqueSignerFactory { magicValue = checkSignature(data, signature, x, y); } + /** + * @dev Retrieves the signer address based on the provided coordinates. + * @param x The x-coordinate of the signer. + * @param y The y-coordinate of the signer. + * @return The address of the signer. + */ function _getSigner(uint256 x, uint256 y) internal view returns (address) { bytes32 codeHash = keccak256(abi.encodePacked(type(WebAuthnSigner).creationCode, x, y)); return address(uint160(uint256(keccak256(abi.encodePacked(hex"ff", address(this), bytes32(0), codeHash))))); } + /** + * @dev Checks if the provided account has no code. + * @param account The address of the account to check. + * @return True if the account has no code, false otherwise. + */ function _hasNoCode(address account) internal view returns (bool) { uint256 size; // solhint-disable-next-line no-inline-assembly diff --git a/4337/contracts/test/TestUniqueSigner.sol b/4337/contracts/test/TestUniqueSigner.sol index 2d0407fc5..b33c83a26 100644 --- a/4337/contracts/test/TestUniqueSigner.sol +++ b/4337/contracts/test/TestUniqueSigner.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.0; import {ISignatureValidator} from "@safe-global/safe-contracts/contracts/interfaces/ISignatureValidator.sol"; -import {IUniqueSignerFactory} from "./SafeSignerLaunchpad.sol"; +import {IUniqueSignerFactory} from "../experimental/SafeSignerLaunchpad.sol"; function checkSignature(bytes memory data, uint256 signature, uint256 key) pure returns (bytes4 magicValue) { uint256 message = uint256(keccak256(data)); diff --git a/4337/contracts/test/FCL/FCL_Webauthn.sol b/4337/contracts/vendor/FCL/FCL_Webauthn.sol similarity index 100% rename from 4337/contracts/test/FCL/FCL_Webauthn.sol rename to 4337/contracts/vendor/FCL/FCL_Webauthn.sol diff --git a/4337/contracts/test/FCL/FCL_ecdsa.sol b/4337/contracts/vendor/FCL/FCL_ecdsa.sol similarity index 100% rename from 4337/contracts/test/FCL/FCL_ecdsa.sol rename to 4337/contracts/vendor/FCL/FCL_ecdsa.sol diff --git a/4337/contracts/test/FCL/FCL_ecdsa_utils.sol b/4337/contracts/vendor/FCL/FCL_ecdsa_utils.sol similarity index 100% rename from 4337/contracts/test/FCL/FCL_ecdsa_utils.sol rename to 4337/contracts/vendor/FCL/FCL_ecdsa_utils.sol diff --git a/4337/contracts/test/FCL/FCL_elliptic.sol b/4337/contracts/vendor/FCL/FCL_elliptic.sol similarity index 100% rename from 4337/contracts/test/FCL/FCL_elliptic.sol rename to 4337/contracts/vendor/FCL/FCL_elliptic.sol diff --git a/4337/contracts/test/FCL/VERSION.md b/4337/contracts/vendor/FCL/VERSION.md similarity index 100% rename from 4337/contracts/test/FCL/VERSION.md rename to 4337/contracts/vendor/FCL/VERSION.md diff --git a/4337/contracts/test/FCL/utils/Base64Url.sol b/4337/contracts/vendor/FCL/utils/Base64Url.sol similarity index 100% rename from 4337/contracts/test/FCL/utils/Base64Url.sol rename to 4337/contracts/vendor/FCL/utils/Base64Url.sol diff --git a/4337/src/deploy/webauthn.ts b/4337/src/deploy/webauthn.ts new file mode 100644 index 000000000..6fc7f6a04 --- /dev/null +++ b/4337/src/deploy/webauthn.ts @@ -0,0 +1,19 @@ +import { DeployFunction } from 'hardhat-deploy/types' + +const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }) => { + if (!network.tags.dev && !network.tags.test) { + return + } + + const { deployer } = await getNamedAccounts() + const { deploy } = deployments + + await deploy('WebAuthnSignerFactory', { + from: deployer, + args: [], + log: true, + deterministicDeployment: true, + }) +} + +export default deploy