Skip to content

Commit

Permalink
feat: add allowlist deploy script & fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
adamegyed committed Aug 1, 2024
1 parent 5aa0d70 commit 4dc064e
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 51 deletions.
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ ENTRYPOINT=
# Create2 expected addresses of the contracts.
# When running for the first time, the error message will contain the expected addresses.
ACCOUNT_IMPL=
FACTORY=
SINGLE_SIGNER_VALIDATION=
FACTORY=

# Optional, defaults to bytes32(0)
ACCOUNT_IMPL_SALT=
Expand All @@ -18,3 +18,7 @@ SINGLE_SIGNER_VALIDATION_SALT=
# Optional, defaults to 0.1 ether and 1 day, respectively
STAKE_AMOUNT=
UNSTAKE_DELAY=

# Allowlist Module
ALLOWLIST_MODULE=
ALLOWLIST_MODULE_SALT=
21 changes: 21 additions & 0 deletions .solhint-script.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"extends": "solhint:recommended",
"rules": {
"func-name-mixedcase": "off",
"immutable-vars-naming": ["error"],
"no-unused-import": ["error"],
"compiler-version": ["error", ">=0.8.19"],
"custom-errors": "off",
"no-console": "off",
"func-visibility": ["error", { "ignoreConstructors": true }],
"max-line-length": ["error", 120],
"max-states-count": ["warn", 30],
"modifier-name-mixedcase": ["error"],
"private-vars-leading-underscore": ["error"],
"no-inline-assembly": "warn",
"avoid-low-level-calls": "off",
"one-contract-per-file": "off",
"no-empty-blocks": "off",
"reason-string": "off"
}
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
"solhint": "^3.6.2"
},
"scripts": {
"lint": "pnpm lint:src && pnpm lint:test",
"lint": "pnpm lint:src && pnpm lint:test && pnpm lint:script",
"lint:src": "solhint --max-warnings 0 -c .solhint-src.json './src/**/*.sol'",
"lint:test": "solhint --max-warnings 0 -c .solhint-test.json './test/**/*.sol'"
"lint:test": "solhint --max-warnings 0 -c .solhint-test.json './test/**/*.sol'",
"lint:script": "solhint --max-warnings 0 -c .solhint-script.json './script/**/*.sol'"
}
}
87 changes: 43 additions & 44 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
pragma solidity ^0.8.25;

import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
import {Script} from "forge-std/Script.sol";
import {console2} from "forge-std/Test.sol";
import {Script, console} from "forge-std/Script.sol";

import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";

