Skip to content

Update EIP-8141: allow payer to approve before sender#11575

Merged
eth-bot merged 1 commit intoethereum:masterfrom
lightclient:frames-pay-before-approve
Apr 28, 2026
Merged

Update EIP-8141: allow payer to approve before sender#11575
eth-bot merged 1 commit intoethereum:masterfrom
lightclient:frames-pay-before-approve

Conversation

@lightclient
Copy link
Copy Markdown
Member

Alternative to #11555

I think it is simpler to just allow the payer to approve before the sender instead of adding the full guarantor role.

@lightclient lightclient requested a review from eth-bot as a code owner April 28, 2026 17:38
@github-actions github-actions Bot added c-update Modifies an existing proposal s-draft This EIP is a Draft t-core labels Apr 28, 2026
@eth-bot
Copy link
Copy Markdown
Collaborator

eth-bot commented Apr 28, 2026

✅ All reviewers have approved.

@eth-bot eth-bot changed the title 8141: allow payer to approve before sender Update EIP-8141: allow payer to approve before sender Apr 28, 2026
@eth-bot eth-bot enabled auto-merge (squash) April 28, 2026 17:39
Copy link
Copy Markdown
Collaborator

@eth-bot eth-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All Reviewers Have Approved; Performing Automatic Merge...

@eth-bot eth-bot merged commit 778fcc1 into ethereum:master Apr 28, 2026
15 of 16 checks passed
Comment thread EIPS/eip-8141.md

- `P256VERIFY` must reject invalid public keys, including points that are not on the P256 curve.
- For the P256 (r1) signature type, the sender address is `keccak(P256_ADDRESS_DOMAIN|qx|qy)[12:]`.
- The default-code payment path does not maintain payer-specific replay protection. A default-code account that approves payment before sender execution approval is replay-safe only if the same transaction later consumes the sender nonce, or if the payer accepts replay risk through some external mechanism.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default code is not safe to use as the guarantor because it uses the canonical sig hash instead of the frame sig hash, so it doesn't know if the transaction will "later consume the sender nonce" since someone can replace the sender signature with an invalid one without invalidating the payer signature.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that seems fine? Payer first seems like a quite specialized role, they can deploy an account to do this?

Comment thread EIPS/eip-8141.md
##### `VERIFY` Mode

Identifies the frame as a validation frame. Its purpose is to *verify* that a sender and/or payer authorized the transaction. It must call `APPROVE` during execution. Failure to do so will result in the whole transaction being invalid.
Identifies the frame as a validation frame. Its purpose is to *verify* that a sender and/or payer authorized the transaction. It must call `APPROVE` during execution. Failure to do so before payment has been approved will result in the whole transaction being invalid after payment has been approved, the frame is treated as a paid failure.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you meant to break this sentence?

Failure to do so before payment has been approved will result in the whole transaction being invalid after payment has been approved, the frame is treated as a paid failure.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, if a VERIFY frame after payment has been approved does NOT call APPROVE at all, is the transaction valid or not? The rest of the spec would suggest that VERIFY frames MUST call approve, but the way this is written makes it sound like it's OK to not call APPROVE as long as payment has been approved.

My suggestion would be:

  • Before payment is approved, VERIFY frames MUST successfully call APPROVE for the transaction to be valid
  • After payment is approved, VERIFY frames MUST call APPROVE for the transaction to be valid, but APPROVE may fail without invalidating the transaction.

Not sure if that's clear or confusing.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that makes sense and should be the intention!

Comment thread EIPS/eip-8141.md
4. `pay` must execute in `VERIFY` mode and successfully call `APPROVE(APPROVE_PAYMENT)`.
4. `pay` must execute in `VERIFY` or `DEFAULT` mode and successfully call `APPROVE(APPROVE_PAYMENT)`.
- If `pay` targets a canonical paymaster instance, the validation prefix must be a sender-first paymaster prefix and `pay` must execute in `VERIFY` mode.
- If `pay` appears in a payer-first prefix, it must not target a canonical paymaster instance.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we update the canonical paymaster code so it can be safely used in a payer-first txn? Otherwise the usefulness of this update is severely limited, since the public mempool only allows 1 pending txn per non-canonical paymaster.

I implemented a replay protection mechanism here: #11555. Though since we don't have an explicit approval scope for guarantors in this PR, the guarantor code path would need to have the additional logic of checking its frame position.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not against adding it to the canonical paymaster, but I think there should be a strong reason to do so at this stage. We can also always add later after 8141 is live if there is demand.

