Open sherlock-admin opened 1 year ago
Possibly a high severity
Given that this applies only for tokens with lower decimals considering this a valid medium
Escalate for 10 USDC,
Given that this applies only for tokens with lower decimals considering this a valid medium
This indeed holds when underlying token has lower decimals such as USDC. But given the popularity of USDC, it is likely that it will be the most used asset as the underlying.
What makes it less likely is if price()
needs to be of lower precision as stated at the beginning of the report
However this does not only hold when price()
has low decimals as stated in the report, because priceDiff
on nominator
has the same precision as lastPrices[protocolId]
on denominator, and thus the precision of the price does not change the result of the division.
This means that the example holds for all protocols, and the severity can be high
Escalate for 10 USDC,
Given that this applies only for tokens with lower decimals considering this a valid medium
This indeed holds when underlying token has lower decimals such as USDC. But given the popularity of USDC, it is likely that it will be the most used asset as the underlying.
What makes it less likely is if
price()
needs to be of lower precision as stated at the beginning of the reportHowever this does not only hold when
price()
has low decimals as stated in the report, becausepriceDiff
onnominator
has the same precision aslastPrices[protocolId]
on denominator, and thus the precision of the price does not change the result of the division.This means that the example holds for all protocols, and the severity can be high
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.
Escalation accepted
Based on both the Sponsor comment and escalation, after further consideration, the impact of this issue is a valid high.
Escalation accepted
Based on both the Sponsor comment and escalation, after further consideration, this issue can be flagged as valid high.
This issue's escalations have been accepted!
Contestants' payouts and scores will be updated according to the changes made on this issue.
Escalation accepted
Based on both the Sponsor comment and escalation, after further consideration, the impact of this issue is a valid high.
This issue's escalations have been accepted!
Contestants' payouts and scores will be updated according to the changes made on this issue.
Fix looks ok, but it looks like an update in addToTotalRewards()
is also needed:
- int256 allocation = basketAllocationInProtocol(_basketId, chain, i) / 1E18;
- if (allocation == 0) continue;
+ int256 allocation = basketAllocationInProtocol(_basketId, chain, i);
+ if (allocation / BASE_SCALE == 0) continue;
Also, due to further changes the fix-review branch needs a couple of additional updates:
- // threshold in vaultCurrency e.g USDC for when user tokens will be sold / burned. Must be negative
+ // threshold in vaultCurrency.decimals() * BASE_SCALE of 1e18 e.g 10 ^ (6 + 18) for USDC for when user tokens will be sold / burned. Must be negative
int256 internal negativeRewardThreshold;
/// @notice Setter for threshold at which user tokens will be sold / burned
- /// @param _threshold treshold in vaultCurrency e.g USDC, must be negative
+ /// @param _threshold treshold in vaultCurrency.decimals() * BASE_SCALE of 1e18 e.g 10 ^ (6 + 18) for USDC, must be negative
function setNegativeRewardThreshold(int256 _threshold) external onlyDao {
negativeRewardThreshold = _threshold;
}
hyh
medium
Vault can lose rewards due to lack of precision
Summary
Vault's storePriceAndRewards() can accrue no rewards as precision can be lost when price() has low decimals.
For example, price() has 6 decimals for Idle USDC and USDT strategies.
Vulnerability Detail
Suppose storePriceAndRewards() is called for Idle USDC protocol, this USDC Vault is relatively new and
Totalunderlying = TotalUnderlyingInProtocols - BalanceVault = USD 30k
, performance fee is5%
and it's1 mln
Derby tokens staked, i.e.totalAllocatedTokens = 1_000_000 * 1e18
, whilelastPrices[_protocolId] = 1_100_000
(which is1.1 USDC
, Idle has price scaled by underlying decimals and tracks accumulated strategy share price).Let's say this provider shows stable returns with
1.7% APY
, suppose market rates are low and this is somewhat above market. In bi-weekly terms it can correspond topriceDiff = 730
, as, roughly excluding price appreciation that doesn't influence much here,(730.0 / 1100000 + 1)**26 - 1 = 1.7%
.In this case
rewardPerLockedToken
will be30000 * 10**6 * 5 * 730 / (1_000_000 * 1_100_000 * 100) = 0
for all rebalancing periods, i.e. no rewards at all will be allocated for the protocol despite it having positive performance.Impact
Rewards can be lost for traders who allocated to protocols where price() has low decimals.
Code Snippet
Vault's storePriceAndRewards() calculates strategy performance reward as
nominator / denominator
, wherenominator = _totalUnderlying * performanceFee * priceDiff
:https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Vault.sol#L220-L245
price() is Provider's exchangeRate():
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Vault.sol#L381-L390
IdleProvider's exchangeRate() is scaled with underlying token decimals:
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/IdleProvider.sol#L113-L118
https://github.com/Idle-Labs/idle-contracts/blob/develop/contracts/IdleTokenV3_1.sol#L240-L245
Tool used
Manual Review
Recommendation
Consider enhancing performance of the rewards calculation and Game's
baskets[_basketId].totalUnRedeemedRewards
, for example:https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Vault.sol#L46-L47
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Vault.sol#L220-L245
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Game.sol#L69-L70
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Game.sol#L296-L306
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Game.sol#L542-L553
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Game.sol#L19-L32