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

AA-183: Reformatting and comments in a separate commit #324

Merged
merged 11 commits into from
Aug 15, 2023
84 changes: 52 additions & 32 deletions contracts/core/BaseAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ import "./Helpers.sol";

/**
* Basic account implementation.
* this contract provides the basic logic for implementing the IAccount interface - validateUserOp
* specific account implementation should inherit it and provide the account-specific logic
* This contract provides the basic logic for implementing the IAccount interface - validateUserOp
* Specific account implementation should inherit it and provide the account-specific logic.
*/
abstract contract BaseAccount is IAccount {
using UserOperationLib for UserOperation;

//return value in case of signature failure, with no time-range.
// equivalent to _packValidationData(true,0,0);
uint256 constant internal SIG_VALIDATION_FAILED = 1;
/**
* Return value in case of signature failure, with no time-range.
* Equivalent to _packValidationData(true,0,0).
*/
uint256 internal constant SIG_VALIDATION_FAILED = 1;

/**
* Return the account nonce.
Expand All @@ -30,45 +32,59 @@ abstract contract BaseAccount is IAccount {
}

/**
* return the entryPoint used by this account.
* subclass should return the current entryPoint used by this account.
* Return the entryPoint used by this account.
* Subclass should return the current entryPoint used by this account.
*/
function entryPoint() public view virtual returns (IEntryPoint);

/**
* Validate user's signature and nonce.
* subclass doesn't need to override this method. Instead, it should override the specific internal validation methods.
* Subclass doesn't need to override this method. Instead,
* it should override the specific internal validation methods.
* @param userOp - The user operation to validate.
* @param userOpHash - The hash of the user operation.
* @param missingAccountFunds - The amount of funds missing from the account
* to pay for the user operation.
*/
function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external override virtual returns (uint256 validationData) {
function validateUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external virtual override returns (uint256 validationData) {
_requireFromEntryPoint();
validationData = _validateSignature(userOp, userOpHash);
_validateNonce(userOp.nonce);
_payPrefund(missingAccountFunds);
}

/**
* ensure the request comes from the known entrypoint.
* Ensure the request comes from the known entrypoint.
*/
function _requireFromEntryPoint() internal virtual view {
require(msg.sender == address(entryPoint()), "account: not from EntryPoint");
function _requireFromEntryPoint() internal view virtual {
require(
msg.sender == address(entryPoint()),
"account: not from EntryPoint"
);
}

/**
* validate the signature is valid for this message.
* @param userOp validate the userOp.signature field
* @param userOpHash convenient field: the hash of the request, to check the signature against
* (also hashes the entrypoint and chain id)
* @return validationData signature and time-range of this operation
* <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
* otherwise, an address of an "authorizer" contract.
* <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite"
* <6-byte> validAfter - first timestamp this operation is valid
* If the account doesn't use time-range, it is enough to return SIG_VALIDATION_FAILED value (1) for signature failure.
* Note that the validation code cannot use block.timestamp (or block.number) directly.
* Validate the signature is valid for this message.
* @param userOp - Validate the userOp.signature field.
* @param userOpHash - Convenient field: the hash of the request, to check the signature against.
* (also hashes the entrypoint and chain id)
* @return validationData - Signature and time-range of this operation.
* <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
* otherwise, an address of an "authorizer" contract.
* <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite"
* <6-byte> validAfter - first timestamp this operation is valid
* If the account doesn't use time-range, it is enough to return
* SIG_VALIDATION_FAILED value (1) for signature failure.
* Note that the validation code cannot use block.timestamp (or block.number) directly.
*/
function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash)
internal virtual returns (uint256 validationData);
function _validateSignature(
UserOperation calldata userOp,
bytes32 userOpHash
) internal virtual returns (uint256 validationData);

/**
* Validate the nonce of the UserOperation.
Expand All @@ -90,16 +106,20 @@ abstract contract BaseAccount is IAccount {
}

/**
* sends to the entrypoint (msg.sender) the missing funds for this transaction.
* subclass MAY override this method for better funds management
* Sends to the entrypoint (msg.sender) the missing funds for this transaction.
* SubClass MAY override this method for better funds management
* (e.g. send to the entryPoint more than the minimum required, so that in future transactions
* it will not be required to send again)
* @param missingAccountFunds the minimum value this method should send the entrypoint.
* this value MAY be zero, in case there is enough deposit, or the userOp has a paymaster.
* it will not be required to send again).
* @param missingAccountFunds - The minimum value this method should send the entrypoint.
* This value MAY be zero, in case there is enough deposit,
* or the userOp has a paymaster.
*/
function _payPrefund(uint256 missingAccountFunds) internal virtual {
if (missingAccountFunds != 0) {
(bool success,) = payable(msg.sender).call{value : missingAccountFunds, gas : type(uint256).max}("");
(bool success, ) = payable(msg.sender).call{
value: missingAccountFunds,
gas: type(uint256).max
}("");
(success);
//ignore failure (its EntryPoint's job to verify, not account.)
}
Expand Down
96 changes: 60 additions & 36 deletions contracts/core/BasePaymaster.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;


/* solhint-disable reason-string */

import "@openzeppelin/contracts/access/Ownable.sol";
Expand All @@ -12,100 +11,125 @@ import "./Helpers.sol";
/**
* Helper class for creating a paymaster.
* provides helper methods for staking.
* validates that the postOp is called only by the entryPoint
* Validates that the postOp is called only by the entryPoint.
*/
abstract contract BasePaymaster is IPaymaster, Ownable {

IEntryPoint immutable public entryPoint;
IEntryPoint public immutable entryPoint;

constructor(IEntryPoint _entryPoint) {
entryPoint = _entryPoint;
}

/// @inheritdoc IPaymaster
function validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost)
external override returns (bytes memory context, uint256 validationData) {
_requireFromEntryPoint();
function validatePaymasterUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external override returns (bytes memory context, uint256 validationData) {
_requireFromEntryPoint();
return _validatePaymasterUserOp(userOp, userOpHash, maxCost);
}

function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost)
internal virtual returns (bytes memory context, uint256 validationData);
/**
* Validate a user operation.
* @param userOp - The user operation.
* @param userOpHash - The hash of the user operation.
* @param maxCost - The maximum cost of the user operation.
*/
function _validatePaymasterUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) internal virtual returns (bytes memory context, uint256 validationData);

/// @inheritdoc IPaymaster
function postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) external override {
function postOp(
PostOpMode mode,
bytes calldata context,
uint256 actualGasCost
) external override {
_requireFromEntryPoint();
_postOp(mode, context, actualGasCost);
}

/**
* post-operation handler.
* Post-operation handler.
* (verified to be called only through the entryPoint)
* @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).
* @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
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");
}

/**
* add a deposit for this paymaster, used for paying for transaction fees
* Add a deposit for this paymaster, used for paying for transaction fees.
*/
function deposit() public payable {
entryPoint.depositTo{value : msg.value}(address(this));
entryPoint.depositTo{value: msg.value}(address(this));
}

/**
* withdraw value from the deposit
* @param withdrawAddress target to send to
* @param amount to withdraw
* Withdraw value from the deposit.
* @param withdrawAddress - Target to send to.
* @param amount - Amount to withdraw.
*/
function withdrawTo(address payable withdrawAddress, uint256 amount) public onlyOwner {
function withdrawTo(
address payable withdrawAddress,
uint256 amount
) public onlyOwner {
entryPoint.withdrawTo(withdrawAddress, amount);
}

/**
* add stake for this paymaster.
* 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.
* @param unstakeDelaySec - The unstake delay for this paymaster. Can only be increased.
*/
function addStake(uint32 unstakeDelaySec) external payable onlyOwner {
entryPoint.addStake{value : msg.value}(unstakeDelaySec);
entryPoint.addStake{value: msg.value}(unstakeDelaySec);
}

/**
* return current paymaster's deposit on the entryPoint.
* Return current paymaster's deposit on the entryPoint.
*/
function getDeposit() public view returns (uint256) {
return entryPoint.balanceOf(address(this));
}

/**
* unlock the stake, in order to withdraw it.
* 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 {
entryPoint.unlockStake();
}

/**
* withdraw the entire paymaster's stake.
* 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.
* @param withdrawAddress - The address to send withdrawn value.
*/
function withdrawStake(address payable withdrawAddress) external onlyOwner {
entryPoint.withdrawStake(withdrawAddress);
}

/// validate the call is made from a valid entrypoint
/**
* Validate the call is made from a valid entrypoint
*/
function _requireFromEntryPoint() internal virtual {
require(msg.sender == address(entryPoint), "Sender not EntryPoint");
}
Expand Down
Loading
Loading