Skip to content

Commit

Permalink
feat(nexus): add NexusHelpers
Browse files Browse the repository at this point in the history
  • Loading branch information
highskore committed Oct 31, 2024
1 parent 46f6146 commit 9272f1a
Show file tree
Hide file tree
Showing 2 changed files with 265 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/test/RhinestoneModuleKit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { HelperBase } from "./helpers/HelperBase.sol";
import { ERC7579Helpers } from "./helpers/ERC7579Helpers.sol";
import { SafeHelpers } from "./helpers/SafeHelpers.sol";
import { KernelHelpers } from "./helpers/KernelHelpers.sol";
import { NexusHelpers } from "./helpers/NexusHelpers.sol";
import { Auxiliary, AuxiliaryFactory } from "./Auxiliary.sol";
import { PackedUserOperation, IStakeManager, IEntryPoint } from "../external/ERC4337.sol";
import { ENTRYPOINT_ADDR } from "./predeploy/EntryPoint.sol";
Expand Down Expand Up @@ -248,7 +249,7 @@ contract RhinestoneModuleKit is AuxiliaryFactory {
writeHelper(address(new ERC7579Helpers()), DEFAULT);
writeHelper(address(new SafeHelpers()), SAFE);
writeHelper(address(new KernelHelpers()), KERNEL);
writeHelper(address(new ERC7579Helpers()), NEXUS);
writeHelper(address(new NexusHelpers()), NEXUS);
writeHelper(address(new ERC7579Helpers()), CUSTOM);

// Initialize factories
Expand Down
263 changes: 263 additions & 0 deletions src/test/helpers/NexusHelpers.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import { PackedUserOperation } from "../../external/ERC4337.sol";
import { AccountInstance } from "../RhinestoneModuleKit.sol";
import { HelperBase } from "./HelperBase.sol";
import { IAccountModulesPaginated } from "./interfaces/IAccountModulesPaginated.sol";
import { IERC1271, EIP1271_MAGIC_VALUE } from "src/Interfaces.sol";
import { CallType } from "src/external/ERC7579.sol";

contract NexusHelpers is HelperBase {
/*//////////////////////////////////////////////////////////////////////////
USER OP
//////////////////////////////////////////////////////////////////////////*/

function execUserOp(
AccountInstance memory instance,
bytes memory callData,
address txValidator
)
public
override
returns (PackedUserOperation memory userOp, bytes32 userOpHash)
{
bytes memory initCode;
bool notDeployedYet = instance.account.code.length == 0;
if (notDeployedYet) {
initCode = instance.initCode;
}

userOp = PackedUserOperation({
sender: instance.account,
nonce: getNonce(instance, 0x00, txValidator),
initCode: initCode,
callData: callData,
accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))),
preVerificationGas: 2e6,
gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))),
paymasterAndData: bytes(""),
signature: bytes("")
});

userOpHash = instance.aux.entrypoint.getUserOpHash(userOp);
}

function configModuleUserOp(
AccountInstance memory instance,
uint256 moduleType,
address module,
bytes memory initData,
bool isInstall,
address txValidator
)
public
override
returns (PackedUserOperation memory userOp, bytes32 userOpHash)
{
bytes memory initCode;
if (instance.account.code.length == 0) {
initCode = instance.initCode;
}
bytes memory callData;
if (isInstall) {
initData = getInstallModuleData({
instance: instance,
moduleType: moduleType,
module: module,
initData: initData
});
callData = getInstallModuleCallData({
instance: instance,
moduleType: moduleType,
module: module,
initData: initData
});
} else {
initData = getUninstallModuleData({
instance: instance,
moduleType: moduleType,
module: module,
initData: initData
});
callData = getUninstallModuleCallData({
instance: instance,
moduleType: moduleType,
module: module,
initData: initData
});
}

userOp = PackedUserOperation({
sender: instance.account,
nonce: getNonce(instance, 0x00, txValidator),
initCode: initCode,
callData: callData,
accountGasLimits: bytes32(abi.encodePacked(uint128(2e6), uint128(2e6))),
preVerificationGas: 2e6,
gasFees: bytes32(abi.encodePacked(uint128(1), uint128(1))),
paymasterAndData: bytes(""),
signature: bytes("")
});

userOpHash = instance.aux.entrypoint.getUserOpHash(userOp);
}

