自定义 Paymaster
开发者可以自行部署兼容 EntryPoint v0.7 的 Paymaster,为满足自定义策略的 UserOperation 支付 Gas。自定义 Paymaster 的合约、赞助服务、资金、签名策略、风控和可用性均由开发者自行维护。

参考实现:
1. IPaymaster API
interface IPaymaster {
enum PostOpMode {
opSucceeded,
opReverted,
postOpReverted
}
function validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external returns (
bytes memory context,
uint256 validationData
);
function postOp(
PostOpMode mode,
bytes calldata context,
uint256 actualGasCost,
uint256 actualUserOpFeePerGas
) external;
}
1.1 validatePaymasterUserOp
| 参数 | 说明 |
|---|---|
userOp | 待赞助的完整 PackedUserOperation |
userOpHash | 绑定 EntryPoint 和 chainId 的 UserOperation hash |
maxCost | 按 UserOperation Gas 上限和价格计算的最大成本 |
返回值:
| 字段 | 说明 |
|---|---|
context | 传给 postOp 的上下文;空 bytes 表示不需要 postOp |
validationData | 签名有效性与时间范围 |
Paymaster 的 validationData 布局与账户相同:
低 160 位:0 表示有效,1 表示签名失败
接续 48 位:validUntil,0 表示无限期
高 48 位:validAfter
Paymaster 不支持返回聚合器地址;低 160 位除 0 和 1 之外的值会导致验证失败。
该方法必须:
-
只接受绑定 EntryPoint 的调用。
-
验证
paymasterData、sender、目标调用、额度和有效期。 -
对不符合赞助策略的 UserOperation 回滚或返回签名失败。
-
在
maxCost范围内完成预算和限额检查。 -
遵守 Bundler 的 ERC-7562 存储访问和状态变更规则。
1.2 postOp
| 参数 | 说明 |
|---|---|
mode | UserOperation 执行成功或回滚 |
context | 验证阶段返回的上下文 |
actualGasCost | 调用 postOp 前已产生的实际 Gas 成本 |
actualUserOpFeePerGas | 该 UserOperation 实际支付的 Gas 单价 |
PostOpMode:
| 值 | 说明 |
|---|---|
opSucceeded | 账户业务调用成功 |
opReverted | 账户业务调用回滚,Paymaster 仍承担 Gas |
postOpReverted | EntryPoint 内部清理状态,不会作为调用参数传给 Paymaster |
仅当 context 非空时,EntryPoint 才调用 postOp。如果验证方法返回非空 context,Paymaster 必须实现可靠的 postOp;postOp 回滚会使 UserOperation 最终失败,但已经产生的 Gas 仍需支付。
2. BasePaymaster
BasePaymaster 提供 EntryPoint 绑定、调用方校验、deposit 和 stake 管理。子类只需实现赞助策略相关逻辑。
2.1 子类扩展接口
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;
_validatePaymasterUserOp 必须实现。只有返回非空 context 时才需要覆盖 _postOp;BasePaymaster 的默认 _postOp 会回滚。
2.2 资金管理接口
function entryPoint() external view returns (address);
function deposit() external payable;
function getDeposit() 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;
除 deposit 外,BasePaymaster 的提取和 stake 管理接口由 Owner 控制。
3. RPC UserOperation 字段
使用 Paymaster 时,RPC UserOperation 包含:
| 字段 | 类型 | 说明 |
|---|---|---|
paymaster | address | Paymaster 合约地址 |
paymasterVerificationGasLimit | QUANTITY | Paymaster 验证 Gas 上限 |
paymasterPostOpGasLimit | QUANTITY | Paymaster postOp Gas 上限 |
paymasterData | DATA | 自定义授权、签名或策略数据 |
两个 Gas 上限必须在最终发送对象中提供。paymasterData 的格式完全由Paymaster 实现和赞助服务约定。
未使用 Paymaster 时应省略全部四个字段,不要填写零地址。
4. paymasterAndData 布局
RPC 字段转换为 PackedUserOperation 时使用以下布局:
offset 0,长度 20 bytes:paymaster
offset 20,长度 16 bytes:paymasterVerificationGasLimit
offset 36,长度 16 bytes:paymasterPostOpGasLimit
offset 52 至结尾:paymasterData
使用 Paymaster 时,该字段长度至少为 52 字节。未使用 Paymaster 时, paymasterAndData 为空 bytes。
5. Deposit 与 stake
5.1 Deposit
Deposit 用于实际支付 UserOperation Gas。EntryPoint 在验证阶段检查并预扣 required prefund。
| 接口 | 说明 |
|---|---|
depositTo(paymaster) | 为 Paymaster 增加 Gas deposit |
balanceOf(paymaster) | 查询可用 deposit |
withdrawTo | 提取 Paymaster 自己的 deposit |
Deposit 不足会导致 AA31 paymaster deposit too low。
5.2 Stake
Stake 用于 Bundler 的声誉和抗拒绝服务规则,不直接支付 Gas。
| 接口 | 说明 |
|---|---|
addStake | 增加 stake 并设置解锁延迟 |
unlockStake | 开始解锁等待期 |
withdrawStake | 等待期结束后提取 stake |
Paymaster 在验证中访问关联存储或改变特定状态时,Bundler 可能要求其满足最低 stake 和 unstake delay。具体阈值由 Bundler 配置决定。
6. 常见错误
| 错误 | 含义 |
|---|---|
AA31 | Paymaster deposit 不足 |
AA32 | Paymaster validationData 时间范围无效 |
AA33 | validatePaymasterUserOp 回滚 |
AA34 | Paymaster validationData 的低 160 位不是 0 |
AA36 | Paymaster 验证超过 Gas 上限 |
PostOpReverted | postOp 回滚;同时检查 PostOpRevertReason 事件 |
AA93 | paymasterAndData 长度或布局无效 |