Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/modulekit to packages #77

Merged
merged 8 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/ISSUE_TEMPLATE/Safe7579_issue_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: Safe7579 Issue Template
about: Use this template to report a bug in the Safe7579 module
title: "[Safe7579]: [TITLE OF THE ISSUE]"
labels: safe7579, modulekit
---
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ out/
/broadcast/*/31337/
/broadcast/**/dry-run/

gas_calculations/*.json
packages/modulekit/gas_calculations/*.json

# Docs
docs/
Expand Down
4 changes: 4 additions & 0 deletions accounts/safe7579/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
},
"devDependencies": {
"@rhinestone/modulekit": "workspace:*",
"@rhinestone/sessionkeymanager": "workspace:*",
"@safe-global/safe-contracts": "^1.4.1",
"@openzeppelin/contracts": "5.0.1",
"@ERC4337/account-abstraction": "github:kopy-kat/account-abstraction#develop",
"@ERC4337/account-abstraction-v0.6": "github:eth-infinitism/account-abstraction#v0.6.0",
"erc4337-validation": "github:rhinestonewtf/erc4337-validation",
"@prb/math": "^4.0.2",
"forge-std": "github:foundry-rs/forge-std",
"ds-test": "github:dapphub/ds-test",
"erc7579": "github:erc7579/erc7579-implementation",
Expand Down
4 changes: 4 additions & 0 deletions accounts/safe7579/remappings.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
ds-test/=node_modules/ds-test/src/
forge-std/=node_modules/forge-std/src/
account-abstraction/=node_modules/@ERC4337/account-abstraction/contracts/
account-abstraction-v0.6/=node_modules/@ERC4337/account-abstraction-v0.6/contracts/
erc7579/=node_modules/erc7579/src/
sentinellist/=node_modules/sentinellist/src/
solmate/=node_modules/solmate/src/
Expand All @@ -9,3 +10,6 @@ solarray/=node_modules/solarray/src/
@rhinestone/=node_modules/@rhinestone/
@safe-global/=node_modules/@safe-global/
@ERC4337/=node_modules/@ERC4337/
@openzeppelin/=node_modules/@openzeppelin/
@prb/math/=node_modules/@prb/math/
erc4337-validation/=node_modules/erc4337-validation/src/
49 changes: 0 additions & 49 deletions accounts/safe7579/src/Account.sol

This file was deleted.

115 changes: 83 additions & 32 deletions accounts/safe7579/src/SafeERC7579.sol
Original file line number Diff line number Diff line change
@@ -1,34 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;

import "erc7579/interfaces/IERC7579Account.sol";
import "erc7579/interfaces/IMSA.sol";
import "erc7579/lib/ModeLib.sol";
import "erc7579/lib/ExecutionLib.sol";
import "erc7579/interfaces/IERC7579Module.sol";
import "./AccessControl.sol";
import "./HookManager.sol";
import "./ExecutionHelper.sol";
import "./ModuleManager.sol";
import "./interfaces/ISafeOp.sol";
import { UserOperationLib } from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol";
import { IERC7579Account, Execution } from "erc7579/interfaces/IERC7579Account.sol";
import { IMSA } from "erc7579/interfaces/IMSA.sol";
import {
CallType, ModeCode, ModeLib, CALLTYPE_SINGLE, CALLTYPE_BATCH
} from "erc7579/lib/ModeLib.sol";
import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol";
import {
IValidator,
MODULE_TYPE_VALIDATOR,
MODULE_TYPE_HOOK,
MODULE_TYPE_EXECUTOR,
MODULE_TYPE_FALLBACK
} from "erc7579/interfaces/IERC7579Module.sol";
import { AccessControl } from "./core/AccessControl.sol";
import { HookManager } from "./core/HookManager.sol";
import { ISafeOp, SAFE_OP_TYPEHASH } from "./interfaces/ISafeOp.sol";
import { ISafe } from "./interfaces/ISafe.sol";
import {
PackedUserOperation,
UserOperationLib
} from "@ERC4337/account-abstraction/contracts/core/UserOperationLib.sol";
import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core/Helpers.sol";

contract SafeERC7579 is
ISafeOp,
IERC7579Account,
AccessControl,
ExecutionHelper,
IMSA,
HookManager
{
import "forge-std/console2.sol";

/**
* @title ERC7579 Adapter for Safe accounts.
* By using Safe's Fallback and Execution modules,
* this contract creates full ERC7579 compliance to Safe accounts
* @author zeroknots.eth | rhinestone.wtf
*/
contract SafeERC7579 is ISafeOp, IERC7579Account, AccessControl, IMSA, HookManager {
using UserOperationLib for PackedUserOperation;
using ModeLib for ModeCode;
using ExecutionLib for bytes;

error Unsupported();

bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH =
0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;

/**
* @inheritdoc IERC7579Account
*/
function execute(
ModeCode mode,
bytes calldata executionCalldata
Expand All @@ -53,6 +69,9 @@ contract SafeERC7579 is
}
}