function getNonce(
AccountInstance memory instance,
bytes1 vMode,
address validator
)
internal
view
returns (uint256 nonce)
{
uint192 key = makeNonceKey(vMode, validator);
nonce = instance.aux.entrypoint.getNonce(address(instance.account), key);
}

function makeNonceKey(bytes1 vMode, address validator) internal pure returns (uint192 key) {
assembly {
key := or(shr(88, vMode), validator)
}
}

/*//////////////////////////////////////////////////////////////////////////
MODULE CONFIG
//////////////////////////////////////////////////////////////////////////*/

/**
* get callData to uninstall validator on ERC7579 Account
*/
function getUninstallValidatorData(
AccountInstance memory instance,
address module,
bytes memory initData
)
public
view
virtual
override
returns (bytes memory data)
{
// get previous validator in sentinel list
address previous;

(address[] memory array,) =
IAccountModulesPaginated(instance.account).getValidatorsPaginated(address(0x1), 100);

if (array.length == 1) {
previous = address(0x1);
} else if (array[0] == module) {
previous = address(0x1);
} else {
for (uint256 i = 1; i < array.length; i++) {
if (array[i] == module) previous = array[i - 1];
}
}
data = abi.encode(previous, initData);
}

/**
* get callData to uninstall executor on ERC7579 Account
*/
function getUninstallExecutorData(
AccountInstance memory instance,
address module,
bytes memory initData
)
public
view
virtual
override
returns (bytes memory data)
{
// get previous executor in sentinel list
address previous;

(address[] memory array,) =
IAccountModulesPaginated(instance.account).getExecutorsPaginated(address(0x1), 100);

if (array.length == 1) {
previous = address(0x1);
} else if (array[0] == module) {
previous = address(0x1);
} else {
for (uint256 i = 1; i < array.length; i++) {
if (array[i] == module) previous = array[i - 1];
}
}
data = abi.encode(previous, initData);
}

/**
* get callData to install fallback on ERC7579 Account
*/
function getInstallFallbackData(
AccountInstance memory instance,
address module,
bytes memory initData
)
public
pure
virtual
override
returns (bytes memory data)
{
(bytes4 selector, CallType callType, bytes memory _initData) =
abi.decode(initData, (bytes4, CallType, bytes));
data = abi.encodePacked(selector, callType, _initData);
}

/**
* get callData to uninstall fallback on ERC7579 Account
*/
function getUninstallFallbackData(
AccountInstance memory instance,
address module,
bytes memory initData
)
public
pure
virtual
override
returns (bytes memory data)
{
(bytes4 selector,, bytes memory _initData) = abi.decode(initData, (bytes4, CallType, bytes));
data = abi.encodePacked(selector, _initData);
}

/*//////////////////////////////////////////////////////////////////////////
SIGNATURE UTILS
//////////////////////////////////////////////////////////////////////////*/

function isValidSignature(
AccountInstance memory instance,
address validator,
bytes32 hash,
bytes memory signature
)
public
virtual
override
deployAccountForAction(instance)
returns (bool isValid)
{
isValid = IERC1271(instance.account).isValidSignature(
hash, abi.encodePacked(validator, signature)
) == EIP1271_MAGIC_VALUE;
}

function formatERC1271Signature(
AccountInstance memory instance,
address validator,
bytes memory signature
)
public
virtual
override
returns (bytes memory)
{
return abi.encodePacked(validator, signature);
}
}

0 comments on commit 9272f1a

Please sign in to comment.