Skip to content

Commit

Permalink
integration test wip
Browse files Browse the repository at this point in the history
  • Loading branch information
mmv08 committed Oct 11, 2023
1 parent e966cc2 commit 0bff8d4
Show file tree
Hide file tree
Showing 5 changed files with 643 additions and 1,452 deletions.
10 changes: 10 additions & 0 deletions contracts/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,13 @@ NODE_URL=""
MNEMONIC=""
INFURA_KEY=""
ETHERSCAN_API_KEY=""

# (Optional) variables for the ERC4337 integration test
ERC4337_TEST_BUNDLER_URL=""
ERC4337_TEST_NODE_URL=""
ERC4337_TEST_SAFE_FACTORY_ADDRESS=""
ERC4337_TEST_SINGLETON_ADDRESS=""
ERC4337_TEST_MNEMONIC=""
# The address derived from the mnemonic must be an owner of the registry and the protocol manager
ERC4337_TEST_SAFE_CORE_PROTOCOL_MANAGER_ADDRESS=""
ERC4337_TEST_SAFE_CORE_PROTOCOL_REGISTRY=""
28 changes: 20 additions & 8 deletions contracts/contracts/ERC4337Plugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import {ISafeProtocolPlugin, ISafeProtocolFunctionHandler} from "@safe-global/sa
import {ISafeProtocolManager} from "@safe-global/safe-core-protocol/contracts/interfaces/Manager.sol";
import {SafeTransaction, SafeRootAccess, SafeProtocolAction} from "@safe-global/safe-core-protocol/contracts/DataTypes.sol";
import {MODULE_TYPE_PLUGIN} from "@safe-global/safe-core-protocol/contracts/common/Constants.sol";
import {BasePlugin, BasePluginWithEventMetadata, PluginMetadata, MetadataProviderType} from "./Base.sol";

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {BasePlugin, BasePluginWithEventMetadata, PluginMetadata, MetadataProviderType} from "./Base.sol";

interface ISafe {
function isOwner(address owner) external view returns (bool);
Expand All @@ -34,7 +33,11 @@ interface ISafe {

function setFunctionHandler(bytes4 selector, address functionHandler) external;

function checkSignatures(bytes32 dataHash, bytes memory, bytes memory signatures) external;
function checkSignatures(bytes32 dataHash, bytes memory, bytes memory signatures) external view;
}

interface IEntryPoint {
function getUserOpHash(UserOperation calldata userOp) external view returns (bytes32);
}

struct UserOperation {
Expand All @@ -61,7 +64,10 @@ contract ERC4337Plugin is ISafeProtocolFunctionHandler, BasePluginWithEventMetad
address public immutable PLUGIN_ADDRESS;
ISafeProtocolManager public immutable SAFE_PROTOCOL_MANAGER;
address payable public immutable ENTRY_POINT;
uint256 public constant SIGNATURE_VALID = 0;
uint256 internal constant SIGNATURE_VALID = 0;
// value in case of signature failure, with no time-range.
// equivalent to _packValidationData(true,0,0);
uint256 internal constant SIGNATURE_VALIDATION_FAILED = 1;

constructor(
ISafeProtocolManager safeCoreProtocolManager,
Expand All @@ -76,10 +82,10 @@ contract ERC4337Plugin is ISafeProtocolFunctionHandler, BasePluginWithEventMetad
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData) {
) external returns (uint256 validationResult) {
require(msg.sender == address(PLUGIN_ADDRESS), "Only plugin");

ISafe(payable(userOp.sender)).checkSignatures(userOpHash, "", userOp.signature);
validationResult = validateSignature(userOp, userOpHash);

if (missingAccountFunds != 0) {
SafeProtocolAction[] memory actions = new SafeProtocolAction[](1);
Expand All @@ -89,8 +95,6 @@ contract ERC4337Plugin is ISafeProtocolFunctionHandler, BasePluginWithEventMetad
SafeTransaction({actions: actions, nonce: 0, metadataHash: userOpHash})
);
}

return SIGNATURE_VALID;
}

function execTransaction(address safe, address payable to, uint256 value, bytes calldata data) external {
Expand All @@ -102,6 +106,14 @@ contract ERC4337Plugin is ISafeProtocolFunctionHandler, BasePluginWithEventMetad
SAFE_PROTOCOL_MANAGER.executeTransaction(safe, SafeTransaction({actions: actions, nonce: 0, metadataHash: bytes32(0)}));
}

function validateSignature(UserOperation calldata userOp, bytes32 userOpHash) internal view returns (uint256 validationResult) {
try ISafe(payable(userOp.sender)).checkSignatures(userOpHash, "", userOp.signature) {
return SIGNATURE_VALID;
} catch {
return SIGNATURE_VALIDATION_FAILED;
}
}

function handle(address, address sender, uint256, bytes calldata data) external returns (bytes memory result) {
bytes4 selector = bytes4(data[0:4]);
require(sender == ENTRY_POINT, "Only entrypoint");
Expand Down
2 changes: 1 addition & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"eslint-plugin-no-only-tests": "^3.1.0",
"eslint-plugin-prettier": "^5.0.0",
"ethers": "^6.7.1",
"hardhat": "^2.17.4",
"hardhat": "^2.18.0",
"hardhat-deploy": "^0.11.37",
"hardhat-gas-reporter": "^1.0.8",
"hardhat-typechain": "^0.3.5",
Expand Down
Loading

0 comments on commit 0bff8d4

Please sign in to comment.