-
Notifications
You must be signed in to change notification settings - Fork 75
improve(SpokePool): Prevent future deposit quoteTimestamps #356
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
Conversation
There are many now, so it makes sense to split them apart before adding new ones. While here: - Enforce that deposits revert for the expected revert reasons. - Enforce that deposits succeed and emit a "FundsDeposited" event. - Tweak a utility function for simplicity. Done in advance of a proposed change to the SpokePool quoteTimestamp validation.
Future quoteTimestamps create unusual challenges for the bots that process Deposit events. Fundamentally, it's impossible to compute the correct realizedLpFeePct for a deposit with a future quoteTimestamp, so all implementations must correctly park these early deposits and pull them out at the right time. Given that we are now seeing diversity in relayer implementations, it seems improbable that all will implement this correctly, and the downside is that they will lose funds for a slight mistake here. From the depositor side, for the most part it is hard to justify deliberately setting a quoteTimestamp that is in the future. The scenarios where this might impact users is: - A chain lags slightly behind the current time, meaning that deposits will fail due to very small time deltas. - A deposit from a multisig normally wants the widest possible time range to collect the necessary signatures, and is technically losing half of that window. For the former, this could be managed by the API, which supplies the suggested quoteTimestamp to the depositor. In cases where the chain has stalled, the API could simply throw a descriptive error. For the latter, this could be mitigated by doubling the current deposit window.
2690a05 to
ab829cb
Compare
ACX-1533 Revise future quoteTimestamp fix
The change implemented by Matt was a quick fix to resolve an immediate issue, but we've agreed to circle back to it and make some updates so it fits cohesively into the code. |
contracts/SpokePool.sol
Outdated
| getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer && | ||
| getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer, | ||
| "invalid quote time" | ||
| getCurrentTime() >= quoteTimestamp && getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer, |
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 getCurrentTime() should not change between these two calls. Would storing them in a local variable make sense so we don't have to call getCurrentTime() twice?
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'd understood that it was counter-intuitively cheaper to call getCurrentTime() twice than to store it in a local variable, but I have now run the gas analytics over the two options and it doesn't show any difference for me. Per your comment below, we should however be OK to remove the 2nd call to getCurrentTime() and just compute that the delta between the current time and quoteTimestamp is less than the configured buffer.
contracts/SpokePool.sol
Outdated
| getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer && | ||
| getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer, | ||
| "invalid quote time" | ||
| getCurrentTime() >= quoteTimestamp && getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer, |
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.
Potential Refactor:
| getCurrentTime() >= quoteTimestamp && getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer, | |
| quoteTimestamp - getCurrentTime() <= depositQuoteTimeBuffer |
Reasoning:
The original expression is really looking to check if the quote timestamp exists in the window between [c_t, c_(t+b)], or visually:
---------------- c ------------------
[ ]
ct ct+b
c = quote timestamp
ct = current time
b = deposit time buffer
If we apply algebra, we can simplify to:
c_t <= c <= c_t + b
0 <= c - c_t <= b
Because getCurrentTime() and quoteTimestamp() are both unsigned ints, I believe any case where c - c_t where the answer should be negative will result in an underflow and thus make the resulting value incredibly large.
As a result, we can leverage this underflow effectively to ignore the lower comparison and we are left with the revised expression.
cc @nicholaspai
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 buffer is backwards-looking rather than forwards-looking, so quoteTimestamp must always be less than getCurrentTime() and we're actually verifying that ct-b <= c <= ct. But adjusting the change to getCurrentTime() - quoteTimestamp <= depositQuoteTimeBuffer works and avoids the 2nd call to getCurrentTime(). This saves almost 100 gas on a deposit 👍
nb. The change to the comment above was also incorrect; there was no more possibility of underflow, but if we apply the above change there will be once more. I think that's probably OK, since we only expect advanced users to end up submitting future timestamps, so they should also be advanced enough to identify where it reverts.
nicholaspai
left a comment
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.
One comment change but LGTM
Identified by Nick. Co-authored-by: nicholaspai <9457025+nicholaspai@users.noreply.github.com>
improve(SpokePool): Prevent future deposit quoteTimestamps
Future quoteTimestamps create unusual challenges for the bots that
process Deposit events. Fundamentally, it's impossible to compute the
correct realizedLpFeePct for a deposit with a future quoteTimestamp, so
all implementations must correctly park these early deposits and pull
them out at the right time. Given that we are now seeing diversity in
relayer implementations, it seems improbable that all will implement
this correctly, and the downside is that they will lose funds for a
slight mistake here.
From the depositor side, for the most part it is hard to justify
deliberately setting a quoteTimestamp that is in the future.
The scenarios where this might impact users is:
will fail due to very small time deltas.
range to collect the necessary signatures, and is technically losing
half of that window.
For the former, this could be managed by the API, which supplies the
suggested quoteTimestamp to the depositor. In cases where the chain has
stalled, the API could simply throw a descriptive error.
For the latter, this could be mitigated by doubling the current deposit
window.
References ACX-1533