Skip to content

Commit

Permalink
Merge pull request #128 from davidinsuomi/develop
Browse files Browse the repository at this point in the history
using soulwallet-core repo
  • Loading branch information
davidinsuomi committed Jan 4, 2024
2 parents d0895e0 + 4f2a2f5 commit b448bc4
Show file tree
Hide file tree
Showing 1,039 changed files with 151,934 additions and 8,116 deletions.
37 changes: 28 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
cache
artifacts
node_modules
.env
coverage
# Compiler and build files
cache/
artifacts/
out/
compiler_config.json

# Node modules
node_modules/

# Coverage files
coverage/
coverage.json

# Environment files
.env
.env*

# MacOS file system
.DS_Store
compiler_config.json
out
lib
.deps

# Development broadcast logs
broadcast/
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/
broadcast/*

# Documentation
docs/
.vscode/
lcov.info
32 changes: 14 additions & 18 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
branch = chore/v1.5.6

[submodule "lib/account-abstraction"]
path = lib/account-abstraction
url = https://github.com/SoulWallet/account-abstraction
branch = v0.6.0-with-openzeppelin-v5

[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/Openzeppelin/openzeppelin-contracts
branch = release-v5.0

[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
branch = release-v5.0

[submodule "lib/solmate"]
path = lib/solmate
url = https://github.com/transmissions11/solmate

[submodule "lib/nitro-contracts"]
path = lib/nitro-contracts
url = https://github.com/OffchainLabs/nitro-contracts

[submodule "lib/solenv"]
path = lib/solenv
url = https://github.com/memester-xyz/solenv
[submodule "lib/SoulWalletCore"]
path = lib/SoulWalletCore
url = https://github.com/SoulWallet/SoulWalletCore
[submodule "lib/solady"]
path = lib/solady
url = https://github.com/vectorized/solady
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/Openzeppelin/openzeppelin-contracts
branch = release-v5.0
[submodule "lib/account-abstraction"]
path = lib/account-abstraction
url = https://github.com/SoulWallet/account-abstraction
branch = v0.6.0-with-openzeppelin-v5
174 changes: 99 additions & 75 deletions contracts/SoulWallet.sol
Original file line number Diff line number Diff line change
@@ -1,118 +1,142 @@
// SPDX-License-Identifier: GPL-3.0
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@account-abstraction/contracts/core/BaseAccount.sol";
import "./interfaces/ISoulWallet.sol";
import "./base/EntryPointManager.sol";
import "./base/ExecutionManager.sol";
import "./base/PluginManager.sol";
import "./base/ModuleManager.sol";
import "./base/OwnerManager.sol";
import "./helper/SignatureValidator.sol";
import "./handler/ERC1271Handler.sol";
import "./base/FallbackManager.sol";
import "./base/UpgradeManager.sol";
import "./base/ValidatorManager.sol";

/// @title SoulWallet
/// @author SoulWallet team
/// @notice logic contract of SoulWallet
/// @dev Draft contract - may be subject to changes
import {IAccount, UserOperation} from "@soulwallet-core/contracts/interface/IAccount.sol";
import {EntryPointManager} from "@soulwallet-core/contracts/base/EntryPointManager.sol";
import {FallbackManager} from "@soulwallet-core/contracts/base/FallbackManager.sol";
import {StandardExecutor} from "@soulwallet-core/contracts/base/StandardExecutor.sol";
import {ValidatorManager} from "@soulwallet-core/contracts/base/ValidatorManager.sol";
import {SignatureDecoder} from "@soulwallet-core/contracts/utils/SignatureDecoder.sol";
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {Errors} from "./libraries/Errors.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "./abstract/ERC1271Handler.sol";
import {SoulWalletOwnerManager} from "./abstract/SoulWalletOwnerManager.sol";
import {SoulWalletModuleManager} from "./abstract/SoulWalletModuleManager.sol";
import {SoulWalletHookManager} from "./abstract/SoulWalletHookManager.sol";
import {SoulWalletUpgradeManager} from "./abstract/SoulWalletUpgradeManager.sol";

contract SoulWallet is
Initializable,
ISoulWallet,
BaseAccount,
IAccount,
IERC1271,
EntryPointManager,
OwnerManager,
SignatureValidator,
PluginManager,
ModuleManager,
UpgradeManager,
ExecutionManager,
SoulWalletOwnerManager,
SoulWalletModuleManager,
SoulWalletHookManager,
StandardExecutor,
ValidatorManager,
FallbackManager,
ERC1271Handler,
ValidatorManager
SoulWalletUpgradeManager,
ERC1271Handler
{
/// @notice Creates a new SoulWallet instance
/// @param _EntryPoint Address of the entry point
/// @param _validator Address of the validator
constructor(IEntryPoint _EntryPoint, IValidator _validator)
EntryPointManager(_EntryPoint)
ValidatorManager(_validator)
{
address internal immutable _DEFAULT_VALIDATOR;

constructor(address _entryPoint, address defaultValidator) EntryPointManager(_entryPoint) {
_DEFAULT_VALIDATOR = defaultValidator;
_disableInitializers();
}

/// @notice Initializes the SoulWallet with given parameters
/// @param owners List of owner addresses (passkey public key hash or eoa address)
/// @param defalutCallbackHandler Default callback handler address
/// @param modules List of module data
/// @param plugins List of plugin data
function initialize(
bytes32[] calldata owners,
address defalutCallbackHandler,
bytes[] calldata modules,
bytes[] calldata plugins
bytes[] calldata hooks
) external initializer {
_addOwners(owners);
_setFallbackHandler(defalutCallbackHandler);
_installValidator(_DEFAULT_VALIDATOR, hex"");
for (uint256 i = 0; i < modules.length;) {
_addModule(modules[i]);
unchecked {
i++;
}
}
for (uint256 i = 0; i < plugins.length;) {
_addPlugin(plugins[i]);
for (uint256 i = 0; i < hooks.length;) {
_installHook(hooks[i]);
unchecked {
i++;
}
}
}

/// @notice Gets the address of the entry point
/// @return IEntryPoint Address of the entry point
function entryPoint() public view override(BaseAccount) returns (IEntryPoint) {
return EntryPointManager._entryPoint();
function _uninstallValidator(address validator) internal override {
require(validator != _DEFAULT_VALIDATOR, "can't uninstall default validator");
super._uninstallValidator(validator);
}

function isValidSignature(bytes32 _hash, bytes calldata signature)
public
view
override
returns (bytes4 magicValue)
{
bytes32 datahash = _encodeRawHash(_hash);

(address validator, bytes calldata validatorSignature, bytes calldata hookSignature) =
SignatureDecoder.signatureSplit(signature);
_preIsValidSignatureHook(datahash, hookSignature);
return _isValidSignature(datahash, validator, validatorSignature);
}

/// @notice Validates the user's signature
/// @param userOp User operation details
/// @param userOpHash Hash of the user operation
/// @return validationData Data related to validation process
function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash)
function _decodeSignature(bytes calldata signature)
internal
pure
virtual
returns (address validator, bytes calldata validatorSignature, bytes calldata hookSignature)
{
return SignatureDecoder.signatureSplit(signature);
}

function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
public
payable
virtual
override
returns (uint256 validationData)
{
bool sigValid;
bytes calldata guardHookInputData;
(validationData, sigValid, guardHookInputData) = _isValidUserOp(userOpHash, userOp.signature);

/*
Why using the current "non-gas-optimized" approach instead of using
`sigValid = sigValid && guardHook(userOp, userOpHash, guardHookInputData);` :
When data is executed on the blockchain, if `sigValid = true`, the gas cost remains consistent.
However, the benefits of using this approach are quite apparent:
By using "semi-valid" signatures off-chain to estimate gas fee (sigValid will always be false),
the estimated fee can include a portion of the execution cost of `guardHook`.
_onlyEntryPoint();

assembly ("memory-safe") {
if missingAccountFunds {
// ignore failure (its EntryPoint's job to verify, not account.)
pop(call(gas(), caller(), missingAccountFunds, 0x00, 0x00, 0x00, 0x00))
}
}
(address validator, bytes calldata validatorSignature, bytes calldata hookSignature) =
_decodeSignature(userOp.signature);

/*
Warning!!!
This function uses `return` to terminate the execution of the entire contract.
If any `Hook` fails, this function will stop the contract's execution and
return `SIG_VALIDATION_FAILED`, skipping all the subsequent unexecuted code.
*/
_preUserOpValidationHook(userOp, userOpHash, missingAccountFunds, hookSignature);

