본문으로 건너뛰기

사용자 정의 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
userOpHashEntryPoint와 chainId에 바인딩된 hash
maxCostGas 한도와 가격으로 계산한 최대 비용
반환값설명
contextpostOp에 전달할 컨텍스트, 빈 bytes면 postOp 불필요
validationData서명 유효성 및 시간 범위
하위 160 bit: 0은 유효, 1은 서명 실패
다음 48 bit: validUntil, 0은 만료 없음
상위 48 bit: validAfter

Paymaster는 집계기 주소를 반환할 수 없습니다. 하위 160 bit가 0 또는 1이 아니면 검증에 실패합니다.

이 메서드는 다음을 충족해야 합니다.

  • 연결된 EntryPoint의 호출만 허용합니다.
  • paymasterData, sender, 대상 호출, 한도 및 만료를 검증합니다.
  • 스폰서 정책을 위반하면 revert하거나 서명 실패를 반환합니다.
  • maxCost 범위에서 예산과 할당량을 확인합니다.
  • Bundler의 ERC-7562 storage 접근 및 상태 변경 규칙을 준수합니다.

1.2 postOp​

파라미터설명
modeUserOperation 실행 성공 또는 revert
context검증 단계에서 반환한 컨텍스트
actualGasCostpostOp 호출 전 실제 Gas 비용
actualUserOpFeePerGas실제 지불한 Gas 단가
값설명
opSucceeded비즈니스 호출 성공
opReverted비즈니스 호출 revert, Paymaster는 Gas를 지불
postOpRevertedEntryPoint 내부 정리 상태이며 호출 인자로 전달되지 않음

EntryPoint는 context가 비어 있지 않을 때만 postOp를 호출합니다. 컨텍스트를 반환하는 Paymaster는 신뢰할 수 있는 postOp를 구현해야 합니다. postOp revert 시 UserOperation은 실패하지만 이미 사용한 Gas는 지급됩니다.

2. BasePaymaster​

BasePaymaster.sol은 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는 revert합니다.

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을 제외한 인출 및 stake 관리 메서드는 Owner로 제한됩니다.

3. RPC UserOperation 필드​

필드타입설명
paymasteraddressPaymaster 컨트랙트 주소
paymasterVerificationGasLimitQUANTITYPaymaster 검증 Gas 한도
paymasterPostOpGasLimitQUANTITYpostOp Gas 한도
paymasterDataDATA사용자 정의 권한, 서명 또는 정책 데이터

최종 전송 객체에는 두 Gas 한도가 모두 필요합니다. paymasterData 형식은 구현과 스폰서 서비스가 정의합니다. Paymaster를 사용하지 않으면 네 필드를 모두 생략하고 0 주소를 넣지 마세요.

4. paymasterAndData 레이아웃​

offset 0, 20 bytes: paymaster
offset 20, 16 bytes: paymasterVerificationGasLimit
offset 36, 16 bytes: paymasterPostOpGasLimit
offset 52 이후: paymasterData

Paymaster 사용 시 최소 52 bytes이며 미사용 시 빈 bytes입니다.

5. Deposit 및 stake​

5.1 Deposit​

Deposit은 실제 UserOperation Gas를 지급하며 EntryPoint는 검증 중 필요한 prefund를 확인하고 예약합니다.

인터페이스설명
depositTo(paymaster)Gas deposit 추가
balanceOf(paymaster)사용 가능한 deposit 조회
withdrawToPaymaster 자신의 deposit 인출

부족하면 AA31 paymaster deposit too low가 발생합니다.

5.2 Stake​

Stake는 Bundler 평판과 서비스 거부 공격 방어에 사용되며 Gas를 직접 지급하지 않습니다.

인터페이스설명
addStakestake 추가 및 잠금 해제 지연 설정
unlockStake대기 기간 시작
withdrawStake대기 기간 후 인출

검증 중 관련 storage에 접근하거나 특정 상태를 변경하면 Bundler가 최소 stake와 unstake delay를 요구할 수 있습니다. 임계값은 Bundler 설정에 따릅니다.

6. 일반 오류​

오류의미
AA31Paymaster deposit 부족
AA32validationData 시간 범위 무효
AA33validatePaymasterUserOp revert
AA34validationData 하위 160 bit가 0이 아님
AA36검증 Gas 한도 초과
PostOpRevertedpostOp revert, PostOpRevertReason도 확인
AA93paymasterAndData 길이 또는 레이아웃 무효