Skip to content

Commit

Permalink
✅ plugin: test passkey owner
Browse files Browse the repository at this point in the history
  • Loading branch information
cruzdanilo committed Apr 10, 2024
1 parent 7359287 commit 57447d9
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 12 deletions.
24 changes: 13 additions & 11 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@ MultiOwnerPluginIntegration:test_ownerPlugin_successInstallation() (gas: 39749)
MultiOwnerPluginIntegration:test_runtimeValidation_alwaysAllow_isValidSignature() (gas: 111927)
MultiOwnerPluginIntegration:test_runtimeValidation_ownerOrSelf_standardExecute() (gas: 146828)
MultiOwnerPluginIntegration:test_userOpValidation_owner_standardExecute() (gas: 332445)
MultiOwnerPluginTest:testFuzz_isValidSignature_ContractOwner(bytes32) (runs: 256, μ: 111557, ~: 111557)
MultiOwnerPluginTest:testFuzz_isValidSignature_ContractOwnerWithEOAOwner(bytes32) (runs: 256, μ: 121977, ~: 121977)
MultiOwnerPluginTest:testFuzz_isValidSignature_EOAOwner(string,bytes32) (runs: 256, μ: 133967, ~: 133960)
MultiOwnerPluginTest:testFuzz_userOpValidationFunction_ContractOwner((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes)) (runs: 256, μ: 133574, ~: 133571)
MultiOwnerPluginTest:testFuzz_userOpValidationFunction_ContractOwnerWithEOAOwner((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes)) (runs: 256, μ: 147397, ~: 147394)
MultiOwnerPluginTest:testFuzz_userOpValidationFunction_EOAOwner(string,(address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes)) (runs: 256, μ: 141613, ~: 141603)
MultiOwnerPluginTest:test_eip712Domain() (gas: 36354)
MultiOwnerPluginTest:testFuzz_isValidSignature_ContractOwner(bytes32) (runs: 256, μ: 111585, ~: 111585)
MultiOwnerPluginTest:testFuzz_isValidSignature_ContractOwnerWithEOAOwner(bytes32) (runs: 256, μ: 121995, ~: 121995)
MultiOwnerPluginTest:testFuzz_isValidSignature_EOAOwner(string,bytes32) (runs: 256, μ: 134007, ~: 134000)
MultiOwnerPluginTest:testFuzz_isValidSignature_PasskeyOwner(bytes32) (runs: 256, μ: 540852, ~: 540606)
MultiOwnerPluginTest:testFuzz_userOpValidationFunction_ContractOwner((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes)) (runs: 256, μ: 133712, ~: 133709)
MultiOwnerPluginTest:testFuzz_userOpValidationFunction_ContractOwnerWithEOAOwner((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes)) (runs: 256, μ: 147415, ~: 147412)
MultiOwnerPluginTest:testFuzz_userOpValidationFunction_EOAOwner(string,(address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes)) (runs: 256, μ: 141609, ~: 141599)
MultiOwnerPluginTest:testFuzz_userOpValidationFunction_PasskeyOwner((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes)) (runs: 256, μ: 547602, ~: 547725)
MultiOwnerPluginTest:test_eip712Domain() (gas: 36308)
MultiOwnerPluginTest:test_multiOwnerPlugin_sentinelIsNotOwner() (gas: 19897)
MultiOwnerPluginTest:test_onInstall_success() (gas: 91236)
MultiOwnerPluginTest:test_onInstall_success() (gas: 91258)
MultiOwnerPluginTest:test_onUninstall_success() (gas: 69907)
MultiOwnerPluginTest:test_pluginInitializeGuards() (gas: 155534)
MultiOwnerPluginTest:test_pluginManifest() (gas: 40036)
MultiOwnerPluginTest:test_pluginManifest() (gas: 39947)
MultiOwnerPluginTest:test_runtimeValidationFunction_OwnerOrSelf() (gas: 26864)
MultiOwnerPluginTest:test_updateOwners_failWithDuplicatedAddresses() (gas: 85485)
MultiOwnerPluginTest:test_updateOwners_failWithEmptyOwners() (gas: 73872)
MultiOwnerPluginTest:test_updateOwners_failWithDuplicatedAddresses() (gas: 85507)
MultiOwnerPluginTest:test_updateOwners_failWithEmptyOwners() (gas: 73894)
MultiOwnerPluginTest:test_updateOwners_failWithNotExist() (gas: 58820)
MultiOwnerPluginTest:test_updateOwners_failWithZeroAddressOwner() (gas: 62527)
MultiOwnerPluginTest:test_updateOwners_success() (gas: 115523)
80 changes: 79 additions & 1 deletion test/MultiOwnerPlugin.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ import { ContractOwner } from "modular-account/test/mocks/ContractOwner.sol";

import { ECDSA } from "solady/utils/ECDSA.sol";

import { WebauthnOwnerPlugin, SignatureWrapper } from "../src/WebauthnOwnerPlugin.sol";
import { WebAuthn } from "webauthn-sol/WebAuthn.sol";
import { Utils, WebAuthnInfo } from "webauthn-sol/../test/Utils.sol";

import { WebauthnOwnerPlugin, PublicKey, SignatureWrapper } from "../src/WebauthnOwnerPlugin.sol";

