Closed code423n4 closed 1 year ago
JeffCX marked the issue as low quality report
0xean marked the issue as unsatisfactory: Insufficient quality
@0xean @LybraFinance
In the comments here, it clearly states here that:
the eUSD will be prioritized for distribution. Distributes earnings in the order of peUSD and other stablecoins if the eUSD balance is insufficient.
But in EUSD.transferShares
it calls the internal _transferShares
here
function transferShares(address _recipient, uint256 _sharesAmount) public returns (uint256) {
address owner = _msgSender();
-> _transferShares(owner, _recipient, _sharesAmount);
emit TransferShares(owner, _recipient, _sharesAmount);
uint256 tokensAmount = getMintedEUSDByShares(_sharesAmount);
emit Transfer(owner, _recipient, tokensAmount);
return tokensAmount;
}
This will revert here if owner
does not have enough shares, which contradicts the above mentioned comment:
function _transferShares(address _sender, address _recipient, uint256 _sharesAmount) internal {
require(_sender != address(0), "TRANSFER_FROM_THE_ZERO_ADDRESS");
require(_recipient != address(0), "TRANSFER_TO_THE_ZERO_ADDRESS");
uint256 currentSenderShares = shares[_sender];
-> require(_sharesAmount <= currentSenderShares, "TRANSFER_AMOUNT_EXCEEDS_BALANCE");
shares[_sender] = currentSenderShares.sub(_sharesAmount);
shares[_recipient] = shares[_recipient].add(_sharesAmount);
}
uint256 balance = EUSD.sharesOf(address(this));
uint256 eUSDShare = balance >= reward ? reward : reward - balance;
/// @audit if transferShares revert, getReward() will always revert
EUSD.transferShares(msg.sender, eUSDShare);
Please write a coded POC to show how you think this will revert. Otherwise, my judging is finalized here.
uint256 balance = EUSD.sharesOf(address(this)); uint256 eUSDShare = balance >= reward ? reward : reward - balance; /// @audit if transferShares revert, getReward() will always revert EUSD.transferShares(msg.sender, eUSDShare);
Please write a coded POC to show how you think this will revert. Otherwise, my judging is finalized here.
Hey @0xean sorry i missed that check u mentioned here, your judging is right and sorry for the confusion!
uint256 balance = EUSD.sharesOf(address(this));
-> uint256 eUSDShare = balance >= reward ? reward : reward - balance;
/// @audit if transferShares revert, getReward() will always revert
EUSD.transferShares(msg.sender, eUSDShare);
Lines of code
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/miner/ProtocolRewardsPool.sol#L197
Vulnerability details
Impact
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/miner/ProtocolRewardsPool.sol#L197
ProtocolRewardsPool.getReward()
will always revert if there is insufficient EUSD to send to borrower, never allowing the order of other earnings to be executed. This could possibly occur if EUSD contract is underfunded or if user has a low share balance due to transfers leading to high eUSD share of rewards. This unfairly prevents borrowers from receiving earnings in the form of peUSD or other approved stablecoins.Vulnerability Details
ProtocolRewards.getReward()
-->EUSD.transferShares()
--> reverts if contract have insufficient share balanceProtocolRewards.getReward()
-->peUSD.transfer
fails if peUSD contract has insufficient balanceProtocolRewards.getReward()
-->token.transfer
fails if other stable coin contract has insufficient balanceTools Used
Manual Analysis
Recommendation
Consider using a try catch block to catch failure of EUSD share transfer. If eusd transfer is unsucessful, cache reward remaining and allow logic of peUSD and other stable coin to occur.
Also consider allowing rewards claimer to claim up to contract balance and cache remaining rewards unclaimed instead of reverting if any of the other reward token contracts are underfunded (eUSD, peUSD, stablecoin).
Assessed type
DoS