Audits
Last updated
Last updated
We don’t need the imbalance checks to be so precise. Fundings won’t affect the imbalance in a way that would put the protocol in a critical position, so it is safe to acknowledge this from our point of view.
It is possible for a position to exceed our maximum limits, but we estimate the likelihood and feasibility to be extremely low, as it would require predicting the price in advance. Additionally, holding a position with higher leverage significantly increases the chances of liquidation for users. That being said, if certain positions slightly exceed the maximum leverage in edge cases, it does not introduce any risk to the protocol.
We chose this solution because we estimated it to be the best one. It’s not perfect, but the alternative is even worse, as it would require applying funding retroactively from the last update timestamp to the position’s creation timestamp. Not only does this seem unfair, but if the last update timestamp is very old, it could result in a proportionally larger error at the user’s expense. With the current solution, the error is bounded by the Chainlink heartbeat, ensuring it remains within a reasonable magnitude. Therefore, we believe it is the safer approach.
According to both the auditor and us, the value sent to the liquidator is negligible compared to the protocol's balances. This does not justify the additional gas consumption.
The difference in value is negligible, and fixing it would require complex logic just to handle that case.
We chose not to cache all values in the case of an update made by governance. If we did, it would cost users more gas and have a low positive impact for them. We estimate the risk to be low, as updates will not happen frequently.
This is by design, changing this logic would mean giving users more control over the rebalancer’s trigger, and would mess with the bonus mechanism.
While the issue is valid, executing it profitably on a consistent basis will be virtually impossible due to the security deposit and various fees (network and protocol). Therefore, from our point of view, it is safe to acknowledge.
This issue will occur in a very specific case: when we recalculate the tick due to the max leverage condition, and the new tick results in a higher liquidation penalty than the first one. This would mean the position becomes instantly liquidatable. We estimate the risk to be low, and it is safe to acknowledge.
The scenarios explained in this issue are correct, but the protocol fee and the gas cost for making a deposit or a withdrawal will make this case more expensive than staying in the vault.
We think that fixing this issue will lead to more issues in the initialization/validation flow. The gain is low since it only accounts for the funding accumulated between initialization and validation, which is currently 24 seconds. The DoS risk exists but only in a very difficult edge case with extremely low liquidity in the protocol.
This is an emergency function, requiring the price to be the latest available is not mandatory and could introduce friction is our operations during a potential incident.
The price used during initiate actions is temporary. Therefore the fact that it doesn’t use the confidence interval doesn’t matter that much. While it could be annoying for the slippage check, it would require some refactoring for a marginal benefit, so we prefer to leave it as is.
We know that our funding formula works well when there is activity in the protocol. The funding rates and the protocol's balance will improve with user actions, even though these actions could potentially accentuate its imbalance. Also, the new formula from the recommendation will not work as expected.
The potential impact is minimal, while the fix carries a higher risk of introducing new issues.
The price of stETH is almost always extremely close to the price of ETH (because they are backed 1-to-1) and there is no reason to doubt this in this particular scenario. For estimating the liquidator rewards, this simplification is satisfactory.
The 0.5 ETH cap on the reward is already extremely high, and even with very high gas prices, it's unlikely that a single tick liquidation achieves this maximum. Furthermore, ticks are usually liquidated one at a time by automated bots as the price gradually draws down.
Because users of the Dip Accumulator (Rebalancer) are exempt from position fee on entry and receive a bonus collateral reward each time it gets triggered, it's important to avoid that they can exit as soon as the reward was collected. This would nullify the rebalancing effect of this component during crucial liquidation events.
During closure initiation, the _lastPrice
can be more recent than the user-provided price, but never older. As such, it's a better estimate to use the _lastPrice
for the slippage check, especially knowing that most of the time, the price comes from the push-based oracle, which does not have a confidence interval anyway.
The trade-off that was made is to allow users to use the on-chain price for initiation of the position closure, which greatly reduces gas usage compared to using a more recent low-latency price. To avoid other security issues and to remain fair to all users, the unrealized funding is extrapolated to the current timestamp for calculations, so that a user closing a position pays funding up to this moment. This is of course an estimate which can insignificantly affect the calculations of the funding for other users for a short period of time.
Because the difference between the position value calculated during closure initiation and closure validation can only be small (they differ in time by only 24 seconds), the amount of assets that will be transferred from/to the vault for correction will not significantly affect the balance of the protocol. Furthermore, we feel that the triggering logic for the Dip Accumulator (Rebalancer) is too complex to be included in the position closure flow for only minimal benefits.
Since the _lastPrice
can be more recent than the user-provided price (which is for a timestamp 24 seconds after their initiation), but never older, it constitutes a better price to check for a liquidation state here. Moreover, the position can be liquidated at any point and by anyone after the opening has been initiated, which greatly reduces the chances of a user dodging a liquidation.
The protocol has many measures in place to avoid that small changes in balance due to protocol state adjustment can profit a malicious user. Position fees and the confidence interval of the low-latency oracle are used to ensure no profit can be made for such small divergences. On the flip side, those adjustments ensure fairness to users while keeping gas costs to a minimum.
The position fee is rarely changed, and if changed, all efforts will be made to do it while no user has a pending action that must be validated. In most cases, the impact on the price slippage check would be very minor anyway.
This behavior is documented in the source code and is expected. It does not constitute a security issue as the protocol can accomodate leverages which are slightly higher than the set maximum without any problems.
As recommended by the auditors, we will not fix the issue.
The position value exceeding the long's balance is a pretty extreme edge case, and the extrapolation should be on at most 1 hour (Chainlink's heartbeat). Therefore, we are confident this issue is safe to acknowledge.
Imbalance checks are there to prevent heavy imbalance on one side, they do not need to be extremely precise. As the impact is negligible, we can safely acknowledge this issue.
Depending on the oracle used during the initiation phase, the price provided can not include a confidence interval. So, for the sake of consistency, it is not included in the slippage check for any oracle price.
The removal of a blocked pending action is an extreme edge case, the loss of the fee (in wstETH and SDEX) is negligible compared to the cost of storing those values for each and every action. As this does not impact other users, it is safe to acknowledge.
This is an accepted side effect of the current calculation, this is accurately reflected in the funding rate shown on our frontend.
If a pending action is blocked, the protocol cannot function properly. We consider it more important to act fast rather than try and get the correct round ID from Chainlink to calculate the proper value. If absolutely necessary, we can call the liquidate
function with a fresh price before removing the blocked pending action.
As this is an extreme edge case and does not impact other users, we think it is safe to acknowledge.
The clamping of the long balance was added to avoid a potential DoS of the protocol in extreme conditions, including extended protocol inactivity with an aggressive funding and a very low average leverage. While it is not a perfect solution, we find the trade-off acceptable, and thus, the issue safe to acknowledge.
The removal of a blocked pending action without cleanup is a "last resort" functionality. While it is not ideal, it is better than having the protocol (and thus, user funds) blocked with no recourse. We are aware of the side-effect and will only use this function if there are no other solutions.
As previously stated in Issue_27
, we will only use _removeBlockedPendingAction
without cleanup if there are no other solutions.
As previously stated in Issue_27
, we will only remove a pending action if it is currently blocking the whole protocol. By-passing imbalance checks is an acceptable side effect to unblocking the protocol.
We consider that this is an acceptable case and prefer to not change the protocol logic.
Addressing this would require significant changes to the underlying math. Given that this is an edge case, and if longBalance
reaches zero, the implications of this particular scenario are relatively minor compared to broader concerns.
As the solution to this issue is non-trivial, we've followed Bailsec recommendation and added documentation in the code.
This issue can only occur when the penalty has been changed and the Rebalancer attempts to open a position on a tick that still has the previous penalty. While this scenario is possible, we accept that the Rebalancer may occasionally have a position with a slightly higher leverage than anticipated. Following the Bailsec recommendation, we have added code documentation to explicitly address this behavior.
Like the issue 35, we acknowledge that this edge-case can happen, but we accept the fact that the Rebalancer can maybe have a lower leverage than expected.
The two-step action on the protocol means that extrapolations made during the initiation phase may slightly change by the validation phase. This is a design choice, and we accept these cases as part of the system's expected behavior.
This is done on purpose to avoid that the Rebalancer has a high leverage, resulting in a riskier position. If the Rebalancer position gets liquidated, its balancing effect is moot. We can safely acknowledge this issue, as it is a design choice.
Clamping the maximum position value to the position's total exposure was a deliberate design choice. As noted in the Bailsec recommendation, altering this logic would require a full rewrite of all mathematical models. For a position value to approach its total exposure would necessitate both extreme profits AND consistently increasing funding rates growing its value. We have decided to accept this outcome and acknowledge this limitation as a known issue.
The user can immediately create a profitable position, but they will be locked into the protocol during at least 4 hours. This means they are exposed to price action of the underlying asset for this duration. If the Rebalancer gets triggered again, they could be locked for additional time. In any case, user profits aren't guaranteed.
This issue will limit, in specific cases, the opening of a Rebalancer position. We plan to fix this issue in a future update of the protocol, but in the meantime it is safe for us to acknowledge it as it does not represent a security risk for the protocol.
Like for the issue 40, we plan to fix it in a future update.
The calculation of the liquidation reward depends on different factors, of which the Rebalancer action. Those rewards are effectively taken from the vault side, but are clamp to 0.5 ETH. So even if the payout put the protocol in an unbalanced state, it will have a minimal impact.
the low SDEX fees mean slippage would only affect the burned amount by a few wei.