aere-contracts/contracts/paymaster/PaymasterBase.sol
Aere Network a13a649b77
Some checks are pending
contracts-ci / Install (lockfile) → compile → full test suite (push) Waiting to run
contracts-ci / PQC known-answer tests (NIST vectors) (push) Waiting to run
contracts-ci / Coverage (scoped, with artifacts) (push) Waiting to run
Initial public release
Aere Network public source. Everything here can be checked against the live
chain (chain id 2800, https://rpc.aere.network).

Scope note, stated up front rather than buried: consensus on chain 2800 is
classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at
the signature, precompile, account and transport layers. Nothing here makes the
consensus post-quantum, and no document in it should be read as claiming so.
2026-07-20 01:02:37 +03:00

115 lines
3.8 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import "@openzeppelin/contracts/access/Ownable.sol";
/// @dev Minimal subset of ERC-4337 v0.7 IEntryPoint needed by paymasters.
interface IEntryPoint {
function depositTo(address account) external payable;
function balanceOf(address account) external view returns (uint256);
function withdrawTo(address payable withdrawAddress, uint256 amount) external;
function addStake(uint32 unstakeDelaySec) external payable;
function unlockStake() external;
function withdrawStake(address payable withdrawAddress) external;
}
/// @dev ERC-4337 v0.7 PackedUserOperation struct (used by paymaster hook).
struct PackedUserOperation {
address sender;
uint256 nonce;
bytes initCode;
bytes callData;
bytes32 accountGasLimits;
uint256 preVerificationGas;
bytes32 gasFees;
bytes paymasterAndData;
bytes signature;
}
/**
* @title PaymasterBase
* @notice Minimal in-house BasePaymaster compatible with OpenZeppelin v4.9.
* Avoids the OZ-v5 dependency that the upstream eth-infinitism package pulls in.
*
* ERC-4337 v0.7 spec:
* - validatePaymasterUserOp returns (context, validationData)
* - postOp is called with (mode, context, actualGasCost, actualUserOpFeePerGas)
*
* Subclasses override `_validatePaymasterUserOp` and (optionally) `_postOp`.
*/
abstract contract PaymasterBase is Ownable {
IEntryPoint public immutable entryPoint;
enum PostOpMode { opSucceeded, opReverted, postOpReverted }
modifier onlyEntryPoint() {
require(msg.sender == address(entryPoint), "Paymaster: not from EntryPoint");
_;
}
constructor(IEntryPoint _entryPoint) {
entryPoint = _entryPoint;
}
/// EntryPoint calls this during UserOp validation.
function validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external onlyEntryPoint returns (bytes memory context, uint256 validationData) {
return _validatePaymasterUserOp(userOp, userOpHash, maxCost);
}
/// EntryPoint calls this after UserOp execution (if the paymaster requested it via context).
function postOp(
PostOpMode mode,
bytes calldata context,
uint256 actualGasCost,
uint256 actualUserOpFeePerGas
) external onlyEntryPoint {
_postOp(mode, context, actualGasCost, actualUserOpFeePerGas);
}
function _validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) internal virtual returns (bytes memory context, uint256 validationData);
function _postOp(
PostOpMode /*mode*/,
bytes calldata /*context*/,
uint256 /*actualGasCost*/,
uint256 /*actualUserOpFeePerGas*/
) internal virtual {
// Default: no-op. Most paymasters don't need post-op logic.
}
// ───────────────────── EntryPoint deposit helpers ─────────────────────
/// Fund the paymaster's gas deposit at the EntryPoint.
function deposit() external payable {
entryPoint.depositTo{ value: msg.value }(address(this));
}
function depositBalance() external view returns (uint256) {
return entryPoint.balanceOf(address(this));
}
function withdrawDeposit(address payable to, uint256 amount) external onlyOwner {
entryPoint.withdrawTo(to, amount);
}
function addStake(uint32 unstakeDelaySec) external payable onlyOwner {
entryPoint.addStake{ value: msg.value }(unstakeDelaySec);
}
function unlockStake() external onlyOwner { entryPoint.unlockStake(); }
function withdrawStake(address payable to) external onlyOwner {
entryPoint.withdrawStake(to);
}
receive() external payable {}
}