Skip to content

Commit

Permalink
feat: ported over all module examples and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroknots committed Feb 19, 2024
1 parent 3901e3a commit 1326e23
Show file tree
Hide file tree
Showing 26 changed files with 4,292 additions and 0 deletions.
24 changes: 24 additions & 0 deletions create_scaffolding.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash

# Check if directory path is provided
if [ -z "$1" ]; then
echo "Usage: ./create_project.sh <directory_path>"
exit 1
fi

# Create the directory if it doesn't exist
mkdir -p $1

# Navigate to the directory
cd $1

# Download package.json using wget from a fixed URL
wget -O package.json <fixed_URL_placeholder>

# Create src and test folders
mkdir src test

# Write "modulekit/=../." into remappings.txt
echo "modulekit/=../." > remappings.txt

echo "Project scaffolding created successfully."
129 changes: 129 additions & 0 deletions examples/src/AutoSend/AutoSend.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import "@rhinestone/sessionkeymanager/src/ISessionValidationModule.sol";
import { IERC20 } from "forge-std/interfaces/IERC20.sol";
import { IERC7579Account } from "@rhinestone/modulekit/src/Accounts.sol";
import { ERC7579ExecutorBase } from "@rhinestone/modulekit/src/Modules.sol";
import { ModeLib } from "erc7579/lib/ModeLib.sol";
import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol";
import { EncodedModuleTypes, ModuleTypeLib, ModuleType } from "erc7579/lib/ModuleTypeLib.sol";

contract AutoSendSessionKey is ERC7579ExecutorBase, ISessionValidationModule {
struct ExecutorAccess {
address sessionKeySigner;
address token;
address receiver;
}

struct SpentLog {
uint128 spent;
uint128 maxAmount;
}

struct Params {
address token;
address receiver;
uint128 amount;
}

error InvalidMethod(bytes4);
error InvalidValue();
error InvalidAmount();
error InvalidTarget();
error InvalidRecipient();

mapping(address account => mapping(address token => SpentLog)) internal _log;

function encode(ExecutorAccess memory transaction) public pure returns (bytes memory) {
return abi.encode(transaction);
}

function getSpentLog(address account, address token) public view returns (SpentLog memory) {
return _log[account][token];
}

function autoSend(Params calldata params) external {
IERC7579Account smartAccount = IERC7579Account(msg.sender);

SpentLog storage log = _log[msg.sender][params.token];

uint128 newSpent = log.spent + params.amount;
if (newSpent > log.maxAmount) {
revert InvalidAmount();
}
log.spent = newSpent;

smartAccount.executeFromExecutor(
ModeLib.encodeSimpleSingle(),
ExecutionLib.encodeSingle(
params.token, 0, abi.encodeCall(IERC20.transfer, (params.receiver, params.amount))
)
);
}

function validateSessionParams(
address destinationContract,
uint256 callValue,
bytes calldata callData,
bytes calldata _sessionKeyData,
bytes calldata /*_callSpecificData*/
)
public
virtual
override
returns (address)
{
ExecutorAccess memory access = abi.decode(_sessionKeyData, (ExecutorAccess));

bytes4 targetSelector = bytes4(callData[:4]);
Params memory params = abi.decode(callData[4:], (Params));
if (targetSelector != this.autoSend.selector) {
revert InvalidMethod(targetSelector);
}

if (params.receiver != access.receiver) {
revert InvalidRecipient();
}

if (destinationContract != address(this)) {
revert InvalidTarget();
}

if (params.token != access.token) {
revert InvalidTarget();
}

if (callValue != 0) {
revert InvalidValue();
}

return access.sessionKeySigner;
}

function onInstall(bytes calldata data) external override {
(address[] memory tokens, SpentLog[] memory log) = abi.decode(data, (address[], SpentLog[]));

for (uint256 i; i < tokens.length; i++) {
_log[msg.sender][tokens[i]] = log[i];
}
}

function onUninstall(bytes calldata data) external override { }

function isModuleType(uint256 typeID) external pure override returns (bool) {
return typeID == TYPE_EXECUTOR;
}

function getModuleTypes() external view returns (EncodedModuleTypes) { }

function isInitialized(address smartAccount) external view returns (bool) { }

function name() external pure virtual returns (string memory) {
return "AutoSend";
}

function version() external pure virtual returns (string memory) {
return "0.0.1";
}
}
41 changes: 41 additions & 0 deletions examples/src/ColdStorage-SubAccount/ColdStorageExecutor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import { IERC7579Account } from "@rhinestone/modulekit/src/Accounts.sol";
import { ERC7579ExecutorBase } from "@rhinestone/modulekit/src/Modules.sol";
import { ModeLib } from "erc7579/lib/ModeLib.sol";
import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol";
import { EncodedModuleTypes, ModuleTypeLib, ModuleType } from "erc7579/lib/ModuleTypeLib.sol";

contract ColdStorageExecutor is ERC7579ExecutorBase {
error UnauthorizedAccess();

mapping(address subAccount => address owner) private _subAccountOwner;

function executeOnSubAccount(address subAccount, bytes calldata callData) external payable {
if (msg.sender != _subAccountOwner[subAccount]) {
revert UnauthorizedAccess();
}

IERC7579Account(subAccount).executeFromExecutor(ModeLib.encodeSimpleSingle(), callData);
}

function onInstall(bytes calldata data) external override {
address owner = address(bytes20(data[0:20]));
_subAccountOwner[msg.sender] = owner;
}

function onUninstall(bytes calldata) external override {
delete _subAccountOwner[msg.sender];
}

function isModuleType(uint256 typeID) external pure override returns (bool) {
return typeID == TYPE_EXECUTOR;
}

function getModuleTypes() external view returns (EncodedModuleTypes) { }

function isInitialized(address smartAccount) external view returns (bool) {
return _subAccountOwner[smartAccount] != address(0);
}
}
Loading

0 comments on commit 1326e23

Please sign in to comment.