EIP-2711: Separate gas payer from msg.sender

Proposition:

  • Keep the “internal” transaction similar to the current ones. They include gasLimit, gasPrice and signeture by the “signer” (msg.sender). This can be submitted and mined like currently
  • Wrap them by adding an overloaded gasPrice and the signature of the “relayer”.

The relayer, if he has an insentive to do so, can wrap the transaction. If the signer doesn’t want to pay the gas, just set the gasPrice of the inner transaction to 0
→ the inner transaction can be mined for free (not likelly, but why not ?)
→ the relayer can add gas to have the transaction mined

If the transaction involves a repaying mechanism onchain, the repaying mechanism should protect the signer by considering a “maxgas” … just like current meta-tx repayement schemes.

Question is, how would that fit with EIP1559

whether you like it or not, this EIP proposes something that is very similar to meta-tx, and which has already been proposed in all core devs by the “meta-transaction folks”. I dobt starting this kind of crusade right here, right now, is a smart move. If I had to chose I would trade in a name I don’t like for support that would bet this EIP into a hard fork / network upgrade.

I’m looking at this as the most updated link, let me know if this is wrong. Under the nonce rationale you’ve listed payload size and deadlock as the problems with requiring a sponsor’s nonce, but I feel like increased cost of validation is biggest concern. I’m not sure if you intended it that to fall under deadlock, but I think it is slightly different and worth mentioning.

I agree with you, we should avoid giving a history lesson within the EIP. However, I believe that it is worth mentioning that this EIP by itself does not solve the relayer payment problem. For that we really need something like rich transactions or batched transactions. I wrote about this need more here.

What do you see as the advantage of this method? At first I was thinking maybe we don’t need to change the tx structure, but if you don’t and introduce some sort of precompile for the relayer to send to then you’re going to link together the signer and sponsor’s nonce - which I think is a problem.

I agree, I don’t want to get hung up on a name it means no support. However, I think being precise in naming is valuable - especially in a technical field. The people I’ve spoken to 1:1 regarding this find it is a more suitable name and appreciate that it is not overloaded with other meanings. Sponsored transactions clearly explain what this EIP is proposing. There is nothing “meta” about the transaction format here, everything is explicit and defined in the protocol. For those reasons, I think it is an appropriate title for this EIP.

I might be wrong, but I imagine that enhancing transaction but appending additional data is preferable to reworking the structure (just like EIP155 does) as it simplifies the client implementation: “is there additional data ? keep the tx I’ve built and just add some check/update with whatever is left”

I really don’t see the point of having a relayer nonce.
→ The internal tx is protected against replay, so the signature for the sponsored transaction (and thus the sponsored transaction) also is.
→ You can sponsor many transaction by many signers without introducing strong ordering between them (better for at scale relaying).
→ If some transaction is sponsored by many people, if one of the version is mined, the other are automatically invalid, and relayer don’t have to support “out of sync” nounces.

Do you see any situation where a relayer nounce would be handy ?

Sorry, I misread your post and thought that by wrapped tx you meant also wrapping with the sponsor’s nonce. But I realize now that you said only the overloaded gas_price and additional signature would be included.

In that case, I agree with you that appending data is probably preferable to reworking the structure. That seems like the advantage here. However, I’m not sure how much this actually matters in practice. Also, I don’t think the signer is has any more protected. Having a gas_limit is not helpful unless gas_price is bounded as well.

I have to disagrea on that. gaslimit is not just about cost, it’s about controlling the execution context, which the signer should define.

A simple example: given its address, and its current nonce, the signer knows what we will the address of the contract he will deploy. This can be helpfull, particularly to recover funds that where send to a contract deployed on another network (I can find you references where that really happens).
Now the signer wants to deploy a contract, so I sign the transaction with the data, and asks for relaying. If the relayer is able to set the gas limit, he can attack by putting a low value (21000), a high gas price, having his transaction mined, reverted because gaslimit is to low.
Boom, he lost some gas but he also increased the signer nounce, preventing from deploying a contract to this address forever.

Also, if a signer wants to send multiple transaction with sequential nonce, and if a relayer uses the same trick to have the first tx revert, the subsequent transaction might have unexpected, potentially dangerous, behaviour.

Again, it’s the signer who is doing the action, so he is the one knowing how much gas is needed, and he is the one whose account is affected if the gas limit is reached. relayer have many way of protecting themselves (either through off chain repaying agreements or using repaying contracts with try/catch protection)

