diff --git a/contracts/interfaces/IRip7560StakeManager.sol b/contracts/interfaces/IRip7560StakeManager.sol new file mode 100644 index 0000000..2f2ed29 --- /dev/null +++ b/contracts/interfaces/IRip7560StakeManager.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.23; + +import "@account-abstraction/contracts/interfaces/IStakeManager.sol"; + +interface IRip7560StakeManager is IStakeManager { + + // internal method to return just the stake info + function getStakeInfo(address[] calldata accounts) external view returns (StakeInfo[] memory infos); +} diff --git a/contracts/interfaces/IStakeManager.sol b/contracts/interfaces/IStakeManager.sol deleted file mode 100644 index c19c1ba..0000000 --- a/contracts/interfaces/IStakeManager.sol +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.12; - -/** - * manage deposits and stakes. - * deposit is just a balance used to pay for UserOperations (either by a paymaster or an account) - * stake is value locked for at least "unstakeDelay" by the staked entity. - */ -interface IStakeManager { - - event Deposited( - address indexed account, - uint256 totalDeposit - ); - - event Withdrawn( - address indexed account, - address withdrawAddress, - uint256 amount - ); - - /// Emitted when stake or unstake delay are modified - event StakeLocked( - address indexed account, - uint256 totalStaked, - uint256 unstakeDelaySec - ); - - /// Emitted once a stake is scheduled for withdrawal - event StakeUnlocked( - address indexed account, - uint256 withdrawTime - ); - - event StakeWithdrawn( - address indexed account, - address withdrawAddress, - uint256 amount - ); - - /** - * @param deposit the entity's deposit - * @param staked true if this entity is staked. - * @param stake actual amount of ether staked for this entity. - * @param unstakeDelaySec minimum delay to withdraw the stake. - * @param withdrawTime - first block timestamp where 'withdrawStake' will be callable, or zero if already locked - * @dev sizes were chosen so that (deposit,staked, stake) fit into one cell (used during handleOps) - * and the rest fit into a 2nd cell. - * 112 bit allows for 10^15 eth - * 48 bit for full timestamp - * 32 bit allows 150 years for unstake delay - */ - struct DepositInfo { - uint112 deposit; - bool staked; - uint112 stake; - uint32 unstakeDelaySec; - uint48 withdrawTime; - } - - //API struct used by getStakeInfo and simulateValidation - struct StakeInfo { - uint256 stake; - uint256 unstakeDelaySec; - } - - /// @return info - full deposit information of given account - function getDepositInfo(address account) external view returns (DepositInfo memory info); - - /// @return the deposit (for gas payment) of the account - function balanceOf(address account) external view returns (uint256); - - /** - * add to the deposit of the given account - */ - function depositTo(address account) external payable; - - /** - * add to the account's stake - amount and delay - * any pending unstake is first cancelled. - * @param _unstakeDelaySec the new lock duration before the deposit can be withdrawn. - */ - function addStake(uint32 _unstakeDelaySec) external payable; - - /** - * attempt to unlock the stake. - * the value can be withdrawn (using withdrawStake) after the unstake delay. - */ - function unlockStake() external; - - /** - * withdraw from the (unlocked) stake. - * must first call unlockStake and wait for the unstakeDelay to pass - * @param withdrawAddress the address to send withdrawn value. - */ - function withdrawStake(address payable withdrawAddress) external; - - /** - * withdraw from the deposit. - * @param withdrawAddress the address to send withdrawn value. - * @param withdrawAmount the amount to withdraw. - */ - function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external; -} diff --git a/contracts/predeploys/Rip7560StakeManager.sol b/contracts/predeploys/Rip7560StakeManager.sol new file mode 100644 index 0000000..fab8ca9 --- /dev/null +++ b/contracts/predeploys/Rip7560StakeManager.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.12; + +import "@account-abstraction/contracts/core/StakeManager.sol"; +import "../interfaces/IRip7560StakeManager.sol"; + +contract Rip7560StakeManager is StakeManager, IRip7560StakeManager { + + // internal method to return just the stake info + function getStakeInfo(address[] calldata accounts) public view returns (StakeInfo[] memory) { + StakeInfo[] memory infos = new StakeInfo[](accounts.length); + for (uint256 i = 0; i < accounts.length; i++) { + infos[i] = _getStakeInfo(accounts[i]); + } + return infos; + } +} diff --git a/contracts/predeploys/StakeManager.sol b/contracts/predeploys/StakeManager.sol deleted file mode 100644 index 90c4935..0000000 --- a/contracts/predeploys/StakeManager.sol +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.12; - -import "../interfaces/IStakeManager.sol"; - -/* solhint-disable avoid-low-level-calls */ -/* solhint-disable not-rely-on-time */ -/** - * manage deposits and stakes. - * deposit is just a balance used to pay for UserOperations (either by a paymaster or an account) - * stake is value locked for at least "unstakeDelay" by a paymaster. - */ -contract StakeManager is IStakeManager { - - /// maps paymaster to their deposits and stakes - mapping(address => DepositInfo) public deposits; - - /// @inheritdoc IStakeManager - function getDepositInfo(address account) public view returns (DepositInfo memory info) { - return deposits[account]; - } - - // internal method to return just the stake info - function _getStakeInfo(address addr) internal view returns (StakeInfo memory info) { - DepositInfo storage depositInfo = deposits[addr]; - info.stake = depositInfo.stake; - info.unstakeDelaySec = depositInfo.unstakeDelaySec; - } - - /// return the deposit (for gas payment) of the account - function balanceOf(address account) public view returns (uint256) { - return deposits[account].deposit; - } - - receive() external payable { - depositTo(msg.sender); - } - - function _incrementDeposit(address account, uint256 amount) internal { - DepositInfo storage info = deposits[account]; - uint256 newAmount = info.deposit + amount; - require(newAmount <= type(uint112).max, "deposit overflow"); - info.deposit = uint112(newAmount); - } - - /** - * add to the deposit of the given account - */ - function depositTo(address account) public payable { - _incrementDeposit(account, msg.value); - DepositInfo storage info = deposits[account]; - emit Deposited(account, info.deposit); - } - - /** - * add to the account's stake - amount and delay - * any pending unstake is first cancelled. - * @param unstakeDelaySec the new lock duration before the deposit can be withdrawn. - */ - function addStake(uint32 unstakeDelaySec) public payable { - DepositInfo storage info = deposits[msg.sender]; - require(unstakeDelaySec > 0, "must specify unstake delay"); - require(unstakeDelaySec >= info.unstakeDelaySec, "cannot decrease unstake time"); - uint256 stake = info.stake + msg.value; - require(stake > 0, "no stake specified"); - require(stake <= type(uint112).max, "stake overflow"); - deposits[msg.sender] = DepositInfo( - info.deposit, - true, - uint112(stake), - unstakeDelaySec, - 0 - ); - emit StakeLocked(msg.sender, stake, unstakeDelaySec); - } - - /** - * attempt to unlock the stake. - * the value can be withdrawn (using withdrawStake) after the unstake delay. - */ - function unlockStake() external { - DepositInfo storage info = deposits[msg.sender]; - require(info.unstakeDelaySec != 0, "not staked"); - require(info.staked, "already unstaking"); - uint48 withdrawTime = uint48(block.timestamp) + info.unstakeDelaySec; - info.withdrawTime = withdrawTime; - info.staked = false; - emit StakeUnlocked(msg.sender, withdrawTime); - } - - - /** - * withdraw from the (unlocked) stake. - * must first call unlockStake and wait for the unstakeDelay to pass - * @param withdrawAddress the address to send withdrawn value. - */ - function withdrawStake(address payable withdrawAddress) external { - DepositInfo storage info = deposits[msg.sender]; - uint256 stake = info.stake; - require(stake > 0, "No stake to withdraw"); - require(info.withdrawTime > 0, "must call unlockStake() first"); - require(info.withdrawTime <= block.timestamp, "Stake withdrawal is not due"); - info.unstakeDelaySec = 0; - info.withdrawTime = 0; - info.stake = 0; - emit StakeWithdrawn(msg.sender, withdrawAddress, stake); - (bool success,) = withdrawAddress.call{value : stake}(""); - require(success, "failed to withdraw stake"); - } - - /** - * withdraw from the deposit. - * @param withdrawAddress the address to send withdrawn value. - * @param withdrawAmount the amount to withdraw. - */ - function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external { - DepositInfo storage info = deposits[msg.sender]; - require(withdrawAmount <= info.deposit, "Withdraw amount too large"); - info.deposit = uint112(info.deposit - withdrawAmount); - emit Withdrawn(msg.sender, withdrawAddress, withdrawAmount); - (bool success,) = withdrawAddress.call{value : withdrawAmount}(""); - require(success, "failed to withdraw"); - } -} diff --git a/package.json b/package.json index ba241fa..7519128 100644 --- a/package.json +++ b/package.json @@ -33,5 +33,8 @@ "ts-node": ">=8.0.0", "typechain": "^8.3.0", "typescript": ">=4.5.0" + }, + "dependencies": { + "@account-abstraction/contracts": "^0.7.0" } }