import { TestLib } from "./utils/TestLib.sol";

// solhint-disable func-name-mixedcase
contract MultiOwnerPluginTest is Test {
using TestLib for address;
using Utils for uint256;
using Utils for bytes32;
using ECDSA for bytes32;

WebauthnOwnerPlugin public plugin;
Expand All @@ -36,6 +41,8 @@ contract MultiOwnerPluginTest is Test {
address public ownerOfContractOwner;
uint256 public ownerOfContractOwnerKey;
ContractOwner public contractOwner;
PublicKey public passkeyOwner;
uint256 public passkeyOwnerKey;
address[] public ownerArray;

// Re-declare events for vm.expectEmit
Expand All @@ -52,6 +59,11 @@ contract MultiOwnerPluginTest is Test {
owner3 = makeAddr("owner3");
(ownerOfContractOwner, ownerOfContractOwnerKey) = makeAddrAndKey("ownerOfContractOwner");
contractOwner = new ContractOwner(ownerOfContractOwner);
passkeyOwner = abi.decode(
hex"1c05286fe694493eae33312f2d2e0d0abeda8db76238b7a204be1fb87f54ce4228fef61ef4ac300f631657635c28e59bfb2fe71bce1634c81c65642042f6dc4d",
(PublicKey)
);
passkeyOwnerKey = uint256(0x03d99692017473e2d631945a812607b23269d85721e0f370b8d3e7d29a874fd2);

// set up owners for accountA
ownerArray = new address[](3);
Expand Down Expand Up @@ -194,6 +206,34 @@ contract MultiOwnerPluginTest is Test {
);
}

function testFuzz_isValidSignature_PasskeyOwner(bytes32 digest) external {
WebAuthnInfo memory webauthn = plugin.getMessageHash(address(accountA), abi.encode(digest)).getWebAuthnStruct();
(bytes32 r, bytes32 s) = vm.signP256(passkeyOwnerKey, webauthn.messageHash);
SignatureWrapper memory sig = SignatureWrapper({
ownerIndex: 0,
signatureData: abi.encode(
WebAuthn.WebAuthnAuth({
authenticatorData: webauthn.authenticatorData,
clientDataJSON: webauthn.clientDataJSON,
typeIndex: 1,
challengeIndex: 23,
r: uint256(r),
s: uint256(s).normalizeS()
})
)
});

assertEq(bytes4(0xFFFFFFFF), plugin.isValidSignature(digest, abi.encode(sig)));

PublicKey[] memory ownersToAdd = new PublicKey[](1);
ownersToAdd[0] = passkeyOwner;
plugin.updateOwnersPublicKeys(ownersToAdd, new PublicKey[](0));
sig.ownerIndex = plugin.ownerIndexOf(accountA, passkeyOwner);

// sig check should pass
assertEq(_1271_MAGIC_VALUE, plugin.isValidSignature(digest, abi.encode(sig)));
}

function testFuzz_isValidSignature_ContractOwner(bytes32 digest) external {
address[] memory ownersToAdd = new address[](1);
ownersToAdd[0] = address(contractOwner);
Expand Down Expand Up @@ -317,6 +357,44 @@ contract MultiOwnerPluginTest is Test {
assertEq(resSuccess, 0);
}

function testFuzz_userOpValidationFunction_PasskeyOwner(UserOperation memory userOp) external {
bytes32 userOpHash = entryPoint.getUserOpHash(userOp);
WebAuthnInfo memory webauthn = userOpHash.toEthSignedMessageHash().getWebAuthnStruct();
(bytes32 r, bytes32 s) = vm.signP256(passkeyOwnerKey, webauthn.messageHash);
SignatureWrapper memory sig = SignatureWrapper({
ownerIndex: 0,
signatureData: abi.encode(
WebAuthn.WebAuthnAuth({
authenticatorData: webauthn.authenticatorData,
clientDataJSON: webauthn.clientDataJSON,
typeIndex: 1,
challengeIndex: 23,
r: uint256(r),
s: uint256(s).normalizeS()
})
)
});

// sig cannot cover the whole user-op struct since user-op struct has sig field
userOp.signature = abi.encode(sig);

// should fail without owner access
uint256 resFail =
plugin.userOpValidationFunction(uint8(IMultiOwnerPlugin.FunctionId.USER_OP_VALIDATION_OWNER), userOp, userOpHash);
assertEq(resFail, 1);

PublicKey[] memory ownersToAdd = new PublicKey[](1);
ownersToAdd[0] = passkeyOwner;
plugin.updateOwnersPublicKeys(ownersToAdd, new PublicKey[](0));
sig.ownerIndex = plugin.ownerIndexOf(accountA, passkeyOwner);
userOp.signature = abi.encode(sig);

// should pass with owner access
uint256 resSuccess =
plugin.userOpValidationFunction(uint8(IMultiOwnerPlugin.FunctionId.USER_OP_VALIDATION_OWNER), userOp, userOpHash);
assertEq(resSuccess, 0);
}

function test_pluginInitializeGuards() external {
plugin.onUninstall(bytes(""));

Expand Down

0 comments on commit 57447d9

Please sign in to comment.