I’m of the opinion that gas_limit and gas_price should both be under the control of the sender.

For gas_limit, the transaction sender is the one with the most context about how much gas the transaction needs to execute. Roughly the same logic can be applied to gas_price.

For gas_price, having it settable by the gas-payer probably makes this un-usable for meta transactions since the it would allow the gas-payer to use unreasonably high gas prices with no consequence in cases where the transaction repays the gas-payer.

From the gas-payer perspective, if the signer uses either a gas_limit or a gas_price that they are not comfortable with, they have the choice to simply not sign the transaction. If these values are left under the control of the gas-payer then the sender must sign a transaction without being able to have full knowledge about what they are signing. And since this is a protocol level thing, I don’t think that we can assume that the sender and relayer will be able to negotiate in all situations.

current meta transaction already have a fix for that. They repay gasUsed * min(gasPrice, maxGasPrice) where maxGasPrice is provided by the sender to the repaying contract

Regarding nonces:

The nonce in eth1.x gives us some DOS protection, ensuring that we can invalidate transactions with too high or low a nonce. I believe that multiple nonces do not provide any additional value, and in-fact, make transaction validation more complex and expensive.

Assuming there is no argument with the above, then we only need one nonce. Our choices seem to be:

  1. sender nonce
  2. gas-payer nonce
  3. some-other nonce

Option 3 of having some other nonce that is not the sender or gas payer does not seem to makes sense.

Option 2 of only having the gas-payer nonce looks problematic. One use case is signing multiple transaction with increasing nonce values which are guaranteed to be executed in nonce order. Using gas-payer nonce would remove the ability of the sender to do this since they would be subject to the gas-payer potentially re-ordering their transactions.

Which leaves Option 1: Just include a single nonce, from the sender account.

Interesting. So the issue of griefing via using arbitrarily high gas prices is easily addressed for the meta-transaction use case at the EVM level.

I’m still concerned about this value being outside of the control of the sender. In the extreme case, the sender has no relationship with the gas payer. IIRC the status token sale set limits on the gas prices allowed for transactions which purchased tokens. I’m not advocating for this design pattern, but such a situation would allow the relayer to cause the sender’s transaction to fail in a way that was outside of the control of the sender.

I’m curious to hear what the argument is for the gas-payer needing to be in control of gas price. Since they have the discretion to sign or not-sign transactions, it seems to make the most sense to leave it in the hands of the sender, and assume that in cases where the gas-payer is sensitive to the exact gas price, then this would need to be handled outside of the protocol.

For example, if the sender trusts gas payer but needs protection against volitile gas prices, the sender can sign multiple messages with different gas prices and the relayer chooses the appropriate one to sign and send.

I imagine the SENDER as “the party that defines what they want to do” and the GAS_PAYER as “the party who gets the transaction included on-chain”. This separation of concerns is what drove me to put both gasLimit and gasPrice into the GAS_PAYER's control rather than the SENDER's control.

I am imagining GAS_PAYER being used for far more than just the traditional meta-transactions of today. One example would be a private relayer where one member of a business (say, an accountant or someone wanting to make a purchase) may submit a transaction to their company’s Transaction Submission Department (TSD) and the TSD would deal with all of the complexity of ensuring inclusion. The person who signed the transaction indicating what they wanted to do doesn’t have the tools/knowledge to properly do gas estimates, gas pricing, replace by fee, escalation, etc. They just know that they want to send 10 ETH to address X or call contract method Y on contract Z.

The fact that someone can maliciously bump the SENDER nonce is certainly something worth considering, and may be enough to convince me to move the gasLimit back to the SENDER's control. I’m pretty firm at the moment on gasPrice being controlled by the GAS_PAYER though as pricing may be done at a different time than SENDER signing. Again, using the company example above, the SENDER may sign the transaction and then it goes through some test suite, is then verified by several different humans, before finally being handed off to the TSD (GAS_PAYER) who picks a reasonable gasPrice at that time.

TL;DR: I think the traditional untrusted-meta-transaction problem can be solved with gasPrice under GAS_PAYER control at layer 2, and by having gasPrice under GAS_PAYER control I think creates opportunities for other uses of this type of transaction.

I have moved gasLimit into SENDER control. Compelling argument to me came from @Amxx in EIP-2711: Separate gas payer from msg.sender

