EIP-8141: Frame Transaction

I also STRONGLY think frames should include a value.

I think this was a part of one PR I have seen, though I don’t know it was removed.

One of the advantages that frame transactions have over traditional 7702 wallets, is that it makes it clear in auth only situation what the transaction is having the wallet execute. This is great because it provides a standardized view of what’s happening, which is incredibly useful for wallets and explorers.

Value is also needed when using pure EOA signature handling modes.

1 Like

Yes value should definitely be part of the frame, otherwise every smart account needlessly has to add a custom execute method.

I believe the EIP coauthors are supportive of enabling accounts to use SENDER frames to transfer value without implementing their own execute() function, though there are a few different ways to achieve that. Adding a value field is the most obvious approach, but there was also a different idea where we allow SENDER frames to do DELEGATECALL (possibly toggled via a bit flag), and then we define a precompile that implements an execute() function that supports value transfer and atomic batching. So now an account can just DELEGATECALL the precompile for execution.

Note that if we go with the DELEGATECALL + precompile approach, we’d presumably remove the atomic batching flag since then it’d be redundant.

I’m curious to hear if people in this thread would prefer the value + atomic flag approach, or the DELEGATECALL + precompile approach?

it would be beneficial to also allow loading the return data.

Could you give some examples on how that might be useful?

When evaluating our learnings from Safe we came to the conclusion that we would like to remove DELEGATECALLs completely, therefore we tend to just add the `value` field (with the atomic flag). Not having DELEGATECALL makes formal verification easier and provides stronger security guarantess.

1 Like

Actually accessing return data of a frame might not be a good idea :sweat_smile: I was thinking about it in the context of handling modules. My optimistic approach would be that account contract actually only holds logic for signature verification, the rest would be done via SENDER frames. But if do this and remove DELEGATECALLs then some of the more complex module flows become harder/ impossible to cover. Ultimately this is a tradeoff where we will most likely not get having some “execute” method on the account contract.

1 Like

Having value in the SENDER frame means that frame transactions can provide a clean separation between what you want the transaction to do (which frames would standardize for AA), and the authorization and payment for that transaction.

Removing value forces frames to be only dumb message pipes to smart contracts. This is bad because this:

  1. Kills the “drop in transaction upgrade” nature of frames that would make for the easiest initial adoption.
  2. Requires that wallets build full featured smart contract wallets for even the least adoption.
  3. Removes the tooling and ecosystem benefits that comes from having the transaction actions default to defined and visible in the frame.
1 Like

I prefer the value in the frame approach, it is more intuitive.

I am interested if I’m missing something though, what is the case for the delegatecall + precompile approach?

1 Like

Now that we are leaning more towards having frames support atomic batching, minimizing the need for an execute loop in wallets, I think it makes sense to support value in the frame. The reason for hesitation is that value only makes sense in the SENDER frame. We were hoping for frames to be totally generic across modes and not have a mismatch of usable fields, but it may be unavoidable. The DELEGATECALL approach could replace the need for value because you could delegatecall into a standardized contract to handle your execution.

2 Likes

Not sure if this has been noted, but VERIFY frames are implicitly capped at 2 per transaction.

Every VERIFY must call APPROVE, there are only two approval flags (sender_approved, payer_approved), and each can only be set once. So you either have 1 VERIFY with APPROVE(0x3) or 2 VERIFYs splitting APPROVE(0x1) and APPROVE(0x2). A third VERIFY would have no valid scope left and would fail to APPROVE, invalidating the tx.

Might be worth stating this explicitly in the Constraints section as a static check it’s the kind of thing an implementer could easily miss when reading the spec.

2 Likes

Opened a PR for this along with a few other nits I found while reading through the spec: Update EIP-8141: Fix spec inconsistencies in APPROVE scopes, default code, and added verify frame count check by chiranjeev13 · Pull Request #11488 · ethereum/EIPs · GitHub

Relatedly, access to frame returndata would enable using it as input in multi-step flows without requiring wrapper contracts, which is desirable in many cases (similar to the motivation behind ERC-8211).

Has native support been considered, e.g. via FRAMERETURNDATASIZE and FRAMERETURNDATACOPY, with per-byte gas cost and a cap per frame?

If a block has frame transactions, are all its validation frames executed first, before non-frame transactions and non-validation frames are executed in order? I mean, similar to how ERC-4337 behaves with respect to validations/executions.

value has been added to frames (only valid for SENDER frames): Update EIP-8141: add value field to frame · ethereum/EIPs@a74eab9 · GitHub

3 Likes

Fantastic! Having value really matters.

Now the only two items left on my list are:

  1. Move the current “default” signature handling to something explicitly opt in. This future proofs the transaction, since one day the “default” behavior might need to be a different algo. Also matches previous behavior on 7702 accounts, where a signature can submit for a smart wallet. It is super important that we keep the built in ability to submit sig transactions. Will really help adoption.
  2. Some way to do atomic batching of some or all frames. Otherwise batching isn’t super useful to users.

Sorry could you clarify on both points? I’m a little confused.

  • What did you mean by “default signature handling”? Were you referring to the default code? If so, isn’t it already opt-in in the sense that you specify the sig algorithm you use via the first byte?
  • Re batching across frames – don’t we already support that?

I missed that atomic batching landed. :+1:

On the default handling, the signature byte addresses half of what I was thinking of. Here’s the other half:

Currently for an EOA with a 7702 delegation, you can use a traditional transaction to either:

  • Run the code on the 7702 delegation, and have that code do your stuff
  • Send a transaction that does not use the 7702 delegation in any way, and since it is signed from that address, it just works as a normal transaction.

And you can be confidant which one of these is going the transaction is going to attempt to do, because the transaction encodes which one is going to happen.

With frame transactions, a single transaction could authenticate in either of two different modes, depending on chain state, without you being able specify which one you wanted. This also means that as long as a delegation is present, there is no way to directly send signature only based frame transactions from that account. (Perhaps that’s a feature?)

Compared to everything else we’ve discussed on frame transactions, this one is fairly minor. I really appreciate the process and work everyone has been putting in, and the standard is almost there.

I think I’m getting what you are saying now. Are you saying that, today a EOA with a 7702 delegation can send either a “regular transaction” or be invoked through their code. Therefore it would be more consistent if, with frame transactions, a EOA with a 7702 delegation can both 1) be authenticated through their default code, and 2) be invoked through their code. That’s what you are saying right?

I think that’s an interesting point, but I wonder how we’d achieve that. The current behavior of “if there’s code, use the code, otherwise use the default code” is very simple and intuitive (IMO). If we wanna do what you suggested, then it seems like we’d need to introduce some kind of a flag?

We currently have this rule where for EOAs the first byte of frame.data becomes a signature_type, where 0x0 is for ecrecover and 0x1 is for P256VERIFY, so we kind of have an EOA specific flag already. We can make 0x2 mean “use 7702 code”. We can also extract this flag out of calldata.

Yes, it would be more consistent. It’s also cleaner, explicit instead of implicit, and a tiny bit more performant.

I’m thinking of a flag on a frame, not a byte in the frame calldata. Reasons:

  • One of the goals of this is that you want to choose at submission time how this is authed. If the flag is in the calldata, then it would appears in calldata to every authing AA contract as well. That messes with clean compatibility for existing smart wallet interfaces, besides being decidedly ugly. Moving this to a flag makes it so that you can have clean calldata to AA contracts. Exactly what is submitted as calldata in the frame is what goes to the smart contract.

  • If the blockchain can look at the transaction, and determine that it doesn’t need to resolve 7702 delegations for that frame, that’s one increment in performance.

1 Like