Open sherlock-admin opened 1 year ago
We think it's invalid. it's design decision.
Aditya: The purpose of insurance pool is to support additional USDT requirements in the scenario the reserve pool does not have required amount. To simplify this, we keep only a small portion of assets for yield generation. Priorities : User redemption above yield generation. Ie: Only when there is enough capital in reserve and insurance pool, we take a small portion to invest in delta nuetral defi pools.
Protocol's design choice, not a issue
Escalate for 10 USDC This is not just a design choice. There are no specifics on what a "small portion" or "enough capital in reserve and insurance pool" means. Allowing the protocol team to remove collateral from the system to earn yield is a security risk. In the current version, USDT is the collateral for USD1. Without USDT, USD1 is worth nothing. The reserve ratio is used to keep the protocol healthy at all times. By including the funds inside the portfolio in the calculation you allow the protocol to become under-collateralized under certain circumstances.
Considering that #16 describes the risk of the portfolio incurring a loss which is deemed a valid issue, it's reckless to account for the funds inside the portfolio when calculating the reserve ratio. From a protocol perspective, these funds are not part of the system anymore. They were moved into a different protocol to earn yield. That is fine as long as you keep the reserve ratio of Unitas above 130%. For that to be the case, the funds inside the portfolio have to be excluded from the reserve ratio calculation.
To sum up, any funds inside the portfolio should not be used to calculate the reserve ratio. They can be gone at any moment due to the risks described in #16.
EDIT:
_getPortfolio()
is not called although it clearly is in the code snipped they provide. The submission makes no senseI checked the docs on whether each of these duplication issues had to be escalated separately. I didn't find any rules for that. So I decided to bring them up in a single comment. Otherwise, I'd had to create 6 additional escalations without even knowing whether this original issue here is deemed valid. If that's not the case you don't care about the wrong duplication anyways.
Escalate for 10 USDC This is not just a design choice. There are no specifics on what a "small portion" or "enough capital in reserve and insurance pool" means. Allowing the protocol team to remove collateral from the system to earn yield is a security risk. In the current version, USDT is the collateral for USD1. Without USDT, USD1 is worth nothing. The reserve ratio is used to keep the protocol healthy at all times. By including the funds inside the portfolio in the calculation you allow the protocol to become under-collateralized under certain circumstances.
Considering that #16 describes the risk of the portfolio incurring a loss which is deemed a valid issue, it's reckless to account for the funds inside the portfolio when calculating the reserve ratio. From a protocol perspective, these funds are not part of the system anymore. They were moved into a different protocol to earn yield. That is fine as long as you keep the reserve ratio of Unitas above 130%. For that to be the case, the funds inside the portfolio have to be excluded from the reserve ratio calculation.
To sum up, any funds inside the portfolio should not be used to calculate the reserve ratio. They can be gone at any moment due to the risks described in #16.
EDIT:
14 is not a valid duplicate. If portfolio > collateral the subtraction would revert so there's no underflow there.
43 is not a valid duplicate. Warden argues that
_getPortfolio()
is not called although it clearly is in the code snipped they provide. The submission makes no sense90 is not a valid duplicate. Warden argues that a swap will fail if there are not enough funds in the insurance pool. That's desired behavior. You don't want to execute the swap if there are not enough funds for it.
127 is not a valid duplicate. Warden argues that the portfolio amount is accounted for multiple times. But, the insurance pool is a separate contract. The portfolio amount would be 0 for the insurance pool. Thus you don't account for it twice.
129 is not a valid duplicate. The issue itself is valid. The admin is able to leave the protocol under-collateralized by sending to many funds to the portfolio. That's a duplicate of #40
142 is not a valid duplicate. Tokens that are not registered in the TokenManager are not used as collateral. Even if the insurance pool holds these tokens they shouldn't be accounted for since they are not registered collateral tokens. Also, the admin has to make a mistake and send these tokens to the insurance pool since they are the only ones that are allowed to deposit.
I checked the docs on whether each of these duplication issues had to be escalated separately. I didn't find any rules for that. So I decided to bring them up in a single comment. Otherwise, I'd had to create 6 additional escalations without even knowing whether this original issue here is deemed valid. If that's not the case you don't care about the wrong duplication anyways.
You've created a valid escalation for 10 USDC!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
Will bring for sponsor review, I think this can be a valid medium
Escalate for 10 USDC
Reading the original report, I see no mentioning of the potential path or risk that leads to the issue. However in the escalation, the arguments are built upon the insights and finding of another report after submission. If the original report stands alone, I am not sure that it is convincing enough.
This escalation also aims to clarify the rules for other Watsons who may do the same in the future.
Escalate for 10 USDC
Reading the original report, I see no mentioning of the potential path or risk that leads to the issue. However in the escalation, the arguments are built upon the insights and finding of another report after submission. If the original report stands alone, I am not sure that it is convincing enough.
This escalation also aims to clarify the rules for other Watsons who may do the same in the future.
You've created a valid escalation for 10 USDC!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
@0xruhum I see what you're getting at. But the only way this can be a valid issue is if the protocol has intended for users to always be able to redeem USD1 into USDT when the reserve ratio is 100% or greater. I don't think Unitas has made that claim anywhere? If you see a claim like this (in comments or in code), please show me.
Update @0xruhum: Based on the following sentence in the README, the broader point of this issue should be true:
The Unitas protocol guarantees unrestricted and unconditional conversion of its unitized stablecoins “back” to USD-pegged stablecoins.
The issue correct gets that "users may not be able to fully redeem USD1 into USDT even when the reserve ratio is above 100%" so this issue should be a valid Medium (maybe even High). But the portfolio aspect is not super unique, so it should be duplicated with any other issues that get the general idea of this vulnerability.
Escalation accepted
Duplicate of #13
But the portfolio aspect is not super unique, so it should be duplicated with any other issues that get the general idea of this vulnerability.
Yep. Just wanted to mention again that the issues I've linked in the original escalation comment aren't valid duplicates tho. That should be taken into account.
Ok @0xruhum, as far as I'm aware none of them are considered to be duplicates right now.
Ok @0xruhum, as far as I'm aware none of them are considered to be duplicates right now.
Hey I think #114 should be taken into account too. I didn't create escalation because it was considered duplicate of the main report in the first place.
Ok @Jiamincoin, I agree that #114 is a duplicate of this issue.
I do not see any discussion of duplicate #118. Please consider it before ending the escalation evaluations.
Result: Medium Has duplicates
Escalations have been resolved successfully!
Escalation status:
Acknowledged by protocol team (won't fix).
Juntao
high
Users may not be able to fully redeem USD1 into USDT even when reserve ratio is above 100%
Summary
Users may not be able to fully redeem USDT even when reserve ratio is above 100%, because of portfolio being taken into the account for calculation.
Vulnerability Detail
Reserve ratio shows how many liabilities is covered by reserves, a reserve ratio above 100% guarantees protocol has enough USDT to redeem, the way of calculating reserve ratio is
Reserve Ratio = allReserves / liabilities
and is implemented in Unitas#_getReserveStatus(...) function:allReserves
is the sum of the balance of Unitas and InsurancePool, calculated in Unitas#_getTotalReservesAndCollaterals() function:liabilities
is the total value of USD1 and USDEMC tokens, calculated in Unitas#_getTotalLiabilities() function:Some amount of USDT in both Unitas and InsurancePool is portfolio, which represents the current amount of assets used for strategic investments, it is worth noting that after sending portfolio,
balance
remains the same, which meansportfolio
is taken into account in the calculation of reserve ratio.This is problematic because
portfolio
is not available when user redeems, and user may not be able to fully redeem for USDT even when protocols says there is sufficient reserve ratio.Let's assume :
Later on, USDEMC appreciates upto 10% and we can get:
The available balance in Unitas is 8000 USD so there is 3000 USD in short, it needs to be obtain from InsurancePool, however, the available balance in InsurancePool is 2400 USD, transaction will be reverted and users cannot redeem.
There would also be an extreme situation when reserve ratio is above 100% but there is no available balance in protocol because all the
balance
isportfolio
(this is possible when InsurancePool is drained out), users cannot redeem any USDT in this case.Impact
Users may not be able to fully redeem USD1 into USDT even when reserve ratio is above 100%, this defeats the purpose of reserve ratio and breaks the promise of the protocol, users may be mislead and lose funds.
Code Snippet
https://github.com/sherlock-audit/2023-04-unitasprotocol/blob/main/Unitas-Protocol/src/Unitas.sol#L500-L535
Tool used
Manual Review
Recommendation
Portfolio should not be taken into account for the calculation of reserve ratio.