Closed c4-bot-10 closed 6 months ago
gzeon-c4 marked the issue as sufficient quality report
gzeon-c4 marked the issue as primary issue
I think this is intended, when ptrate decreased any further increase is treated as yield to yt
yanisepfl (sponsor) disputed
I think this is intended, when ptrate decreased any further increase is treated as yield to yt
What is stated there is absolutely correct, except if rates have gone to 0, in which case nothing can be done anymore. Indeed, in the catastrophic situation where the IBT rate goes to 0 (non malicious IBT hacked, malicious IBT etc...), depositing/redeeming in and out of the IBT does not make sense anymore (e.g. if the IBT rate is 0, we could expect a user to deposit very small amounts and obtain huge amounts of IBTs). Therefore, what happens after such a scenario is out-of-scope. Also, if it was a non-malicious protocol, and that it recovered funds, it would be up to the hacked protocol to carefully investigate how to redistribute recovered funds to users (which should be done without considering post attack IBT/PT/YT holdings which might be completely off when it comes to who should recover what).
The issue is thus disputed.
JustDravee marked the issue as unsatisfactory: Invalid
Lines of code
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L901-L914
Vulnerability details
Bug description
PrincipalToken contract allows user to tokenize their yield by depositing underlying assets or shares of the underlying ERC4626 vault. The rate which is used to issue new principal tokens is determined by the
ibtRate
andptRate
.ibtRate
is the rate at which oneibtUnit
can be redeemed for the underlying asset, it can increase or decrease and it influences theptRate
.ibtRate
is updated upon user interaction with the protocol, whileptRate
is only updated after an accounted negative rate change on theibtRate
._getCurrentPTandIBTRates()
The function above shows how these rates are calculated and set. The scenario where the
currentIBTRate
is set to 0 happens in a situation where either IBTs have been hacked and stolen all their deposits or a malicious IBT. I will not review the scenario of malicious IBT as it is out of scope, but I will focus on the first case. First of all, let's discuss why and how settingcurrentIBTRate
to 0 can lead to problems. As can be seen from the function, whencurrentIBTRate
is 0, the calculations ofcurrentPTRate
will result in:This is problematic, because unlike
ibtRate
,ptRate
can never increase.ptRate
being 0 leads to the inability for users to ever withdraw their deposited IBTs. This happens due toredeem()
function calling_convertSharesToIBTs()
, where calculations ofibt
to redeem will result in 0, and due towithdraw()
calling_withdrawShares()
, which will revert whenptRate
is 0._convertSharesToIBTs()
_withdrawShares()
Now let's discuss the mentioned scenario under which this situation can occur. If a non-malicious IBT has lost all of its funds, there is still a non-zero chance it will be able to recover. But because
ptRate
is set to 0 and can NEVER increase, all of the holders of that PrincipalToken won't ever have a chance to recover their funds, they will be forever stuck on the balance of the PT contract.Impact
Because
ptRate
can never increase, after it is set to 0, all of the user funds will be stuck on PrincipalToken contract without a way to rescue them.Proof of Concept
Please add the following function to
PrincipalToken3.t.sol
and run the test withforge test --match-test 'testUnableToWithdrawWhenRateIsZero'
.Recommended Mitigation
Ideally
ptRate
should never be set to 0 and it's impossible under normal conditions. Instead of setting it to 0 in such a situation, pause the contract, until IBT is able to resolve the issue. _getCurrentPTandIBTRates()Assessed type
Other