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

feat: add factory stake script #326

Merged
merged 1 commit into from
Dec 17, 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
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ ACCOUNT_FACTORY_SALT=

# Factory staking setup

# Needs a new factory address variable, to address a foundry test suite issue with setEnv
ACCOUNT_FACTORY_TO_STAKE=

# 0.1 ether required by bundlers
REQUIRED_STAKE_AMOUNT_WEI=100000000000000000
# 1 day required by bundlers
Expand Down
83 changes: 83 additions & 0 deletions script/StakeFactory.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

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

import {AccountFactory} from "../src/factory/AccountFactory.sol";

import {ScriptBase} from "./ScriptBase.sol";

contract StakeFactoryScript is ScriptBase {
AccountFactory internal _accountFactory;

IEntryPoint internal _entryPoint;

function setUp() public {
_entryPoint = _getEntryPoint();

// Has to use a different env var name to avoid conflicts with the one in DeployFactoryScript, because
// vm.setEnv in tests doesn't isolate and it would result in a race condition.
_accountFactory = AccountFactory(vm.envOr("ACCOUNT_FACTORY_TO_STAKE", address(0)));
}

function run() public {
console.log("******** Staking Account Factory *********");

if (address(_accountFactory) == address(0)) {
console.log("Account Factory not found or invalid");
revert();
}

console.log("Using AccountFactory at address: ", address(_accountFactory));

(uint256 stakeAmountWei, uint256 unstakeDelay) = _getStakeParams();

uint256 stakeNeeded = _checkCurrentStake(stakeAmountWei);

vm.startBroadcast();

_accountFactory.addStake{value: stakeNeeded}(uint32(unstakeDelay));

vm.stopBroadcast();

console.log("******** Done Staking Account Factory *********");
}

function _getStakeParams() internal view returns (uint256 stakeAmountWei, uint256 unstakeDelaySec) {
stakeAmountWei = vm.envOr("REQUIRED_STAKE_AMOUNT_WEI", uint256(0));

if (stakeAmountWei == 0) {
console.log("Env Variable 'REQUIRED_STAKE_AMOUNT_WEI' not found or invalid.");
revert();
}

console.log("Using user-defined stake amount: ", stakeAmountWei);

unstakeDelaySec = vm.envOr("UNSTAKE_DELAY_SEC", uint256(0));

if (unstakeDelaySec == 0) {
console.log("Env Variable 'UNSTAKE_DELAY_SEC' not found or invalid.");
revert();
}

console.log("Using user-defined unstake delay: ", unstakeDelaySec);
}

function _checkCurrentStake(uint256 requiredStakeAmountWei) internal view returns (uint256 stakeNeeded) {
IStakeManager.DepositInfo memory factoryDepositInfo = _entryPoint.getDepositInfo(address(_accountFactory));

uint256 currentStake = factoryDepositInfo.stake;

if (currentStake > requiredStakeAmountWei) {
console.log("Factory already has enough stake: ", currentStake);
stakeNeeded = 0;
} else {
stakeNeeded = requiredStakeAmountWei - currentStake;
console.log("Adding stake to factory: ", stakeNeeded);
}

return stakeNeeded;
}
}
9 changes: 4 additions & 5 deletions test/script/DeployAccounts.s.t.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

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

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

import {DeployAccountsScript} from "../../script/DeployAccounts.s.sol";
import {ModularAccount} from "../../src/account/ModularAccount.sol";

import {SemiModularAccount7702} from "../../src/account/SemiModularAccount7702.sol";
import {SemiModularAccountBytecode} from "../../src/account/SemiModularAccountBytecode.sol";

