-
Notifications
You must be signed in to change notification settings - Fork 46
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
lastInterestRateAdjTime
is not reset on debt increases
#632
Comments
Looking at the one-premature-adjustment-fee-free change, I had a few thoughts. First and foremost, recall that premature adjustment fees were originally designed as a solution to a user monitoring redemptions, and optimistically moving further up the redemption queue, and then back down, while incurring minimal increased interest rates (by virtue of maintaining a low interest rate for a majority of the time, and higher rates during relatively short periods. A fee equal to one week of, roughly, average interest was therefore levied for all changes made within the cooldown period (one week). Which meant that the above strategy would pay the lower rate, plus 2 weeks at the average rate, making this simple strategy unprofitable. ChainSecurity’s analysis, yielded a finding, where two changes could be made for free, where a user who has adjusted less than 7 days previously, joins a batch that they control and which had not been changed previously for at least 7 days, and which has a different interest rate than the trove currently has (first free change), and then making a 2nd change before the 7 day period of the trove before this exploit (“second free change”). Recall that we closed this, by requiring that moving into a batch would trigger a premature adjustment fee in the above, effectively closing the first, but not the second free change. Robert’s scenario using smaller troves and adjusting a larger troves’ debt to one of the smaller troves, is another example of this effect of using the second fee free change. Our later discussions, pointing out that more sophisticated optimisations of the first variant, a batch which can be controlled to exercise the second free change (“empty batch method”). Both Robert’s scenario, and the empty batch method, require a user wanting the ability to make the second free change to pay an upfront premature adjustment fee, and give the user up-to 7 days to take advantage of this adjustment, after which, no premature adjustment would have taken place. Knowing this helps us simply the advantage, and risks of performing this exploit. I propose that we compare the behaviour of an entity wishing to gain access to the second free change (“Attacker”) with that of an honest user who simply adjusts their rates. Robert’s scenario was as follows: Attacker opens a bunch of small (e.g. 2000 BOLD) troves with relatively low interest rates, aiming to keep them at the bottom of the list by adjusting their rates from time to time or reopening them after redemptions if necessary. The overall costs of doing this shouldn't be too high since those troves are relatively small. An honest user by comparison would perform the following: Honest user opens a single trove with the total amount equal to the Attacker’s small troves and big trove with 0.5% interest rate The key to understand here is the time change between steps 1 and 3 in the attacker’s scenario, and between 1 and 2 in the honest user scenario. In the event that 7 days have passed in both, the attacker would have paid today to access the second rate change, whereas the honest user would not have. This means that the attacker would have to save more in interest (paying a sufficiently lower amount in interest than incurred by the upfront fee, while not being forced to exercise their option (step 4) too long before 7 days have passed, but not more than 7 days, ideal exercise time would be seconds before the end of their original cooldown period, but this is not a decision taken by the attacker but by third party redeemers, so we assume cannot be influenced by the attacker or known ex ante). Being forced to proceed to step 4 soon after step 3 means that the interest saved would be lower (for simplicity, let’s assume they are forced to move to the same rate that the honest user sets in their step 2), as they would now move to the higher rate (post 4) and complete the remainder of the 7 days at the new higher rate, whereas they would have paid the sunk cost of the upfront fee (which was not done by the honest user). Their relative PnL (compared with the honest user would be the difference of the interest rate saved over the time in effect, less the upfront fee). We can work out what this difference would be, but unless the difference between the higher than attacker step 2 IR, but lower than attacker step 4 fee set in attacker’s step 3 is sufficiently broad, this attack is likely to not be profitable for the attacker. If we, conversely, assume that both the attacker and honest user have changed their IRs less than 7 days (between attacker step 1 and 3, and honest user step 1 and 2), then the math is a little different. Because the primary motivation of changing the interest rate for both the attacker and the honest user is in response to an increased risk of redemption (recall that by taking the risk and not changing, they both have to pay the upfront fee to rebuild their position post a redemption, which can be said to be their max downside). I propose that the behaviour of the attacker and the honest user would vary at steps 3 and 2, respectively. Recall at step 1, both had a rate of 0.5%. As both know that by setting their rate, they will be either forced to pay a rate which is perceived as safe for 7 days, or face a further upfront fee. An honest user would therefore likely opt for a “safe rate”, which balances their interest rate costs, while minimising the risk that they need to repeat step 2 in less than a week. The attacker, however, has a second strategy to maximise their PnL. They ideally set an “intermediate rate” which avoids redemptions now, but will likely need to be changed less than 7 days from now (after which the intermediate rate is deemed to have been safe, and the honest user simplified overpaid, but this is purely speculative and no second free change was realized, i.e. the attacker took a zero-sum bet and won versus the honest user). To determine the potential PnL of this scenario, we need to now determine the difference between the intermediate rate and the safe rate, up to a maximum of 7 days. I have tried to map this out in this spreadsheet You can also find a visual in this presentation As we do not know, ex ante, when redemptions will come through, an attacker may be forced to exercise this optionality, moving to the safe rate, almost immediately. This would mean that their savings are minimal. Therefore the worst case from the point of view of honest users, is that the attacker is forced to move, but only moments before the 7 day cooldown has ended. It’s worth noting, that repeating the attack after 7 days, whether option in step 4 is exercised or not, it likely to return to the scenario where the honest user is better off, as they would have not changed their rate, and the attacker would have to pay to gain access to the second free change option. I would argue that the further in time the forced exercise of step 4 occurs, the greater the uncertainty. Said differently, setting an intermediate rate which needs to almost immediately be raised to the safe rate results in the least PnL for the attacker (at the expense of honest users), and can be most accurately predicted. Setting an intermediate rate that is closer to the safe rate (higher), reduces the maximum PnL of the attacker, and minimizes the socialized cost. Finally, I would offer, that if the attacker has a sufficient weight in the system, and is able to materially change the yield paid out across BOLD, the greater the likelihood of a subsequent redemption occurring as third parties sell their BOLD due to below market yield, forcing the attacker to exercise 4 over a shorter period of time. In closing, I think that there are significant differences between the original finding from ChainSecurity and the issue proposed by Robert, as well as the empty batch method. Given the highly path dependent nature of a profitable payoff for an attacker, as well as the degradation of UX for honest users, my suggestion is that we do not make any further code changes for this issue, and document the issue as a known issue in the readme. |
Brought up by @cvalkan
According to the Readme,
lastInterestRateAdjTime
is only (re)set to the currentblocktime
when a new Trove is opened or when its interest rate is changed, but not when its debt is increased.It seems that this indeed reflects the behavior of our code (see: onAdjustTrove() doesn't update lastInterestRateAdjTime).
We had similar discussions regarding joining/leaving batches (CS-BOLD-021)
a. The attacker incurs the upfront fee on the debt added to the small trove
b.
lastInterestRateAdjTime
isn't reset since it's only a debt increaseFrom what I can see, this strategy allows the attacker to make free adjustments within less than 7 days, which is unfair.
The text was updated successfully, but these errors were encountered: