From 57447d9ec786957ca6ac0cb03e54190a5aa391a0 Mon Sep 17 00:00:00 2001 From: danilo neves cruz Date: Wed, 10 Apr 2024 15:16:35 -0300 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=20plugin:=20test=20passkey=20owner?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 24 ++++++----- test/MultiOwnerPlugin.t.sol | 80 ++++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 12 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 97e6974..64f39e1 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -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) \ No newline at end of file diff --git a/test/MultiOwnerPlugin.t.sol b/test/MultiOwnerPlugin.t.sol index 3d878a5..318611c 100644 --- a/test/MultiOwnerPlugin.t.sol +++ b/test/MultiOwnerPlugin.t.sol @@ -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; @@ -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 @@ -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); @@ -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); @@ -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(""));