Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Research Area: L1 Fee Abstraction #73

Open
tynes opened this issue Feb 29, 2024 · 6 comments
Open

Research Area: L1 Fee Abstraction #73

tynes opened this issue Feb 29, 2024 · 6 comments

Comments

@tynes
Copy link
Contributor

tynes commented Feb 29, 2024

Right now, the L1 portion of the fee is defined in native code. With various hardforks, the fee calculations are changed. This adds tech debt to the state transition function as there becomes more branching logic depending on the currently active chain spec. For example, ecotone introduces a new fee formula and fjord may introduce a new fee formula. This means that every op stack execution client needs to support this branching logic.

It is possible to use EVM bytecode instead to define the L1 portion of the fee. A solidity interface could be defined that accepts the RLP encoded transaction and potentially some other data and it is expected to return a uint256 that represents the L1 fee or the L1 gas used. This would remove altering the fee logic from being a hardfork and increase the social scalability of fee logic discussions as any team working on the OP Stack can choose to use their own fee formulas that work best for them. There should be some standard EVM bytecode that comes with the OP Stack that can do a good job of this fee charging so that teams don't need to think about this problem unless they really want to.

There are some performance considerations of this approach. Benchmarking is required to learn how much of an impact this would have on syncing. Spinning up an EVM instance to do this calculation will always be slower than running the calculation in native code. It is likely that it should be a STATICCALL context, ie no writing of state because that could result in some strange side effects. The only application of writing state would be to write the L1 fee to transient storage such that smart contracts would be able to access the value only during the execution of the particular transaction, this could be useful for meta tx relaying.

Another concern is how the L1 portion of the fee isn't committed to by the user's signature. There may have been some work done to attempt to standardize a "multidimensional fee transaction for L2s" that could help with this problem. If the smart contract can be swapped very quickly, then it may be possible for the network to overcharge end users for their L1 fee because they cannot express a "max amount of L1 fee" they are willing to pay. It is possible that this logic could exist in the smart contract doing the L1 fee charging itself, this could work well with smart contract wallets. This is already an issue for what its worth, as the chain operator can bump the L1 fee params in the SystemConfig arbitrarily.

@tynes
Copy link
Contributor Author

tynes commented Jun 3, 2024

This could be extended to support more than L1 fee abstraction but instead abstract the full fee payment. This would be more intrusive to EVM equivalence, but would enable a lot of experimentation. It is possible that only abstracting the L1 portion of the fee is enough. We would want to think through the exact data passed into the smart contract if we were abstracting the entire fee payment. Likely we would want gasUsed, success and the raw transaction data.

@tynes
Copy link
Contributor Author

tynes commented Jun 3, 2024

This could also be used for MEV rebates by reducing fees for users that need a rebate. A mechanism for tracking who deserves rebates would need to be developed. This could be managed by the chain operator as an oracle, or on chain applications could track this information. For example Uniswap v4 hooks could be very useful for automating the process of determining who deserves MEV rebates

@PinelliaC
Copy link

I believe this proposal has great potential and is also highly flexible. I have carefully reviewed the document. However, there are some critical details that I have doubts about. I hope we can clarify these through discussion. We would like to contribute to accelerating its implementation if necessary.

Fee ratio: The exchange rate between the native token and ether on a custom gas token chain.

A solidity interface could be defined that accepts the RLP encoded transaction and potentially some other data and it is expected to return a uint256 that represents the L1 fee or the L1 gas used

For this implementation, is a fee ratio needed? If so, where should it be stored, and who should update the fee ratio as it changes frequently?
If not, how should the exchange rate between ether and the native token be handled?

This could be extended to support more than L1 fee abstraction but instead abstract the full fee payment.

Since the L1 fee is used to purchase data availability for Ethereum and involves only the data size of the transaction content, it can be computed using a smart contract. However, the L2 fee involves the EVM execution process; how can this approach support it?

@tynes
Copy link
Contributor Author

tynes commented Sep 6, 2024

Regarding the fee ratio, there is no enshrined concept of a fee ratio. It is up to the chain governor to choose the implementation details of the contract that computes the fee. If the chain governor wants to use a fee ratio in their contract, they are free to do so, they could also using an oracle based an an AMM or ecdsa signature.

For this implementation, is a fee ratio needed? If so, where should it be stored, and who should update the fee ratio as it changes frequently?
If not, how should the exchange rate between ether and the native token be handled?

These are implementation specific details. I am happy to provide advice on how it can be done, but ultimately all the protocol is aware of is EVM execution where bytes are passed in and the amount of gas to be charged is returned. For illiquid assets, you likely want a more centralized oracle solution that is able to push exchange rate updates directly to the L2. For liquid assets, you could use an AMM based oracle for the exchange rate.

This could be extended to support more than L1 fee abstraction but instead abstract the full fee payment.

Perhaps its best to just keep it simple and only add this sort of abstraction to the L1 portion of the fee. This would be a much more simple change. There wouldn't be a way to turn off the execution fee or modify it but I suppose that is fine.

@ArtificialPB
Copy link

How would this change impact the Receipt type? It currently contains multiple L1 fee-related fields (L1GasPrice, L1BlobBaseFee, L1Fee, ...), some of which were stored in the DB pre-bedrock, but are now decoded from the L1BlockInfo tx in func (rs Receipts) DeriveFields function.

The L1 gas price info returned from the on-chain function would then again need to be stored in DB for each Receipt, otherwise:

  • the receipt lookup (e.g. via RPC) will not return the correct L1 costs associated with the tx execution,
  • or, in case the gas cost function would be re-executed on lookup, one would need to run an archive node to be able to compute it.

Do you see re-adding some L1 gas cost fields to Receipt as an acceptable outcome of fee abstraction change? Could be implemented similar to DepositNonce/DepositReceiptVersion.

@tynes
Copy link
Contributor Author

tynes commented Nov 18, 2024

@ArtificialPB I haven't thought super deeply about all of the database implications but you raise good points. You don't want to require an archive node to be able to dynamically recreate the values. It does make sense to index them with the receipt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants