Skip to content

Commit

Permalink
Indexed Public Key Hash
Browse files Browse the repository at this point in the history
  • Loading branch information
nlordell committed Jul 10, 2024
1 parent 0b80eea commit d12d35a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 3 deletions.
6 changes: 4 additions & 2 deletions modules/passkey/contracts/4337/SafeWebAuthnSharedSigner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion modules/passkey/test/4337/SafeWebAuthnSharedSigner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand All @@ -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 () => {
Expand Down
39 changes: 39 additions & 0 deletions modules/passkey/test/userstories/SafeAddressForPasskey.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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())
})
})

0 comments on commit d12d35a

Please sign in to comment.