Fee Subsidies
Objective
Fee subsidies enable users to interact with an app without paying gas fees themselves. Users do not need to hold any native tokens to execute transactions with the app’s contracts. Instead, gas costs are covered by a third party, typically the app’s developers.
Solution
Fee subsidies can be built on ERC-4337 account abstraction. Rather than broadcasting transactions directly to the blockchain, users submit UserOperations to a bundler. The bundler aggregates these operations into a single transaction and sends it on-chain.
Within each UserOperation, the user specifies a paymaster contract. This paymaster (not the sender) pays the bundler for the gas used by the UserOperation.
The paymaster’s primary function is to determine whether a UserOperation qualifies for sponsorship, typically by checking if the operation interacts with the subsidized app. This verification is non-trivial, since users can deploy arbitrary smart account implementations. To prevent abuse, the paymaster must:
Inspect the UserOperation’s calldata to confirm it targets the sponsored contract(s).
Verify that the user’s account is running a pre-approved smart account implementation.
An example paymaster for sponsoring a single-contract app might look like this:
contract MyPaymaster is IPaymaster {
function validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external view override returns (bytes memory context, uint256 validationData) {
if (msg.sender != address(entryPoint)) {
revert InvalidEntryPoint();
}
// check if the sender use a whitelisted account implementation
if (userOp.sender.codehash != keccak256(abi.encodePacked(bytes3(0xef0100), allowedSmartAccountImpl))) {
revert InvalidAccountCodeHash();
}
// check if userOp.callData targets the whitelisted contract
checkUserOpCallData(userOp.callData);
// check if userOp.gasFees are within limits
checkUserOpGasFees(userOp.gasFees);
return ("", _packValidationData(false, 0, 0)); // accept paying gas
}
}
Last updated