Files
2023-09-12 15:27:46 +07:00

127 lines
4.5 KiB
Solidity

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IPaymaster} from "@account-abstraction/contracts/interfaces/IPaymaster.sol";
import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol";
import {BaseSmartAccountErrors} from "../common/Errors.sol";
import "@account-abstraction/contracts/core/Helpers.sol";
/**
* Helper class for creating a paymaster.
* provides helper methods for staking.
* validates that the postOp is called only by the ENTRY_POINT
@notice Could have Ownable2Step
*/
abstract contract BasePaymaster is IPaymaster, Ownable, BaseSmartAccountErrors {
IEntryPoint public immutable ENTRY_POINT;
constructor(address _owner, IEntryPoint _entryPoint) {
ENTRY_POINT = _entryPoint;
_transferOwnership(_owner);
}
/**
* add a deposit for this paymaster, used for paying for transaction fees
*/
function deposit() external payable virtual;
/// @inheritdoc IPaymaster
function postOp(
PostOpMode mode,
bytes calldata context,
uint256 actualGasCost
) external override {
_requireFromEntryPoint();
_postOp(mode, context, actualGasCost);
}
/// @inheritdoc IPaymaster
function validatePaymasterUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external override returns (bytes memory context, uint256 validationData) {
_requireFromEntryPoint();
return _validatePaymasterUserOp(userOp, userOpHash, maxCost);
}
/**
* withdraw value from the deposit
* @param withdrawAddress target to send to
* @param amount to withdraw
*/
function withdrawTo(
address payable withdrawAddress,
uint256 amount
) external virtual;
/**
* add stake for this paymaster.
* This method can also carry eth value to add to the current stake.
* @param unstakeDelaySec - the unstake delay for this paymaster. Can only be increased.
*/
function addStake(uint32 unstakeDelaySec) external payable onlyOwner {
ENTRY_POINT.addStake{value: msg.value}(unstakeDelaySec);
}
/**
* unlock the stake, in order to withdraw it.
* The paymaster can't serve requests once unlocked, until it calls addStake again
*/
function unlockStake() external onlyOwner {
ENTRY_POINT.unlockStake();
}
/**
* withdraw the entire paymaster's stake.
* stake must be unlocked first (and then wait for the unstakeDelay to be over)
* @param withdrawAddress the address to send withdrawn value.
*/
function withdrawStake(address payable withdrawAddress) external onlyOwner {
ENTRY_POINT.withdrawStake(withdrawAddress);
}
/**
* return current paymaster's deposit on the ENTRY_POINT.
*/
function getDeposit() public view returns (uint256) {
return ENTRY_POINT.balanceOf(address(this));
}
function _validatePaymasterUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) internal virtual returns (bytes memory context, uint256 validationData);
/**
* post-operation handler.
* (verified to be called only through the ENTRY_POINT)
* @dev if subclass returns a non-empty context from validatePaymasterUserOp, it must also implement this method.
* @param mode enum with the following options:
* opSucceeded - user operation succeeded.
* opReverted - user op reverted. still has to pay for gas.
* postOpReverted - user op succeeded, but caused postOp (in mode=opSucceeded) to revert.
* Now this is the 2nd call, after user's op was deliberately reverted.
* @param context - the context value returned by validatePaymasterUserOp
* @param actualGasCost - actual gas used so far (without this postOp call).
*/
function _postOp(
PostOpMode mode,
bytes calldata context,
uint256 actualGasCost
) internal virtual {
(mode, context, actualGasCost); // unused params
// subclass must override this method if validatePaymasterUserOp returns a context
revert("must override");
}
/// validate the call is made from a valid entrypoint
function _requireFromEntryPoint() internal virtual {
if (msg.sender != address(ENTRY_POINT))
revert CallerIsNotAnEntryPoint(msg.sender);
}
}