Skip to content

Commit

Permalink
Use encoded account in Safe recovery module
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnGuilding committed Aug 7, 2024
1 parent 730abb1 commit 1e7da8c
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 8 deletions.
18 changes: 11 additions & 7 deletions src/modules/SafeEmailRecoveryModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ contract SafeEmailRecoveryModule is EmailRecoveryManager {

event RecoveryExecuted(address indexed account);

error InvalidAccount(address account);
error InvalidSelector(bytes4 selector);
error RecoveryFailed(address account);

Expand All @@ -37,20 +38,23 @@ contract SafeEmailRecoveryModule is EmailRecoveryManager {
}

/**
* @notice Executes recovery on a Safe account. Must be called by the trusted recovery manager
* @notice Executes recovery on a Safe account. Called from the recovery manager
* @param account The account to execute recovery for
* @param recoveryData The recovery calldata that should be executed on the Safe
* being recovered
* @param recoveryData The recovery data that should be executed on the Safe
* being recovered. recoveryData = abi.encode(safeAccount, recoveryFunctionCalldata)
*/
function recover(address account, bytes calldata recoveryData) internal override {
(, bytes memory recoveryCalldata) = abi.decode(recoveryData, (address, bytes));
// FIXME: What if you use this module with a different subject handler? It could chose
// not to encode the account/validator along with the calldata
(address encodedAccount, bytes memory recoveryCalldata) =
abi.decode(recoveryData, (address, bytes));

if (encodedAccount == address(0) || encodedAccount != account) {
revert InvalidAccount(encodedAccount);
}

bytes4 calldataSelector;
assembly {
calldataSelector := mload(add(recoveryCalldata, 32))
}

if (calldataSelector != selector) {
revert InvalidSelector(calldataSelector);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ contract OwnableValidatorRecovery_EmailRecoveryModule_Integration_Test is
assertEq(recoveryRequest.executeAfter, 0);
assertEq(recoveryRequest.executeBefore, 0);
assertEq(recoveryRequest.currentWeight, 1);
assertEq(recoveryRequest.recoveryDataHash, recoveryDataHash1);

// handle recovery request for guardian 2
uint256 executeAfter = block.timestamp + delay;
Expand All @@ -76,6 +77,7 @@ contract OwnableValidatorRecovery_EmailRecoveryModule_Integration_Test is
assertEq(recoveryRequest.executeAfter, executeAfter);
assertEq(recoveryRequest.executeBefore, executeBefore);
assertEq(recoveryRequest.currentWeight, 3);
assertEq(recoveryRequest.recoveryDataHash, recoveryDataHash1);

// Time travel so that the recovery delay has passed
vm.warp(block.timestamp + delay);
Expand All @@ -89,6 +91,7 @@ contract OwnableValidatorRecovery_EmailRecoveryModule_Integration_Test is
assertEq(recoveryRequest.executeAfter, 0);
assertEq(recoveryRequest.executeBefore, 0);
assertEq(recoveryRequest.currentWeight, 0);
assertEq(recoveryRequest.recoveryDataHash, bytes32(0));
assertEq(updatedOwner, newOwner1);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ contract OwnableValidatorRecovery_UniversalEmailRecoveryModule_Integration_Test
assertEq(recoveryRequest.executeAfter, 0);
assertEq(recoveryRequest.executeBefore, 0);
assertEq(recoveryRequest.currentWeight, 1);
assertEq(recoveryRequest.recoveryDataHash, recoveryDataHash1);

// handle recovery request for guardian 2
uint256 executeAfter = block.timestamp + delay;
Expand All @@ -75,6 +76,7 @@ contract OwnableValidatorRecovery_UniversalEmailRecoveryModule_Integration_Test
assertEq(recoveryRequest.executeAfter, executeAfter);
assertEq(recoveryRequest.executeBefore, executeBefore);
assertEq(recoveryRequest.currentWeight, 3);
assertEq(recoveryRequest.recoveryDataHash, recoveryDataHash1);

// Time travel so that the recovery delay has passed
vm.warp(block.timestamp + delay);
Expand All @@ -88,6 +90,7 @@ contract OwnableValidatorRecovery_UniversalEmailRecoveryModule_Integration_Test
assertEq(recoveryRequest.executeAfter, 0);
assertEq(recoveryRequest.executeBefore, 0);
assertEq(recoveryRequest.currentWeight, 0);
assertEq(recoveryRequest.recoveryDataHash, bytes32(0));
assertEq(updatedOwner, newOwner1);
}

Expand Down
7 changes: 6 additions & 1 deletion test/integration/SafeRecovery/SafeRecoveryNativeModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ contract SafeRecoveryNativeModule_Integration_Test is SafeNativeIntegrationBase
"swapOwner(address,address,address)", address(1), owner, newOwner
);
bytes memory recoveryData = abi.encode(safeAddress, recoveryCalldata);
bytes32 calldataHash = keccak256(recoveryData);
bytes32 recoveryDataHash = keccak256(recoveryData);

bytes[] memory subjectParamsForRecovery = new bytes[](4);
subjectParamsForRecovery[0] = abi.encode(safeAddress);
Expand Down Expand Up @@ -64,7 +64,10 @@ contract SafeRecoveryNativeModule_Integration_Test is SafeNativeIntegrationBase
emailRecoveryModule.handleRecovery(emailAuthMsg, templateIdx);
IEmailRecoveryManager.RecoveryRequest memory recoveryRequest =
emailRecoveryModule.getRecoveryRequest(safeAddress);
assertEq(recoveryRequest.executeAfter, 0);
assertEq(recoveryRequest.executeBefore, 0);
assertEq(recoveryRequest.currentWeight, 1);
assertEq(recoveryRequest.recoveryDataHash, recoveryDataHash);

// handle recovery request for guardian 2
uint256 executeAfter = block.timestamp + delay;
Expand All @@ -75,6 +78,7 @@ contract SafeRecoveryNativeModule_Integration_Test is SafeNativeIntegrationBase
assertEq(recoveryRequest.executeAfter, executeAfter);
assertEq(recoveryRequest.executeBefore, executeBefore);
assertEq(recoveryRequest.currentWeight, 3);
assertEq(recoveryRequest.recoveryDataHash, recoveryDataHash);

vm.warp(block.timestamp + delay);

Expand All @@ -85,6 +89,7 @@ contract SafeRecoveryNativeModule_Integration_Test is SafeNativeIntegrationBase
assertEq(recoveryRequest.executeAfter, 0);
assertEq(recoveryRequest.executeBefore, 0);
assertEq(recoveryRequest.currentWeight, 0);
assertEq(recoveryRequest.recoveryDataHash, bytes32(0));

vm.prank(safeAddress);
bool isOwner = Safe(payable(safeAddress)).isOwner(newOwner);
Expand Down

0 comments on commit 1e7da8c

Please sign in to comment.