From d12d35a0cc4b0227f27c262ffaf6c3d1c3f3c55e Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Wed, 10 Jul 2024 09:03:42 +0200 Subject: [PATCH] Indexed Public Key Hash --- .../4337/SafeWebAuthnSharedSigner.sol | 6 ++- .../4337/SafeWebAuthnSharedSigner.spec.ts | 3 +- .../userstories/SafeAddressForPasskey.spec.ts | 39 +++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/modules/passkey/contracts/4337/SafeWebAuthnSharedSigner.sol b/modules/passkey/contracts/4337/SafeWebAuthnSharedSigner.sol index 9329b8e2..f73b6eb0 100644 --- a/modules/passkey/contracts/4337/SafeWebAuthnSharedSigner.sol +++ b/modules/passkey/contracts/4337/SafeWebAuthnSharedSigner.sol @@ -50,11 +50,12 @@ contract SafeWebAuthnSharedSigner is SignatureValidator { * is done as a `DELEGATECALL`, the contract emitting the event is the configured account. This * is also why the event name is prefixed with `SafeWebAuthnSharedSigner`, in order to avoid * event `topic0` collisions with other contracts (seeing as "configured" is a common term). + * @param publicKeyHash The Keccak-256 hash of the public key coordinates. * @param x The x-coordinate of the public key. * @param y The y-coordinate of the public key. * @param verifiers The P-256 verifiers to use. */ - event SafeWebAuthnSharedSignerConfigured(uint256 x, uint256 y, P256.Verifiers verifiers); + event SafeWebAuthnSharedSignerConfigured(bytes32 indexed publicKeyHash, uint256 x, uint256 y, P256.Verifiers verifiers); /** * @notice An error indicating a `CALL` to a function that should only be `DELEGATECALL`-ed. @@ -146,7 +147,8 @@ contract SafeWebAuthnSharedSigner is SignatureValidator { signerStorage.y = signer.y; signerStorage.verifiers = signer.verifiers; - emit SafeWebAuthnSharedSignerConfigured(signer.x, signer.y, signer.verifiers); + bytes32 publicKeyHash = keccak256(abi.encode(signer.x, signer.y)); + emit SafeWebAuthnSharedSignerConfigured(publicKeyHash, signer.x, signer.y, signer.verifiers); } /** diff --git a/modules/passkey/test/4337/SafeWebAuthnSharedSigner.spec.ts b/modules/passkey/test/4337/SafeWebAuthnSharedSigner.spec.ts index 30f5a3b7..d27a5cf9 100644 --- a/modules/passkey/test/4337/SafeWebAuthnSharedSigner.spec.ts +++ b/modules/passkey/test/4337/SafeWebAuthnSharedSigner.spec.ts @@ -178,6 +178,7 @@ describe('SafeWebAuthnSharedSigner', () => { y: ethers.id('publicKey.y'), verifiers: ethers.toBeHex(await mockVerifier.getAddress(), 32), } + const publicKeyHash = ethers.solidityPackedKeccak256(['uint256', 'uint256'], [config.x, config.y]) const initializer = safeSingleton.interface.encodeFunctionData('setup', [ [sharedSigner.target], @@ -193,7 +194,7 @@ describe('SafeWebAuthnSharedSigner', () => { const account = await proxyFactory.createProxyWithNonce.staticCall(safeSingleton, initializer, 0) await expect(proxyFactory.createProxyWithNonce(safeSingleton, initializer, 0)) .to.emit(sharedSigner.attach(account), 'SafeWebAuthnSharedSignerConfigured') - .withArgs(config.x, config.y, config.verifiers) + .withArgs(publicKeyHash, config.x, config.y, config.verifiers) }) it('Should revert if not DELEGATECALL-ed', async () => { diff --git a/modules/passkey/test/userstories/SafeAddressForPasskey.spec.ts b/modules/passkey/test/userstories/SafeAddressForPasskey.spec.ts index dc4c28e6..d58cb2ec 100644 --- a/modules/passkey/test/userstories/SafeAddressForPasskey.spec.ts +++ b/modules/passkey/test/userstories/SafeAddressForPasskey.spec.ts @@ -130,4 +130,43 @@ describe('Safe Address for Passkey [@userstory]', () => { expect(deterministicSafeAddress).to.equal(await safe.getAddress()) }) + + it('should search for Safes owned by a WebAuthn shared signer', async () => { + const { safeSingleton, sharedSigner, signerConfig, deploySafe } = await setupTests() + + const safe = await deploySafe({ + initializer: safeSingleton.interface.encodeFunctionData('setup', [ + [await sharedSigner.getAddress()], + 1, + await sharedSigner.getAddress(), + sharedSigner.interface.encodeFunctionData('configure', [signerConfig]), + ethers.ZeroAddress, + ethers.ZeroAddress, + 0, + ethers.ZeroAddress, + ]), + saltNonce: 0n, + }) + + let foundSafeAddress = null + + const publicKeyHash = ethers.solidityPackedKeccak256(['uint256', 'uint256'], [signerConfig.x, signerConfig.y]) + const configuredSafes = await ethers.provider.getLogs({ + topics: sharedSigner.interface.encodeFilterTopics('SafeWebAuthnSharedSignerConfigured', [publicKeyHash]), + fromBlock: 0, + }) + for (const { address: possibleSafeAddress } of configuredSafes) { + const possibleSafe = safeSingleton.attach(possibleSafeAddress) as typeof safeSingleton + + const { x, y } = await sharedSigner.getConfiguration(possibleSafe) + const isOwner = await possibleSafe.isOwner(sharedSigner) + + if (signerConfig.x === x && signerConfig.y === y && isOwner) { + foundSafeAddress = possibleSafe + break + } + } + + expect(foundSafeAddress).to.equal(await safe.getAddress()) + }) })