/**
* @inheritdoc IERC7579Account
*/
function executeFromExecutor(
ModeCode mode,
bytes calldata executionCalldata
Expand All @@ -79,13 +98,21 @@ contract SafeERC7579 is
}
}

/**
* @inheritdoc IERC7579Account
*/
function executeUserOp(PackedUserOperation calldata userOp)
external
payable
override
onlyEntryPointOrSelf
{ }
{
revert Unsupported();
}

/**
* @inheritdoc IERC7579Account
*/
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
Expand All @@ -110,9 +137,12 @@ contract SafeERC7579 is

// pay prefund
if (missingAccountFunds != 0) {
ISafe(userOp.getSender()).execTransactionFromModule(
entryPoint(), missingAccountFunds, "", 0
);
_execute({
safe: userOp.getSender(),
target: entryPoint(),
value: missingAccountFunds,
callData: ""
});
}
}

Expand Down Expand Up @@ -142,8 +172,14 @@ contract SafeERC7579 is
}
}

/**
* @inheritdoc IERC7579Account
*/
function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4) { }

/**
* @inheritdoc IERC7579Account
*/
function installModule(
uint256 moduleType,
address module,
Expand All @@ -162,6 +198,9 @@ contract SafeERC7579 is
emit ModuleInstalled(moduleType, module);
}

/**
* @inheritdoc IERC7579Account
*/
function uninstallModule(
uint256 moduleType,
address module,
Expand All @@ -180,20 +219,29 @@ contract SafeERC7579 is
emit ModuleUninstalled(moduleType, module);
}

/**
* @inheritdoc IERC7579Account
*/
function supportsAccountMode(ModeCode encodedMode) external pure override returns (bool) {
CallType callType = encodedMode.getCallType();
if (callType == CALLTYPE_BATCH) return true;
else if (callType == CALLTYPE_SINGLE) return true;
else return false;
}

/**
* @inheritdoc IERC7579Account
*/
function supportsModule(uint256 moduleTypeId) external pure override returns (bool) {
if (moduleTypeId == MODULE_TYPE_VALIDATOR) return true;
else if (moduleTypeId == MODULE_TYPE_EXECUTOR) return true;
else if (moduleTypeId == MODULE_TYPE_FALLBACK) return true;
else return false;
}

/**
* @inheritdoc IERC7579Account
*/
function isModuleInstalled(
uint256 moduleType,
address module,
Expand All @@ -211,8 +259,11 @@ contract SafeERC7579 is
else return false;
}

/**
* @inheritdoc IERC7579Account
*/
function accountId() external pure override returns (string memory accountImplementationId) {
return "safe-erc7579.v0.0.1";
return "safe-erc7579.v0.0.0";
}

/**
Expand Down Expand Up @@ -293,20 +344,20 @@ contract SafeERC7579 is
}
}

/**
* Domain Separator for EIP-712.
*/
function domainSeparator() public view returns (bytes32) {
return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, this));
}

function initializeAccount(bytes calldata data) external payable {
_initModuleManager();
(address[] memory validators, address[] memory executors) =
abi.decode(data, (address[], address[]));
for (uint256 i = 0; i < validators.length; i++) {
_installValidator(validators[i], data);
}

for (uint256 i = 0; i < executors.length; i++) {
_installExecutor(executors[i], data);
}
(address bootstrap, bytes memory bootstrapCall) = abi.decode(data, (address, bytes));
console2.log("bootstrap: ", bootstrap);

(bool success,) = bootstrap.delegatecall(bootstrapCall);
if (!success) revert AccountInitializationFailed();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,42 @@
pragma solidity >=0.8.0 <0.9.0;

import { Execution } from "erc7579/interfaces/IERC7579Account.sol";
import "./interfaces/ISafe.sol";
import "forge-std/console2.sol";
import "../interfaces/ISafe.sol";

/**
* @title Helper contract to execute transactions from a safe
* All functions implemented in this contract check,
* that the transaction was successful
* @author zeroknots.eth
*/
abstract contract ExecutionHelper {
error ExecutionFailed();

contract ExecutionHelper {
function _execute(
address safe,
address target,
uint256 value,
bytes calldata callData
bytes memory callData
)
internal
{
bool success = ISafe(safe).execTransactionFromModule(target, value, callData, 0);
require(success, "Execution failed");
if (!success) revert ExecutionFailed();
}

function _executeReturnData(
address safe,
address target,
uint256 value,
bytes calldata callData
bytes memory callData
)
internal
returns (bytes memory returnData)
{
bool success;
(success, returnData) =
ISafe(safe).execTransactionFromModuleReturnData(target, value, callData, 0);
require(success, "Execution failed");
if (!success) revert ExecutionFailed();
}

function _execute(address safe, Execution[] calldata executions) internal {
Expand Down
Loading
Loading