/*
When any hook execution fails, this line will not be executed.
*/
bool guardHookResult = guardHook(userOp, userOpHash, guardHookInputData);
return _validateUserOp(userOp, userOpHash, validator, validatorSignature);
}

/**
* Only authorized modules can manage hooks and modules.
*/
function pluginManagementAccess() internal view override {
_onlyModule();
}

// equivalence code: `(sigFailed ? 1 : 0) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48))`
// validUntil and validAfter is already packed in signatureData.validationData,
// and aggregator is address(0), so we just need to add sigFailed flag.
validationData = validationData | ((sigValid && guardHookResult) ? 0 : SIG_VALIDATION_FAILED);
/**
* Only authorized modules can manage validators
*/
function validatorManagementAccess() internal view override {
_onlyModule();
}

/// @notice Upgrades the contract to a new implementation
/// @param newImplementation Address of the new implementation
/// @dev Can only be called from an external module for security reasons
function upgradeTo(address newImplementation) external onlyModule {
UpgradeManager._upgradeTo(newImplementation);
function upgradeTo(address newImplementation) external override {
_onlyModule();
_upgradeTo(newImplementation);
}

/// @notice Handles the upgrade from an old implementation
Expand Down
63 changes: 63 additions & 0 deletions contracts/abstract/DefaultCallbackHandler.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";

contract DefaultCallbackHandler is IERC721Receiver, IERC1155Receiver {
bytes4 private constant _ERC721_RECEIVED =
IERC721Receiver.onERC721Received.selector;
bytes4 private constant _ERC1155_RECEIVED =
IERC1155Receiver.onERC1155Received.selector;
bytes4 private constant _ERC1155_BATCH_RECEIVED =
IERC1155Receiver.onERC1155BatchReceived.selector;

bytes4 private constant _INTERFACE_ID_ERC721_RECEIVER =
type(IERC721Receiver).interfaceId;
bytes4 private constant _INTERFACE_ID_ERC1155_RECEIVER =
type(IERC1155Receiver).interfaceId;
bytes4 private constant _INTERFACE_ID_ERC165 = type(IERC165).interfaceId;

function onERC721Received(
address,
address,
uint256,
bytes calldata
) external pure override returns (bytes4) {
return _ERC721_RECEIVED;
}

function onERC1155Received(
address,
address,
uint256,
uint256,
bytes calldata
) external pure override returns (bytes4) {
return _ERC1155_RECEIVED;
}

function onERC1155BatchReceived(
address,
address,
uint256[] calldata,
uint256[] calldata,
bytes calldata
) external pure override returns (bytes4) {
return _ERC1155_BATCH_RECEIVED;
}

function supportsInterface(
bytes4 interfaceId
) external view virtual override returns (bool) {
return
interfaceId == _INTERFACE_ID_ERC721_RECEIVER ||
interfaceId == _INTERFACE_ID_ERC1155_RECEIVER ||
interfaceId == _INTERFACE_ID_ERC165;
}

receive() external payable {}

fallback() external payable {}
}
Loading

0 comments on commit b448bc4

Please sign in to comment.