-
Notifications
You must be signed in to change notification settings - Fork 37
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
[Design] L2 state derived automatic contract update transactions. #1736
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThe "Ten Auto Updater" is a proposed feature for Ethereum that aims to enable automatic updates of contracts on layer 2 without the need to publish transactions on layer 1. It introduces the concept of "L2 state derived transactions" and outlines the technical requirements and potential use cases for this functionality. Changes
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Status
Actionable comments generated: 6
Configuration used: CodeRabbit UI
Files selected for processing (1)
- design/scratchpad/Design_auto_updater.md (1 hunks)
Additional comments: 3
design/scratchpad/Design_auto_updater.md (3)
5-8: The introduction provides a clear rationale for the feature, explaining the limitations of Ethereum's current transaction initiation process and the benefits of "L2 state derived transactions." It's well-articulated and sets the stage for the rest of the document.
28-36: The "Use cases" section is well thought out, providing concrete examples of how the feature could be utilized. It's important to ensure that these use cases have been validated with potential users of the system to confirm that there is a demand for such a feature. If not already done, gathering feedback from dApp developers could be beneficial.
59-65: The "Performance considerations" section does a good job of addressing potential concerns. The comparison between
L2 derived transactions
andL2 user transactions
is insightful. However, it would be prudent to include some performance benchmarks or projections to support the claim that there will be no noticeable performance degradation.
### Cross Chain Synthetic Transactions Primer | ||
|
||
The synthetic transactions we currently have are not published to the L1. They are not included in the batch albeit mutating its state. This is not an issue, because the transactions are deterministically derived from the L1 state or more specifically, the L1 block that the batch points to. This means that when a validator is recomputing the batch, the data for rebuilding the transactions, in the same order is available implicitly. If we were to publish them to the L1 it would only be redundant and increase costs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The primer on "Cross Chain Synthetic Transactions" is informative. However, it assumes prior knowledge of the batch process and how it relates to L1 state. For clarity, consider adding a brief explanation or a reference link for readers who may not be familiar with these concepts.
### L2 State Derived transactions | ||
|
||
L2 state derived transaction is a special synthetic transaction, also started by the sequencer that would call a specific contract. This contract would have to register itself as updateable and prepay L2 gas costs to the `block.coinbase`. Using this prepayed funding, the sequencer would create the implicit functions calling the entry point function with no calldata and no value. It is possible to extend to support implicit calldata sent through the prepayment, but its best to keep it simple for the initial design. | ||
|
||
The updatable contracts would need to export a callable method that determines if an update transaction should happen. Let's say this function signature will be `shouldAutoUpdate() returns (bool)`. | ||
Whenever a batch is produced, after all the transactions have been applied the sequencer would go through the registered contracts and `derive` the synthetic auto updates that need to happen. Then they would be applied as any other transaction would, where the gas limit and cost would be put as the prepaid amount. Anything unused will be refunded back to the contract. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The section on "L2 State Derived transactions" introduces a new concept effectively. It's important to ensure that the term "sequencer" is well-defined elsewhere in the documentation, as it's a key actor in this process. The explanation of the contract registration and the prepayment mechanism is clear, but it might benefit from a simple diagram or flowchart to illustrate the process visually.
#### Computation implications | ||
|
||
The callable `shouldAutoUpdate` function would need to be subsidized by the sequencer and thus would have hard cap gas limit. This is similar to how optimism grants free gas for some special auto calls on cross chain messages. Alternatively we can use a scheduling mechanic where the contract instructs the sequencer when a transaction should happen, similar to Arbitrum's retryable transactions. When something is scheduled, it would be prepaid and the executed scheduled call should reschedule a new one to keep the automation going. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "Computation implications" subsection introduces the shouldAutoUpdate
function and discusses its gas implications. The comparison to Optimism's gas grants is useful for context. However, the document should specify the exact gas limit for the shouldAutoUpdate
calls or provide a method for determining it to avoid ambiguity.
It's important to note that most dApps aren't structured to be automated in such a way - there is no way to iterate their debt for example, as its stored in maps and people search for liquidation opportunities off chain. Regardless of this, it's reasonable to expect the feature will be utilized. Contracts currently are mostly structured around rebalancing on user inputs directly, along with exposing some public functions that can do another rebalance based on calling other contracts and so on. This is highly inefficient as most of those contracts would be far better off using an automated update system that is paid for by the users who would split the cost instead of paying all of it. While its easy to argue that L2 execution costs are so low right now that this is irrelevant, lowering the barrier even more would enable more use cases and make current ones more efficient. | ||
|
||
|
||
And lastly, there is a very exotic use case for this feature that isn't really possible anywhere - security monitoring. A contract can register an automatic callback that checks some constraints and if something is wrong pause everything automatically. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mention of "security monitoring" as an exotic use case is intriguing. It would be helpful to expand on this idea with more details or a hypothetical scenario to illustrate how it might work in practice.
### Tech Requirements | ||
|
||
We'd need a predeployed system smart contract that allows for registering contracts: | ||
|
||
```solidity | ||
interface TenAutomationRegistry { | ||
function registerCallback(bytes memory callInstructions) external payable | ||
function uniqueCaller(address targetContract, bytes memory callInstructions) pure returns (address) | ||
} | ||
``` | ||
|
||
dApps will use this system contract to register callbacks. Whenever `registerCallback` is called a record will be put to call `msg.sender` with `callInstructions`. | ||
It is payable in this design, because we might need to put some arbitrary cost to prevent DOS attacks. | ||
The `uniqueCaller` getter would return the unique address who will be the `tx.origin` for a specific contract's callback. This will allow the dApps to limit who can call the special automatic functions if they wish to do so. Futhermore it will be a layer of security as the caller address will be isolated per contract's callback, in order to prevent potential security exploits, albeit I'm not able to come up with an example. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "Tech Requirements" section outlines the interface for the TenAutomationRegistry
. The use of payable
in the registerCallback
function is appropriate given the need to prevent DOS attacks. The uniqueCaller
function's purpose is well-explained, but it would be beneficial to include a note on how the unique address is generated or an example of its usage.
The `uniqueCaller` getter would return the unique address who will be the `tx.origin` for a specific contract's callback. This will allow the dApps to limit who can call the special automatic functions if they wish to do so. Futhermore it will be a layer of security as the caller address will be isolated per contract's callback, in order to prevent potential security exploits, albeit I'm not able to come up with an example. | ||
|
||
|
||
To implement the whole feature we'd need to extend the logic in the `BatchExecutor` component and simply add another layer of transactions at the end to be executed by the `evm_facade`. Those transactions will be executed with gas priced same as normal user transactions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation details involving the BatchExecutor
component are briefly mentioned. It would be advantageous to link to existing documentation or code for the BatchExecutor
and evm_facade
for readers to understand the changes in context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Status
Actionable comments generated: 0
Configuration used: CodeRabbit UI
Files selected for processing (1)
- design/scratchpad/Design_auto_updater.md (1 hunks)
Files skipped from review as they are similar to previous changes (1)
- design/scratchpad/Design_auto_updater.md
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Status
Actionable comments generated: 0
Configuration used: CodeRabbit UI
Files selected for processing (1)
- design/scratchpad/Design_auto_updater.md (1 hunks)
Files skipped from review as they are similar to previous changes (1)
- design/scratchpad/Design_auto_updater.md
This feels like a cool, pretty unique feature if we could pull it off. Having to regularly update state as an admin function seems pretty common, I think games developers would find that useful (as well as the AMMs etc. you mentioned). My first thought was DOS attack vector, which you addressed, but I'm a bit worried that the number of these checks will grow and grow like a memory leak. I'm not sure the one-off cost is going to cut it for that, because these auto-update contracts will live forever unless users deregister them I guess, and there's no incentive to deregister really (if the checkUpdate function is free and it's always false because their dapp is dead or whatever so they're not being charged for it actually executing). I was wondering, would it be possible to have the developer deposit eth that will be used to pay for the auto-update check functions? This would mean that:
What do you reckon? Not sure how hard it would be to implement. |
"I imagine this would be really great for automated arbitrage" is a cool point, acknowledging that 'good' MEV exists on the chain and needs to be mopped up. I think publicising this feature would be really important because like you said it's non-standard so people won't expect it. But app developers that want automated housekeeping functions and people wanting to hunt MEV is a pretty big market to pitch it to imo. I think it's important in the long term that we don't make it too cheap though, it's going to cost us to run these and this could be a way to monetise the chain to keep gas fees low, if we can indirectly claim a slice of the MEV by allowing people to register their on-chain algos. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The design needs a bit of restructuring to make it more clear.
Start with the high level, then the use cases, then the proposed implementation.
Is there any usage for gaming that you can think of?
|
||
## Introduction | ||
|
||
In Ethereum it is well known that transactions cannot originate from contracts. There is no way to automatically run some update. Someone has to init the transaction. If you have a contract on a layer 2 that needs rebalancing for example someone has to initiate it. This results in having to publish the transaction on the L1 and pay for it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does rebalancing mean?
@@ -0,0 +1,80 @@ | |||
# Ten Auto Updater - Scheduled callbacks | |||
|
|||
## Introduction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not clear what high-level problem this solves
|
||
You can imagine the scheduling approach akin to doing a recursive javascript `setTimeout`. `block.coinbase` is payed and a system function is called on a predeployed contract. Contracts can use this to conviniently have the first call to them in batch trigger a schedule, paid for by the contract. Gas costs with schedules can be problematic however if they are allowed to happen at arbitrary point in time, as contracts will be unable to predict costs and might fail the schedule (and reschedule) transaction due to being out of gas. This would effectively terminate their loop if they operate based on such. Given that excess will be refunded it shouldn't be a huge problem if contracts oversupply the schedule payment. It's the approach they seem to have with chainlink callbacks. | ||
|
||
#### Use cases |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this section should be in the beginning, in the high level overview
Why this change is needed
Please provide a description and a link to the underlying ticket
What changes were made as part of this PR
Please provide a high level list of the changes made
PR checks pre-merging
Please indicate below by ticking the checkbox that you have read and performed the required
PR checks