Closed sherlock-admin3 closed 6 months ago
Not relevant imho
1 comment(s) were left on this issue during the judging contest.
panprog commented:
invalid. Please report each issue independantly next time. Problem 1: The recepients list is supposed to be pretty small, just some trusted addresses set by the admins, so this is by-design. The gas problem is purely speculation: if the recepients list is small, there is no problem with it. Problem 2: since recipients are set by trusted admin, the addresses are highly unlikely to become blacklisted, but even if it happens, there is no problem for the admin to update the recepients to fix this issue. Problem 3: Don't see any problem or impact here. If distributedAsset is updated, all the calculations are kept from the previous one, just everything is now paid in a different asset. No problem there.
Timenov
medium
Bad implementation of yield distribution can leave users with no yield.
Summary
Yield can be distributed by calling
ZivoeYDL::distributeYield
. This can be called by anyone as long asunlocked == true
andblock.timestamp >= lastDistribution + daysBetweenDistributions * 86400
. Then the function will senddistributedAsset
to all addresses part ofprotocolRecipients
andresidualRecipients
. Several problems can occur because of bad implementation.Vulnerability Detail
I will list 3 problems that will break the logic(listed by most likely to happen).
Problem 1(Out of gas)
This function is pretty big. It has 2 for loops that iterate over
protocolRecipients
andresidualRecipients
. In each iteration several calls are performed likesafeIncreaseAllowance
,depositReward
,safeTransfer
and many others. Alsorequire
statements and math operations. This easily can run out of gas.Yes, there is a function
updateRecipients
that will updatedprotocolRecipients
andresidualRecipients
, but still the issue is there. Lets say that call fails with 100 recipients. The recipients are split by 2, so now we have 2 groups of 50. The first will receive their yield, but the second group will have to wait more time. This can happen multiple times, not only once.Problem 2(User can not receive
distributedAsset
)If a user that is part of either
protocolRecipients
orresidualRecipients
can not receivedistributedAsset
(e.g. part of USDC blacklist), the function will fail and no one will receive yield.Problem 3(User blocking distribution by changing
lastDistribution
)Lets say DAI was
distributedAsset
and is successfully sent to everyone. Now the next will beUSDC
. However it is still not updated, but theblock.timestamp >= lastDistribution + daysBetweenDistributions * 86400
is passed. Now DAI will still be thedistributedAsset
, but the balance will be 0. User can calldistributeYield
just to increase thelastDistribution
in order to block yield distribution to a certain period.Impact
Yield distribution will be blocked.
Code Snippet
https://github.com/sherlock-audit/2024-03-zivoe/blob/main/zivoe-core-foundry/src/ZivoeYDL.sol#L213-L311
Tool used
Manual Review
Recommendation
Consider implementing the following changes:
Problem 1 fix:
Use
pull over push
. Add mapping that will keep track of yield for each user. Add another function that users will call to get their yield.Problem 2 fix:
Add parameter
recipient
to the new function, that will allow blacklisted users to send their yield to the address.Problem 3 fix:
Add a check to verify that
distributedAsset
is different from the previous one or restrict only trusted entities to call that function.