Comment thread EIPS/eip-8141.md
- execution uses a banned opcode
- execution performs a state write, except deterministic deployment performed by the first `deploy` frame through a known deployer
- execution reads storage outside `tx.sender`
- execution performs a state write, except deterministic deployment performed by the first `deploy` frame through a known deployer, or payer-owned replay-protection writes performed by an admitted `pay` frame
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not helpful to specify "replay-protection writes" right? Since it's not clear how the client would enforce that. I think we just need to make the canonical paymaster handle replay, and canonical paymaster can do state writes because of the canonical paymaster exception.

Comment thread EIPS/eip-8141.md
- execution performs a state write, except deterministic deployment performed by the first `deploy` frame through a known deployer
- execution reads storage outside `tx.sender`
- execution performs a state write, except deterministic deployment performed by the first `deploy` frame through a known deployer, or payer-owned replay-protection writes performed by an admitted `pay` frame
- execution reads storage outside `tx.sender`, except payer-owned storage read by an admitted `pay` frame for payment authentication and replay protection
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Comment thread EIPS/eip-8141.md
- TSTORE (0x5D)

`SLOAD` can be used only to access `tx.sender` storage, including when reached transitively via `CALL*` or `DELEGATECALL`.
`SLOAD` can be used only to access `tx.sender` storage, including when reached transitively via `CALL*` or `DELEGATECALL`. A `pay` frame admitted under the paymaster rules may additionally read the paymaster's own storage needed to authenticate and replay-protect payment.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Comment thread EIPS/eip-8141.md
Comment thread EIPS/eip-8141.md
The canonical paymaster in this draft authorizes with a single secp256k1 signer via `ecrecover`, does not support contract-signature schemes, and may change in later specifications, in which case a new canonical implementation version would be required.

Because the canonical paymaster implementation is explicitly standardized to be safe for public mempool use, nodes do not need to apply the generic validation trace and opcode rules to that `pay` frame. Instead, they identify it by runtime code match and apply the paymaster-specific accounting and revalidation rules in this section.
The canonical paymaster is sender-first only for public mempool purposes. Its `pay` frame executes in `VERIFY` mode after an `only_verify` frame has approved execution. Its calldata is `r || s || v`, where `r` and `s` are 32 bytes each and `v` is one byte. The canonical paymaster signature is checked against the canonical signature hash (`TXPARAM(0x08)`). It does not maintain payer-owned replay protection; replay protection for the canonical sender-first flow comes from the sender nonce consumed by the preceding execution approval.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per comments above, once we update the canonical paymaster to support the guarantor pattern, we don't need all these mentions of sender-first throughout the PR.

Comment thread EIPS/eip-8141.md
##### Non-canonical paymaster

For non-canonical paymasters, `pending_withdrawal_amount` is not meaningful since they may not support timelocked withdrawals. Instead, we keep the mempool safe by enforcing that each non-canonical paymaster can only be used with no more than `MAX_PENDING_TXS_USING_NON_CANONICAL_PAYMASTER` pending transactions.
For non-canonical paymasters, `pending_withdrawal_amount` is not meaningful since they may not support timelocked withdrawals. Instead, we keep the mempool safe by enforcing that each non-canonical paymaster can only be used with no more than `MAX_PENDING_TXS_USING_NON_CANONICAL_PAYMASTER` pending transactions. This limit also bounds the effect of non-canonical paymaster replay-state dependencies.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per comments above, I think these mentions of replay-state may be unhelpful since it's not clear how they can be enforced.

Comment thread EIPS/eip-8141.md

`FRAMEPARAM`, `FRAMEDATALOAD`, and `FRAMEDATACOPY` allow validation code to inspect other frames, including later `SENDER` frames and their `value`s. As a result, paymasters and other `VERIFY` frames can observe user operation parameters before approval and may condition their behavior on that information. Users should therefore treat non-`VERIFY` frame parameters and data as visible to validation logic and should not rely on untrusted paymasters or verifiers to keep such information private.

#### Payer-First Replay Protection
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's already a very similar section above; might wanna consolidate it.

@lightclient
Copy link
Copy Markdown
Member Author

reopened as draft #11580

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c-update Modifies an existing proposal s-draft This EIP is a Draft t-core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants