Skip to content

Commit

Permalink
Merge pull request #37 from xWerk/fix/space-self-execution
Browse files Browse the repository at this point in the history
Allow `Space` self execution
  • Loading branch information
gabrielstoica authored Nov 29, 2024
2 parents 0ae1b90 + d55bacb commit 6f285ce
Show file tree
Hide file tree
Showing 23 changed files with 520 additions and 509 deletions.
352 changes: 0 additions & 352 deletions broadcast/DeployDeterministicCore.s.sol/84532/run-1732820030.json

This file was deleted.

352 changes: 352 additions & 0 deletions broadcast/DeployDeterministicCore.s.sol/84532/run-1732865797.json

Large diffs are not rendered by default.

244 changes: 122 additions & 122 deletions broadcast/DeployDeterministicCore.s.sol/84532/run-latest.json

Large diffs are not rendered by default.

18 changes: 10 additions & 8 deletions src/Space.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@ contract Space is ISpace, AccountCore, ERC1271, ModuleManager {
MODIFIERS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Checks whether the caller is the EntryPoint contract or the admin.
/// @notice Checks whether the caller is the {EntryPoint}, the admin or the contract itself (redirected through `execute()`)
modifier onlyAdminOrEntrypoint() virtual {
require(msg.sender == address(entryPoint()) || isAdmin(msg.sender), "Account: not admin or EntryPoint.");
if (!(msg.sender == address(entryPoint()) || isAdmin(msg.sender) || msg.sender == address(this))) {
revert Errors.CallerNotEntryPointOrAdmin();
}
_;
}

Expand Down Expand Up @@ -314,20 +316,20 @@ contract Space is ISpace, AccountCore, ERC1271, ModuleManager {
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

/// @dev Executes a low-level call on the `module` contract with the `data` data forwarding the `value` value
function _call(address module, uint256 value, bytes calldata data) internal returns (bool success) {
// Execute the call via assembly
/// @dev Executes a low-level call on the `target` contract with the `data` data forwarding the `value` value
function _call(address target, uint256 value, bytes calldata data) internal returns (bool success) {
// Execute the low-level call
bytes memory result;
(success, result) = module.call{ value: value }(data);
(success, result) = target.call{ value: value }(data);

// Revert with the same error returned by the module contract if the call failed
// Revert with the same error returned by the target contract if the call failed
if (!success) {
assembly {
revert(add(result, 0x20), mload(result))
}
} else {
// Otherwise log the execution success
emit ModuleExecutionSucceded(module, value, data);
emit ModuleExecutionSucceded(target, value, data);
}
}
}
3 changes: 3 additions & 0 deletions src/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ library Errors {
/// @notice Thrown when `msg.sender` is not the {Space} contract owner
error CallerNotSpaceOwner();

/// @notice Thrown when `msg.sender` is not the {EntryPoint} or the admin
error CallerNotEntryPointOrAdmin();

/// @notice Thrown when a native token (ETH) withdrawal fails
error NativeWithdrawFailed();

Expand Down
6 changes: 4 additions & 2 deletions test/mocks/MockBadSpace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,11 @@ contract MockBadSpace is ISpace, AccountCore, ERC1271, ModuleManager {
MODIFIERS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Checks whether the caller is the EntryPoint contract or the admin.
/// @notice Checks whether the caller is the {EntryPoint}, the admin or the contract itself (redirected through `execute()`)
modifier onlyAdminOrEntrypoint() virtual {
require(msg.sender == address(entryPoint()) || isAdmin(msg.sender), "Account: not admin or EntryPoint.");
if (!(msg.sender == address(entryPoint()) || isAdmin(msg.sender) || msg.sender == address(this))) {
revert Errors.CallerNotEntryPointOrAdmin();
}
_;
}

Expand Down
5 changes: 3 additions & 2 deletions test/unit/concrete/space/disable-module/disableModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.26;
import { Space_Unit_Concrete_Test } from "../Space.t.sol";
import { MockModule } from "../../../../mocks/MockModule.sol";
import { Events } from "../../../../utils/Events.sol";
import { Errors } from "../../../../utils/Errors.sol";

contract DisableModule_Unit_Concrete_Test is Space_Unit_Concrete_Test {
function setUp() public virtual override {
Expand All @@ -14,8 +15,8 @@ contract DisableModule_Unit_Concrete_Test is Space_Unit_Concrete_Test {
// Make Bob the caller for this test suite who is not the owner of the space
vm.startPrank({ msgSender: users.bob });

// Expect the next call to revert with the "Account: not admin or EntryPoint." error
vm.expectRevert("Account: not admin or EntryPoint.");
// Expect the next call to revert with the {CallerNotEntryPointOrAdmin} error
vm.expectRevert(Errors.CallerNotEntryPointOrAdmin.selector);

// Run the test
space.disableModule({ module: address(0x1) });
Expand Down
2 changes: 1 addition & 1 deletion test/unit/concrete/space/disable-module/disableModule.tree
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
disableModule.t.sol
├── when the caller IS NOT the space owner
│ └── it should revert with the "Account: not admin or EntryPoint." error
│ └── it should revert with the {CallerNotEntryPointOrAdmin} error
└── when the caller IS the space owner
└── given module enabled
├── it should mark the module as disabled
Expand Down
4 changes: 2 additions & 2 deletions test/unit/concrete/space/enable-module/enableModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ contract EnableModule_Unit_Concrete_Test is Space_Unit_Concrete_Test {
// Make Bob the caller for this test suite who is not the owner of the space
vm.startPrank({ msgSender: users.bob });

// Expect the next call to revert with the "Account: not admin or EntryPoint." error
vm.expectRevert("Account: not admin or EntryPoint.");
// Expect the next call to revert with the {CallerNotEntryPointOrAdmin} error
vm.expectRevert(Errors.CallerNotEntryPointOrAdmin.selector);

// Run the test
space.enableModule({ module: address(0x1) });
Expand Down
2 changes: 1 addition & 1 deletion test/unit/concrete/space/enable-module/enableModule.tree
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
enableModule.t.sol
├── when the caller IS NOT the space owner
│ └── it should revert with the "Account: not admin or EntryPoint." error
│ └── it should revert with the {CallerNotEntryPointOrAdmin} error
└── when the caller IS the space owner
├── when the module IS NOT allowlisted
│ └── it should revert with the {ModuleNotAllowlisted} error
Expand Down
4 changes: 2 additions & 2 deletions test/unit/concrete/space/execute-batch/executeBatch.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ contract ExecuteBatch_Unit_Concrete_Test is Space_Unit_Concrete_Test {
// Make Bob the caller for this test suite who is not the owner of the space
vm.startPrank({ msgSender: users.bob });

// Expect the next call to revert with the "Account: not admin or EntryPoint." error
vm.expectRevert("Account: not admin or EntryPoint.");
// Expect the next call to revert with the {CallerNotEntryPointOrAdmin} error
vm.expectRevert(Errors.CallerNotEntryPointOrAdmin.selector);

// Run the test
space.executeBatch(modules, values, data);
Expand Down
2 changes: 1 addition & 1 deletion test/unit/concrete/space/execute-batch/executeBatch.tree
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
executeBatch.t.sol
├── when the caller IS NOT the space owner
│ └── it should revert with the "Account: not admin or EntryPoint." error
│ └── it should revert with the {CallerNotEntryPointOrAdmin} error
└── when the caller IS the space owner
├── when one array have a different length than the others
│ └── it should revert with the {WrongArrayLengths} error
Expand Down
4 changes: 2 additions & 2 deletions test/unit/concrete/space/execute/execute.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ contract Execute_Unit_Concrete_Test is Space_Unit_Concrete_Test {
// Make Bob the caller for this test suite who is not the owner of the space
vm.startPrank({ msgSender: users.bob });

// Expect the next call to revert with the "Account: not admin or EntryPoint." error
vm.expectRevert("Account: not admin or EntryPoint.");
// Expect the next call to revert with the {CallerNotEntryPointOrAdmin} error
vm.expectRevert(Errors.CallerNotEntryPointOrAdmin.selector);

// Run the test
space.execute({ module: address(mockModule), value: 0, data: "" });
Expand Down
2 changes: 1 addition & 1 deletion test/unit/concrete/space/execute/execute.tree
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
execute.t.sol
├── when the caller IS NOT the space owner
│ └── it should revert with the "Account: not admin or EntryPoint." error
│ └── it should revert with the {CallerNotEntryPointOrAdmin} error
└── when the caller IS the space owner
├── when the module IS NOT enabled
│ └── it should revert with the {ModuleNotEnabled} error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ contract WithdrawERC1155_Unit_Concrete_Test is Space_Unit_Concrete_Test {
// Make Bob the caller for this test suite who is not the owner of the space
vm.startPrank({ msgSender: users.bob });

// Expect the next call to revert with the "Account: not admin or EntryPoint." error
vm.expectRevert("Account: not admin or EntryPoint.");
// Expect the next call to revert with the {CallerNotEntryPointOrAdmin} error
vm.expectRevert(Errors.CallerNotEntryPointOrAdmin.selector);

// Run the test
space.withdrawERC1155({ to: users.bob, collection: IERC1155(address(0x0)), ids: ids, amounts: amounts });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
withdrawERC1155.t.sol
├── when the caller IS NOT the space owner
│ └── it should revert with the "Account: not admin or EntryPoint." error
│ └── it should revert with the {CallerNotEntryPointOrAdmin} error
└── when the caller IS the space owner
├── when there the ERC-1155 balance IS NOT sufficient
│ └── it should revert with the {ERC1155InsufficientBalance} error
Expand Down
4 changes: 2 additions & 2 deletions test/unit/concrete/space/withdraw-erc20/withdrawERC20.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ contract WithdrawERC20_Unit_Concrete_Test is Space_Unit_Concrete_Test {
// Make Bob the caller for this test suite who is not the owner of the space
vm.startPrank({ msgSender: users.bob });

// Expect the next call to revert with the "Account: not admin or EntryPoint." error
vm.expectRevert("Account: not admin or EntryPoint.");
// Expect the next call to revert with the {CallerNotEntryPointOrAdmin} error
vm.expectRevert(Errors.CallerNotEntryPointOrAdmin.selector);

// Run the test
space.withdrawERC20({ to: users.bob, asset: IERC20(address(0x0)), amount: 100e6 });
Expand Down
2 changes: 1 addition & 1 deletion test/unit/concrete/space/withdraw-erc20/withdrawERC20.tree
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
withdrawERC20.t.sol
├── when the caller IS NOT the space owner
│ └── it should revert with the "Account: not admin or EntryPoint." error
│ └── it should revert with the {CallerNotEntryPointOrAdmin} error
└── when the caller IS the space owner
├── when space ERC-20 token balance IS INSUFFICIENT to support the withdrawal
│ └── it should revert with the {InsufficientERC20ToWithdraw} error
Expand Down
4 changes: 2 additions & 2 deletions test/unit/concrete/space/withdraw-erc721/withdrawERC721.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ contract WithdrawERC721_Unit_Concrete_Test is Space_Unit_Concrete_Test {
// Make Bob the caller for this test suite who is not the owner of the space
vm.startPrank({ msgSender: users.bob });

// Expect the next call to revert with the "Account: not admin or EntryPoint." error
vm.expectRevert("Account: not admin or EntryPoint.");
// Expect the next call to revert with the {CallerNotEntryPointOrAdmin} error
vm.expectRevert(Errors.CallerNotEntryPointOrAdmin.selector);

// Run the test
space.withdrawERC721({ to: users.bob, collection: IERC721(address(0x0)), tokenId: 1 });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
withdrawERC721.t.sol
├── when the caller IS NOT the space owner
│ └── it should revert with the "Account: not admin or EntryPoint." error
│ └── it should revert with the {CallerNotEntryPointOrAdmin} error
└── when the caller IS the space owner
├── when there is no existing ERC-721 token to be transferred
│ └── it should revert with the {ERC721WithdrawalFailed} error
Expand Down
4 changes: 2 additions & 2 deletions test/unit/concrete/space/withdraw-native/withdrawNative.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ contract WithdrawNative_Unit_Concrete_Test is Space_Unit_Concrete_Test {
// Make Bob the caller for this test suite who is not the owner of the space
vm.startPrank({ msgSender: users.bob });

// Expect the next call to revert with the "Account: not admin or EntryPoint." error
vm.expectRevert("Account: not admin or EntryPoint.");
// Expect the next call to revert with the {CallerNotEntryPointOrAdmin} error
vm.expectRevert(Errors.CallerNotEntryPointOrAdmin.selector);

// Run the test
space.withdrawNative({ to: users.bob, amount: 2 ether });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
withdrawNative.t.sol
├── when the caller IS NOT the space owner
│ └── it should revert with the "Account: not admin or EntryPoint." error
│ └── it should revert with the {CallerNotEntryPointOrAdmin} error
└── when the caller IS the space owner
├── when space native token (ETH) balance IS INSUFFICIENT to support the withdrawal
│ └── it should revert with the {InsufficientERC20ToWithdraw} error
Expand Down
5 changes: 4 additions & 1 deletion test/utils/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ library Errors {
error CallerNotStationOwner();

/*//////////////////////////////////////////////////////////////////////////
CONTAINER
SPACE
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when `msg.sender` is not the {Space} contract owner
error CallerNotSpaceOwner();

/// @notice Thrown when `msg.sender` is not the {EntryPoint} or the admin
error CallerNotEntryPointOrAdmin();

/// @notice Thrown when a native token (ETH) withdrawal fails
error NativeWithdrawFailed();

Expand Down

0 comments on commit 6f285ce

Please sign in to comment.