I think the “right” thing to do would be to create a new transaction payload type, perhaps with a sentinel value up front to make it easily identifiable, that supports versioning of the transaction and adding transaction types over time. For example, we could do rlp([TransactionType, [...]]) where TransactionType is a number identifying the type of transaction that is included and the [...] is the actual signed transaction. Need to think more on whether such a transaction can lead to conflicts with existing transactions or if it is possible to uniquely identify them easily or not, but that would let us add new transaction types without having to do bit packing like EIP-155 did, or having to worry about “how do I tell what type of transaction it is” as this one is going to end up doing.

I think the above is generally safe because the 2nd item in the tuple is a list, which is RLP encoded different from other things. Also, we could say that the high bit of the TransactionType is always set to 1, which will never be a valid nonce for legacy transactions to make it even easier to identify legacy transactions early on.

Should an EIP-2711 transaction cost more than the standard base transaction cost of 21000? The raw TX will is larger, more signature verification, and more nonce/account state updates.

It seems tx.origin would be the “sender” and not the “gasPayer” ? Will there be an opcode for gasPayer address?

No having the sender nonce woud allow the gas-payer to replay the sender’s transaction. This is a HUGE no. Imagine sending eth or erc20 … the recipient would be able to do is own repaying to replay this … and drain your entier account

My argument was twofold:

  • if the outer transaction has a gas price that is overloaded by the repayer, we can use the existing transaction format, with gasPrice=0, for the internal format … thus simplifying implementation.
  • This also allows anyone to take any pending transaction and accelerate it. The sender would not be affected in anyway (unless the transaction goes through a repaying mechanism, see later)
  • The sender just want its transaction mined. He should not care about the gasPrice (who cares as long as the tx goes through?).
  • The only case where the sender cares (which is also, AFAIK, the only real usage of the gas price opcode) is when there is an onchain repaying mechanism.
  • Onchain repaying mechanism DO implement protection against relayer putting high gas price to drain the user in favor of the miners.

So not only is the problem out of scope, it’s not even a real one. I believe we should not address it.

I fear this will kills backward compatibility. We have to make sure that all existing transaction format (pre EIP155, post EIP155) remain valid and unchanged otherwize you break a lot of things.

This is the real question. While I could argue that it would make a lot of sens to have tx.origin be the payer, and msg.sender (of the caller) be the signer … this would potentially break many contracts :cry:

Having a new opcode would be nice.

Personal opinion, this will never go trough/move forward unless we have feeback (and support) from core devs.

Maybe a bit too much for this, but any thoughts about adding a token address to automatically make the payment and agreed rate of conversion? As another extension, agreement?

I’m strongly :-1: on inclusion of anything “token” related. Those things can all be handled within the EVM/SmartContract layer.

3 Likes

After some good conversation with @MicahZoltu:

There seem to be a number of strong cases for why gasPrice should typicaly be under the control of the gas-payer. These are primarily centered around separation of concerns since the gas-payer is the one responsible for getting the transaction included and speed of inclusion is often a function of gasPrice.

One case against gasPrice being controlled by gas payer is the griefing angle for meta-transactions when the gas payer is being re-imbursed, but this can be fully mitigated at the EVM/SmartContract layer.

The cases for gasPrice being controlled by sender are fewer, but they are compelling. The 0x protocol use the formula 150,000 * gasPrice * orders filled to compute protocol fees. If gasPrice is controlled by the gas payer, then someone could monitor the transaction pool for sponsored transactions, re-sign them at a higher gas price, and grief the transaction sender.

Given that there seem to be strong cases for both, we advocate supporting both via something like https://github.com/ethereum/EIPs/issues/232 which poses an extensible transaction format.

  • Step one would be to introduce this new format, applied to the current legacy transaction format.
  • Step two would be to introduce new formats for sponsored transactions.

Based on current thinking, there are good cases for sponsored transaction to support the following

  1. Sender controlled gasLimit and gasPrice
  2. Sender controlled gasLimit, Payer controlled gasPrice

There are 2 other potential formats that could be included if there are compelling use cases for them:

  • Payer controlled gasLimit and gasPrice
  • Sender controlled gasPrice, Payer controlled gasLimit

If anyone has strong cases for these formats, speak up.

We are also looking at https://github.com/ethereum/EIPs/pull/2681/files which caps the size of the transaction nonce which is at position-0. This would have the benefit of being able to differentiate between a legacy transaction and a new-style transaction assuming that we offset the transaction versions by 2**64. I’m not advocating for this approach as it is a bit hacky and the new transaction format can already be differentiated from the legacy one by decoding the full RLP payload.