Axir ERC20Paymaster
The ERC20Paymaster
is an ERC-4337 compliant Paymaster contract that allows sponsoring gas fees in exchange for ERC-20 tokens. It supports various payment modes, including user-paid transactions with or without limits, and transactions with guarantors.
Overview
The ERC20Paymaster
contract enables users to pay for transaction fees using ERC-20 tokens instead of the native cryptocurrency (e.g., ETH). It uses oracles to fetch the latest token prices and supports standard and up-rebasing ERC-20 tokens.
Key features:
- Support for multiple payment modes
- Dynamic pricing based on oracle data
- Refund of excess tokens
- Configurable price markup
Constructor
constructor(
IERC20Metadata _token,
IEntryPoint _entryPoint,
IOracle _tokenOracle,
IOracle _nativeAssetOracle,
uint32 _stalenessThreshold,
address _owner,
uint32 _priceMarkupLimit,
uint32 _priceMarkup,
uint256 _refundPostOpCost,
uint256 _refundPostOpCostWithGuarantor
)
Initializes the ERC20Paymaster contract with the following parameters:
_token
: The ERC20 token used for transaction fee payments_entryPoint
: The ERC-4337 EntryPoint contract_tokenOracle
: Oracle contract for token to USD prices_nativeAssetOracle
: Oracle contract for native asset (ETH, Matic, etc.) to USD prices_stalenessThreshold
: Time in seconds after which an oracle result is considered stale_owner
: Address to be set as the contract owner_priceMarkupLimit
: Maximum allowed price markup percentage (1e6 = 100%)_priceMarkup
: Initial price markup percentage (1e6 = 100%)_refundPostOpCost
: Estimated gas cost for token refunds_refundPostOpCostWithGuarantor
: Estimated gas cost for token refunds with a guarantor
Payment Modes
The paymaster supports four modes:
- User pays, no limit
- User pays, with a limit
- User pays with a guarantor, no limit
- User pays with a guarantor, with a limit
Modes 2 and 3 are not compatible with the default storage access rules of ERC-4337 and require a whitelist for the guarantors.
Key Functions
validatePaymasterUserOp
function _validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) internal override returns (bytes memory context, uint256 validationResult)
Validates the paymaster data, calculates the required token amount, and transfers the tokens.
postOp
function _postOp(
PostOpMode,
bytes calldata context,
uint256 actualGasCost,
uint256 actualUserOpFeePerGas
) internal override
Performs post-operation tasks, such as refunding excess tokens and attempting to pay back the guarantor if there is one.
updateMarkup
function updateMarkup(uint32 _priceMarkup) external onlyOwner
Allows the contract owner to update the price markup percentage.
withdrawToken
function withdrawToken(address to, uint256 amount) external onlyOwner
Allows the contract owner to withdraw a specified amount of tokens from the contract.
getPrice
function getPrice() public view returns (uint192)
Fetches the latest token price using the configured oracles.
getHash
function getHash(
PackedUserOperation calldata userOp,
uint48 validUntil,
uint48 validAfter,
uint256 tokenLimit
) public view returns (bytes32)
Hashes the user operation data for signature verification.
Events
MarkupUpdated
event MarkupUpdated(uint32 priceMarkup)
Emitted when the price markup is updated.
UserOperationSponsored
event UserOperationSponsored(
bytes32 indexed userOpHash,
address indexed user,
address indexed guarantor,
uint256 tokenAmountPaid,
uint256 tokenPrice,
bool paidByGuarantor
)
Emitted when a user operation is sponsored by the paymaster.
Custom Errors
The contract defines several custom errors for various failure conditions:
PaymasterDataModeInvalid()
PaymasterDataLengthInvalid()
TokenAmountTooHigh()
TokenLimitZero()
PriceMarkupTooHigh()
PriceMarkupTooLow()
OraclePriceStale()
OraclePriceNotPositive()
OracleDecimalsInvalid()