Expand All @@ -28,10 +27,10 @@ contract DeployScript is Script {
uint256 public requiredUnstakeDelay = vm.envOr("UNSTAKE_DELAY", uint256(1 days));

function run() public {
console2.log("******** Deploying ERC-6900 Reference Implementation ********");
console2.log("Chain: ", block.chainid);
console2.log("EP: ", address(entryPoint));
console2.log("Factory owner: ", owner);
console.log("******** Deploying ERC-6900 Reference Implementation ********");
console.log("Chain: ", block.chainid);
console.log("EP: ", address(entryPoint));
console.log("Factory owner: ", owner);

vm.startBroadcast();
_deployAccountImpl(accountImplSalt, accountImpl);
Expand All @@ -42,69 +41,69 @@ contract DeployScript is Script {
}

function _deployAccountImpl(bytes32 salt, address expected) internal {
console2.log(string.concat("Deploying AccountImpl with salt: ", vm.toString(salt)));
console.log(string.concat("Deploying AccountImpl with salt: ", vm.toString(salt)));

address addr = Create2.computeAddress(
salt,
keccak256(abi.encodePacked(type(UpgradeableModularAccount).creationCode, abi.encode(entryPoint))),
CREATE2_FACTORY
);
if (addr != expected) {
console2.log("Expected address mismatch");
console2.log("Expected: ", expected);
console2.log("Actual: ", addr);
console.log("Expected address mismatch");
console.log("Expected: ", expected);
console.log("Actual: ", addr);
revert();
}

if (addr.code.length == 0) {
console2.log("No code found at expected address, deploying...");
console.log("No code found at expected address, deploying...");
UpgradeableModularAccount deployed = new UpgradeableModularAccount{salt: salt}(entryPoint);

if (address(deployed) != expected) {
console2.log("Deployed address mismatch");
console2.log("Expected: ", expected);
console2.log("Deployed: ", address(deployed));
console.log("Deployed address mismatch");
console.log("Expected: ", expected);
console.log("Deployed: ", address(deployed));
revert();
}

console2.log("Deployed AccountImpl at: ", address(deployed));
console.log("Deployed AccountImpl at: ", address(deployed));
} else {
console2.log("Code found at expected address, skipping deployment");
console.log("Code found at expected address, skipping deployment");
}
}

function _deploySingleSignerValidation(bytes32 salt, address expected) internal {
console2.log(string.concat("Deploying SingleSignerValidation with salt: ", vm.toString(salt)));
console.log(string.concat("Deploying SingleSignerValidation with salt: ", vm.toString(salt)));

address addr = Create2.computeAddress(
salt, keccak256(abi.encodePacked(type(SingleSignerValidation).creationCode)), CREATE2_FACTORY
);
if (addr != expected) {
console2.log("Expected address mismatch");
console2.log("Expected: ", expected);
console2.log("Actual: ", addr);
console.log("Expected address mismatch");
console.log("Expected: ", expected);
console.log("Actual: ", addr);
revert();
}

if (addr.code.length == 0) {
console2.log("No code found at expected address, deploying...");
console.log("No code found at expected address, deploying...");
SingleSignerValidation deployed = new SingleSignerValidation{salt: salt}();

if (address(deployed) != expected) {
console2.log("Deployed address mismatch");
console2.log("Expected: ", expected);
console2.log("Deployed: ", address(deployed));
console.log("Deployed address mismatch");
console.log("Expected: ", expected);
console.log("Deployed: ", address(deployed));
revert();
}

console2.log("Deployed SingleSignerValidation at: ", address(deployed));
console.log("Deployed SingleSignerValidation at: ", address(deployed));
} else {
console2.log("Code found at expected address, skipping deployment");
console.log("Code found at expected address, skipping deployment");
}
}

function _deployAccountFactory(bytes32 salt, address expected) internal {
console2.log(string.concat("Deploying AccountFactory with salt: ", vm.toString(salt)));
console.log(string.concat("Deploying AccountFactory with salt: ", vm.toString(salt)));

address addr = Create2.computeAddress(
salt,
Expand All @@ -117,46 +116,46 @@ contract DeployScript is Script {
CREATE2_FACTORY
);
if (addr != expected) {
console2.log("Expected address mismatch");
console2.log("Expected: ", expected);
console2.log("Actual: ", addr);
console.log("Expected address mismatch");
console.log("Expected: ", expected);
console.log("Actual: ", addr);
revert();
}

if (addr.code.length == 0) {
console2.log("No code found at expected address, deploying...");
console.log("No code found at expected address, deploying...");
AccountFactory deployed = new AccountFactory{salt: salt}(
entryPoint, UpgradeableModularAccount(payable(accountImpl)), singleSignerValidation, owner
);

if (address(deployed) != expected) {
console2.log("Deployed address mismatch");
console2.log("Expected: ", expected);
console2.log("Deployed: ", address(deployed));
console.log("Deployed address mismatch");
console.log("Expected: ", expected);
console.log("Deployed: ", address(deployed));
revert();
}

console2.log("Deployed AccountFactory at: ", address(deployed));
console.log("Deployed AccountFactory at: ", address(deployed));
} else {
console2.log("Code found at expected address, skipping deployment");
console.log("Code found at expected address, skipping deployment");
}
}

function _addStakeForFactory(uint32 unstakeDelay, uint256 stakeAmount) internal {
console2.log("Adding stake to factory");
console.log("Adding stake to factory");

uint256 currentStake = entryPoint.getDepositInfo(address(factory)).stake;
console2.log("Current stake: ", currentStake);
console.log("Current stake: ", currentStake);
uint256 stakeToAdd = stakeAmount - currentStake;

if (stakeToAdd > 0) {
console2.log("Adding stake: ", stakeToAdd);
entryPoint.addStake{value: stakeToAdd}(unstakeDelay);
console2.log("Staked factory: ", address(factory));
console2.log("Total stake amount: ", entryPoint.getDepositInfo(address(factory)).stake);
console2.log("Unstake delay: ", entryPoint.getDepositInfo(address(factory)).unstakeDelaySec);
console.log("Adding stake: ", stakeToAdd);
AccountFactory(factory).addStake{value: stakeAmount}(unstakeDelay);
console.log("Staked factory: ", address(factory));
console.log("Total stake amount: ", entryPoint.getDepositInfo(address(factory)).stake);
console.log("Unstake delay: ", entryPoint.getDepositInfo(address(factory)).unstakeDelaySec);
} else {
console2.log("No stake to add");
console.log("No stake to add");
}
}
}
51 changes: 51 additions & 0 deletions script/DeployAllowlistModule.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;

import {Script, console} from "forge-std/Script.sol";

import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";

import {AllowlistModule} from "../src/modules/permissionhooks/AllowlistModule.sol";

contract DeployAllowlistModuleScript is Script {
address public allowlistModule = vm.envOr("ALLOWLIST_MODULE", address(0));

bytes32 public allowlistModuleSalt = bytes32(vm.envOr("ALLOWLIST_MODULE_SALT", uint256(0)));

function run() public {
console.log("******** Deploying AllowlistModule ********");
console.log("Chain: ", block.chainid);

vm.startBroadcast();
_deployAllowlistModule(allowlistModuleSalt, allowlistModule);
vm.stopBroadcast();
}

function _deployAllowlistModule(bytes32 salt, address expected) internal {
console.log(string.concat("Deploying AllowlistModule with salt: ", vm.toString(salt)));

address addr = Create2.computeAddress(salt, keccak256(type(AllowlistModule).creationCode), CREATE2_FACTORY);
if (addr != expected) {
console.log("Expected address mismatch");
console.log("Expected: ", expected);
console.log("Actual: ", addr);
revert();
}

if (addr.code.length == 0) {
console.log("No code found at expected address, deploying...");
AllowlistModule deployed = new AllowlistModule{salt: salt}();

if (address(deployed) != expected) {
console.log("Deployed address mismatch");
console.log("Expected: ", expected);
console.log("Actual: ", address(deployed));
revert();
}

console.log("Deployed AllowlistModule at: ", address(deployed));
} else {
console.log("Code found at expected address, skipping deployment");
}
}
}
5 changes: 2 additions & 3 deletions src/account/AccountFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {ValidationConfigLib} from "../helpers/ValidationConfigLib.sol";
contract AccountFactory is Ownable {
UpgradeableModularAccount public immutable ACCOUNT_IMPL;
bytes32 private immutable _PROXY_BYTECODE_HASH;
uint32 public constant UNSTAKE_DELAY = 1 weeks;
IEntryPoint public immutable ENTRY_POINT;
address public immutable SINGLE_SIGNER_VALIDATION;

Expand Down Expand Up @@ -61,8 +60,8 @@ contract AccountFactory is Ownable {
return UpgradeableModularAccount(payable(addr));
}

function addStake() external payable onlyOwner {
ENTRY_POINT.addStake{value: msg.value}(UNSTAKE_DELAY);
function addStake(uint32 unstakeDelay) external payable onlyOwner {
ENTRY_POINT.addStake{value: msg.value}(unstakeDelay);
}

function unlockStake() external onlyOwner {
Expand Down
19 changes: 18 additions & 1 deletion test/script/Deploy.s.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.25;
import {Test} from "forge-std/Test.sol";

import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol";
import {IStakeManager} from "@eth-infinitism/account-abstraction/interfaces/IStakeManager.sol";
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";

import {DeployScript} from "../../script/Deploy.s.sol";
Expand All @@ -25,7 +26,10 @@ contract DeployTest is Test {

function setUp() public {
_entryPoint = new EntryPoint();
_owner = makeAddr("OWNER");

// Set the owner to the foundry default sender, as this is what will be used as the sender within the
// `startBroadcast` segment of the script.
_owner = DEFAULT_SENDER;

vm.setEnv("ENTRYPOINT", vm.toString(address(_entryPoint)));
vm.setEnv("OWNER", vm.toString(_owner));
Expand Down Expand Up @@ -72,5 +76,18 @@ contract DeployTest is Test {
assertTrue(_accountImpl.code.length > 0);
assertTrue(_factory.code.length > 0);
assertTrue(_singleSignerValidation.code.length > 0);

assertEq(
_singleSignerValidation.code,
type(SingleSignerValidation).runtimeCode,
"SingleSignerValidation runtime code mismatch"
);

// Check factory stake
IStakeManager.DepositInfo memory depositInfo = _entryPoint.getDepositInfo(_factory);

assertTrue(depositInfo.staked, "Factory not staked");
assertEq(depositInfo.stake, 0.1 ether, "Unexpected factory stake amount");
assertEq(depositInfo.unstakeDelaySec, 1 days, "Unexpected factory unstake delay");
}
}
32 changes: 32 additions & 0 deletions test/script/DeployAllowlistModule.s.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;

import {Test} from "forge-std/Test.sol";

import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";

import {DeployAllowlistModuleScript} from "../../script/DeployAllowlistModule.s.sol";

import {AllowlistModule} from "../../src/modules/permissionhooks/AllowlistModule.sol";

contract DeployAllowlistModuleTest is Test {
DeployAllowlistModuleScript internal _deployScript;

address internal _allowlistModule;

function setUp() public {
_allowlistModule =
Create2.computeAddress(bytes32(0), keccak256(type(AllowlistModule).creationCode), CREATE2_FACTORY);

vm.setEnv("ALLOWLIST_MODULE", vm.toString(address(_allowlistModule)));

_deployScript = new DeployAllowlistModuleScript();
}

function test_deployAllowlistModuleScript_run() public {
_deployScript.run();

assertTrue(_allowlistModule.code.length > 0, "AllowlistModule not deployed");
assertEq(_allowlistModule.code, type(AllowlistModule).runtimeCode, "AllowlistModule runtime code mismatch");
}
}

0 comments on commit 4dc064e

Please sign in to comment.