contract DeployAccountsTest is Test {
import {OptimizedTest} from "../utils/OptimizedTest.sol";

contract DeployAccountsTest is OptimizedTest {
DeployAccountsScript internal _deployAccountsScript;

address public entryPoint;
Expand All @@ -25,7 +24,7 @@ contract DeployAccountsTest is Test {

bytes32 zeroSalt = bytes32(0);

entryPoint = makeAddr("Entrypoint");
entryPoint = address(_deployEntryPoint070());

executionInstallDelegate = makeAddr("ExecutionInstallDelegate");

Expand Down
8 changes: 4 additions & 4 deletions test/script/DeployFactory.s.t.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

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

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

import {DeployFactoryScript} from "../../script/DeployFactory.s.sol";
import {AccountFactory} from "../../src/factory/AccountFactory.sol";

contract DeployFactoryTest is Test {
import {OptimizedTest} from "../utils/OptimizedTest.sol";

contract DeployFactoryTest is OptimizedTest {
DeployFactoryScript internal _deployFactoryScript;

address public entryPoint;
Expand All @@ -25,7 +25,7 @@ contract DeployFactoryTest is Test {

bytes32 zeroSalt = bytes32(0);

entryPoint = makeAddr("Entrypoint");
entryPoint = address(_deployEntryPoint070());
modularAccountImpl = makeAddr("Modular Account Impl");
semiModularAccountBytecodeImpl = makeAddr("Semi Modular Account Bytecode Impl");
singleSignerValidationModule = makeAddr("Single Signer Validation Module");
Expand Down
8 changes: 4 additions & 4 deletions test/script/DeploySmaStorage.s.t.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

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

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

import {DeploySmaStorageScript} from "../../script/DeploySmaStorage.s.sol";
import {SemiModularAccountStorageOnly} from "../../src/account/SemiModularAccountStorageOnly.sol";

contract DeploySmaStorageTest is Test {
import {OptimizedTest} from "../utils/OptimizedTest.sol";

contract DeploySmaStorageTest is OptimizedTest {
DeploySmaStorageScript internal _deploySmaStorageScript;

address public entryPoint;
Expand All @@ -20,7 +20,7 @@ contract DeploySmaStorageTest is Test {

bytes32 zeroSalt = bytes32(0);

entryPoint = makeAddr("Entrypoint");
entryPoint = address(_deployEntryPoint070());

executionInstallDelegate = makeAddr("ExecutionInstallDelegate");

Expand Down
85 changes: 85 additions & 0 deletions test/script/StakeFactory.s.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";

import {StakeFactoryScript} from "../../script/StakeFactory.s.sol";
import {AccountFactory} from "../../src/factory/AccountFactory.sol";
import {ExecutionInstallDelegate} from "../../src/helpers/ExecutionInstallDelegate.sol";
import {WebAuthnValidationModule} from "../../src/modules/validation/WebAuthnValidationModule.sol";

import {OptimizedTest} from "../utils/OptimizedTest.sol";

contract StakeFactoryTest is OptimizedTest {
StakeFactoryScript internal _stakeFactoryScript;

EntryPoint internal _entryPoint;

AccountFactory internal _accountFactory;

uint256 internal constant _REQUIRED_STAKE_AMOUNT_WEI = 100_000_000_000_000_000;
uint32 internal constant _UNSTAKE_DELAY_SEC = 86_400;

function setUp() public {
_stakeFactoryScript = new StakeFactoryScript();

_entryPoint = _deployEntryPoint070();

ExecutionInstallDelegate executionInstallDelegate = _deployExecutionInstallDelegate();

_accountFactory = new AccountFactory(
_entryPoint,
_deployModularAccount(_entryPoint, executionInstallDelegate),
_deploySemiModularAccountBytecode(_entryPoint, executionInstallDelegate),
address(_deploySingleSignerValidationModule()),
address(new WebAuthnValidationModule()),
DEFAULT_SENDER
);

vm.setEnv("REQUIRED_STAKE_AMOUNT_WEI", vm.toString(_REQUIRED_STAKE_AMOUNT_WEI));
vm.setEnv("UNSTAKE_DELAY_SEC", vm.toString(_UNSTAKE_DELAY_SEC));
vm.setEnv("ACCOUNT_FACTORY_TO_STAKE", vm.toString(address(_accountFactory)));
}

function test_stakeFactoryScript_fromZero() public {
IEntryPoint.DepositInfo memory factoryDepositInfo = _entryPoint.getDepositInfo(address(_accountFactory));

assertFalse(factoryDepositInfo.staked, "Factory should not be staked");
assertEq(factoryDepositInfo.stake, 0, "Factory Stake should be 0");
assertEq(factoryDepositInfo.unstakeDelaySec, 0, "Factory Unstake Delay should be 0");

_stakeFactoryScript.setUp();

_stakeFactoryScript.run();

factoryDepositInfo = _entryPoint.getDepositInfo(address(_accountFactory));

assertTrue(factoryDepositInfo.staked, "Factory should be staked");
assertEq(factoryDepositInfo.stake, _REQUIRED_STAKE_AMOUNT_WEI, "Factory Stake should be 1000");
assertEq(factoryDepositInfo.unstakeDelaySec, _UNSTAKE_DELAY_SEC, "Factory Unstake Delay should be 86_400");
}

function test_stakeFactoryScript_fromNonZero() public {
vm.prank(DEFAULT_SENDER);
_accountFactory.addStake{value: _REQUIRED_STAKE_AMOUNT_WEI / 2}(uint32(_UNSTAKE_DELAY_SEC / 2));

IEntryPoint.DepositInfo memory factoryDepositInfo = _entryPoint.getDepositInfo(address(_accountFactory));

assertTrue(factoryDepositInfo.staked, "Factory should be staked");
assertEq(factoryDepositInfo.stake, _REQUIRED_STAKE_AMOUNT_WEI / 2, "Factory Stake should be 500");
assertEq(
factoryDepositInfo.unstakeDelaySec, _UNSTAKE_DELAY_SEC / 2, "Factory Unstake Delay should be 43_200"
);

_stakeFactoryScript.setUp();

_stakeFactoryScript.run();

factoryDepositInfo = _entryPoint.getDepositInfo(address(_accountFactory));

assertTrue(factoryDepositInfo.staked, "Factory should be staked");
assertEq(factoryDepositInfo.stake, _REQUIRED_STAKE_AMOUNT_WEI, "Factory Stake should be 1000");
assertEq(factoryDepositInfo.unstakeDelaySec, _UNSTAKE_DELAY_SEC, "Factory Unstake Delay should be 86_400");
}
}
Loading