-
Notifications
You must be signed in to change notification settings - Fork 22
[review] MIP-56 : Rate-Limiter for the HTLC-type Native Bridge #56
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
Changes from all commits
4f75ddc
f71b312
a383560
3db31bb
5da5f5e
28c2b3a
ed4bcbf
2541422
8d198e4
88c995e
24ded2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,3 +14,5 @@ | |
|
|
||
| /MIP/mip15/ @l-monninger @apenzk | ||
| /MD/md-15/ @l-monninger @apenzk | ||
|
|
||
| /MIP/mip-56/ @apenzk | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| # MIP-56: Rate-Limiter for the HTLC-based Native Bridge | ||
| - **Description**: A rate limitation mechanism for the HTLC-based Native Bridge. | ||
| - **Authors**: [Andreas Penzkofer](mailto:andreas.penzkofer@movementlabs.xyz) | ||
|
|
||
| ## Abstract | ||
|
|
||
| The **Rate-Limiter** for the HTLC-based Native Bridge (hereafter called Native Bridge) is introduced to de-escalate the risk of double-spends through the Native Bridge by limiting the number of tokens that can be transferred during a certain time frame. The rate limit is determined by the reaction time of the bridge operator, called the **Risk Period**, and the value locked in the **Security Fund**, see [MIP-50](https://github.com/movementlabsxyz/MIP/pull/50). | ||
|
|
||
| The Native Bridge Rate Limiter is implemented through a contract on L1. This contract is governed by the Aptos governance framework, see [MIP-48](https://github.com/movementlabsxyz/MIP/pull/48/), and can be updated through a governance process. | ||
|
|
||
| ## Motivation | ||
|
|
||
| The correct operation of the Native Bridge relies on liveness and safety assumptions for the relayer, see [MIP-13](https://github.com/movementlabsxyz/MIP/tree/mip/security_falliblity/MIP/mip-46). If any of these would not hold, the Native Bridge could expose the network to double-spends. | ||
|
|
||
| ## Specification | ||
|
|
||
| The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. | ||
|
|
||
|  | ||
| *Figure 1: Overview of the Rate-Limiter mechanism for the Native Bridge.* | ||
|
|
||
| > [!NOTE] In the following we note that when talk about the Rate-Limiter, we mean the Rate-Limiter contract. | ||
|
|
||
| 1. The Rate-Limiter SHOULD be implemented as a contract on L1. | ||
| 1. The Rate-Limiter MUST handle both the **transfer directions** L1 -> L2 and L2 -> L1. | ||
| 1. For either transfer direction the transfer value MUST be tracked, i.e. the transferred value for L1->L2 should be recored in `budget_L1L2` and for L2->L1 in `budget_L2L1`. | ||
| 1. The Rate-Limiter SHOULD be governed by the Aptos governance framework, see [MIP-48](https://github.com/movementlabsxyz/MIP/pull/48/), and can be updated through a governance process. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related to my comment above, I see no way (given our current design) the aptos_governance module can communicate directly to the L1. If you're proposing that decisions be made via aptos_governance on the L2 then those decisions be carried out on the L1 by a trusted party, that will suffice for now. Perhaps you could make that clearer here or elsewhere.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this ties in with the above comment on selecting a main action layer. |
||
| 1. The security fund contract, see [MIP-50](https://github.com/movementlabsxyz/MIP/pull/50), MUST update `security_fund` in the Rate-Limiter contract if the amount of funds changes in the security fund contract. | ||
| 1. The `risk_period` value SHOULD be set by the governance process and updated through the governance process. It estimates the maximum reaction time to check whether transfers have been completed correctly. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this point it could only be updated manually. Which is fine for Bilbao stage. We have no way to relay arbitrary actions / messages from one chain to another. This would imply, for full automation and tight governance, a governance relayer, for relayer actions that are outcomes of an accepted proposal from the L2 contract to the L1, which is an interesting idea. Again out of scope though. |
||
| 1. For a given transfer direction, the Rate-Limiter should disable transfers across the bridge if the rate limit is exceeded for that transfer direction. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For "across the bridge" what is meant exactly, on the L2 and L1? I still fail to see how the L1 contract can do any operations on the L2 (it can use the relayer of course, but I think the idea here is to not rely on relaying a message)?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| 1. The rate limit MUST be set according to the equation `rate_limit = security_fund / risk_period * 0.5`. This is to ensure that each bridge transfer direction is ensured sufficiently. | ||
| 1. The Rate-Limiter MUST reject a transfer request if the rate limit is exceeded for that transfer direction by that transaction. I.e. for L1->L2 the Rate-Limiter MUST reject any transfer that would violate `budget_L1L2 < rate_limit` and for L2->L1 the Rate-Limiter MUST reject any transfer that would violate `budget_L2L1 < rate_limit`. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To drill down a bit. The case : Is this what you intend?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it seems the function that would apply the rate limit should be i assume currently a failed lock on L1 would not be reported to L2? Or is there a way the user on L2 can learn that the transfer request failed due to rate limit on L1?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also see the next code line that i just added (L35 currently: ... The rate limiation should be applied at the earliest ....) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why we don't apply rater limiting on both side to the initiate_transfer. There's no need to have it only on one chain. They just have to share the same equation.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would also be possible, but requires two pools : one security pool on L1 and one security pool on L2. pro
con
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added it as an optimization suggestion
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the addition of two pools this adds too much complexity for something Minimal that achieves that rate-limit guarantee that we need. I am going to implement on L1 only if we want to add Rate Limiter on the L2 later, this can happen post Bilbao Model. Or, can be considered as part of the Biarritz Model. |
||
| 1. The rate limitation should be applied at the earliest possible point on L1. For the L1->L2 transfer direction, according to [MIP-39](https://github.com/movementlabsxyz/MIP/pull/39) this is at the `init_bridge_transfer` function. While, for the L2->L1 transfer direction, it is the `lock_bridge_transfer` function. | ||
|
|
||
| ### Optimization | ||
|
|
||
| 1. The Rate-Limiter COULD be implemented as a contract on L2 to save on gas costs. However the security of this approach must be carefully evaluated, as the base truth for the protocol is the L1, which entertains ultimate settlement. | ||
| 1. The rate limit COULD be unbalanced between the two transfer directions by a factor `weight`$\in [0,1]$. That is the equations would be `rate_limit_L1L2 = security_fund / risk_period * weight` and `rate_limit_L2L1 = security_fund / risk_period * (1-weight)`. This would allow for a more flexible rate limit, if the network experiences higher inflow into or outflow from L2. | ||
| 1. The Rate-Limiter COULD consider the budget across both directions as a single budget. This would apply the above equation with a dynamic `weight`. However this raises the question of the asynchrony of events between the two directions, and such an approach should be analyzed carefully. | ||
| 1. The `budget_L1L2` and `budget_L2L1` values COULD be reset, if the governance is convinced that all transfers have been processed correctly and are not revertible, however this is risky due to the introduction of human error. Alternatively, an automated approach could be considered that takes into account all completed transfers. However, this is out of scope for this MIP. | ||
| 1. Alternatively to the security fund contract updating the `security_fund` value in the Rate-Limiter contract, the Rate-Limiter contract could read the `security_fund` value from the security fund contract. However, this raises the question of how regular the Rate-Limiter should update the value, and also it would imply that occasionally the Rate-Limiter could have an outdated value. It is more risky. | ||
| 1. Rate limitation could be implemented on both sides of the bridge. This permits to inform the user at the earliest possible point that a transfer is rejected. However, naively, it would require two separate security fund pools (one on L1 and one on L2), and increase the amount of code, as contracts require implementation both on L1 and L2. | ||
|
|
||
| ### Limitations | ||
|
|
||
| #### Security Considerations | ||
|
|
||
| The Governance imposes a risk on the Rate-Limiter, as it could be manipulated by the governance which holds control over the `risk_period` value. However, the Governance is also responsible for the security fund and other components in the Network. Furthermore the Governance is designed with the intention of moving to a more decentralized design eventually. | ||
|
|
||
| #### Bad user experience when budget is nearly exhausted | ||
|
|
||
| If the budget is nearly exhausted, the Rate-Limiter will reject transfers. This could lead to a bad user experience, as users would not be able to transfer tokens across the bridge. However, this is a necessary trade-off to ensure the security of the bridge. | ||
|
|
||
| User experience could be improved by having warnings issued by a client that reads the remaining budget from the Rate-Limiter contract. In particular the error `RATE_LIMIT_EXCEEDED` should be displayed to the user. | ||
|
|
||
| ## Reference Implementation | ||
|
|
||
| ## Verification | ||
|
|
||
| If the Rate-Limiter handles each transfer direction budget individually, requests for transfers are applied deterministically through the L1 ordering. Thus no asynchronous assumptions are introduced by the Rate-Limiter. | ||
|
|
||
| If the Security Fund contract updates the `security_fund` value in the Rate-Limiter contract, the Rate-Limiter can be sure to have the correct value for the rate limit. | ||
|
|
||
| ## Errata | ||
|
|
||
| ## Appendix | ||
|
|
||
| ## Copyright | ||
|
|
||
| Copyright and related rights waived via [CC0](../LICENSE.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.
If the Limiter is on the L1, how will the governance framework (which is on the L2 communicate with it?) there is no direct path. Perhaps, for now any arguments passed to it are set via restricted functions and later you could have some kind of proxy governance on the L1. Though I would say this is out of scope here.
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.
If the governance is on L2 the rate limit and other governance related function should be implemented on L2?
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.
is the governance on L2 due to operational (gas) 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.
Good question. I think we just initially thought of governance on the L2 because we are aptos first. But perhaps governance on the L1 makes more sense for us. To align those decisions and execute on the L1.
Uh oh!
There was an error while loading. Please reload this page.
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.
i think at least initially we should decide on a particular layer, which would require that most things happen on that layer. which would mean that Rate-Limiter, Bridge-Security-Fund, Governance would need to be on the same layer.
Considerations:
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.
Surely L1. We don't care about cost for L1, as governance transactions are infrequent. High Gas could be considered a good thing for governance, i.e: its expensive to submit a proposal, do it thoughtfully.
Uh oh!
There was an error while loading. Please reload this page.
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.
Also, with that, we can just use already existing protocols such as snapshot https://snapshot.org/#/
Or the MolochDAO contracts (I wouldn't recommend), snapshot better.
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.
For the governance, I think it's because Aptos framework implements one that we wanted to use.
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.
so who sets these values if not governance?
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.
a trusted signer, us. For Bilbao Model, as we wont have any governance implemented for initial mainnet. Only post.