跳到主要内容

自定义 Paymaster

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

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​

参数说明
modeUserOperation 执行成功或回滚
context验证阶段返回的上下文
actualGasCost调用 postOp 前已产生的实际 Gas 成本
actualUserOpFeePerGas该 UserOperation 实际支付的 Gas 单价

PostOpMode:

值说明
opSucceeded账户业务调用成功
opReverted账户业务调用回滚,Paymaster 仍承担 Gas
postOpRevertedEntryPoint 内部清理状态,不会作为调用参数传给 Paymaster

仅当 context 非空时,EntryPoint 才调用 postOp。如果验证方法返回非空 context,Paymaster 必须实现可靠的 postOp;postOp 回滚会使 UserOperation 最终失败,但已经产生的 Gas 仍需支付。

2. BasePaymaster​

BasePaymaster.sol

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 包含:

字段类型说明
paymasteraddressPaymaster 合约地址
paymasterVerificationGasLimitQUANTITYPaymaster 验证 Gas 上限
paymasterPostOpGasLimitQUANTITYPaymaster postOp Gas 上限
paymasterDataDATA自定义授权、签名或策略数据

两个 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. 常见错误​

错误含义
AA31Paymaster deposit 不足
AA32Paymaster validationData 时间范围无效
AA33validatePaymasterUserOp 回滚
AA34Paymaster validationData 的低 160 位不是 0
AA36Paymaster 验证超过 Gas 上限
PostOpRevertedpostOp 回滚;同时检查 PostOpRevertReason 事件
AA93paymasterAndData 长度或布局无效