Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions solidity/contracts/YieldVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,25 @@ contract YieldVault {
rewardDistributor = msg.sender;
}

// BUG: Does not cap at periodFinish — accrues phantom rewards after period ends
// FIX: Cap calculation at periodFinish to prevent phantom rewards
function rewardPerToken() public view returns (uint256) {
if (totalSupply == 0) return rewardPerTokenStored;

uint256 endTime = block.timestamp < periodFinish ? block.timestamp : periodFinish;
uint256 timeDelta = endTime - lastUpdateTime;

return rewardPerTokenStored + (
(block.timestamp - lastUpdateTime) * rewardRate * 1e18 / totalSupply
timeDelta * rewardRate * 1e18 / totalSupply
);
}

// BUG: Uses uncapped rewardPerToken
function earned(address account) public view returns (uint256) {
return balanceOf[account] * (rewardPerToken() - userRewardPerTokenPaid[account]) / 1e18 + rewards[account];
}

modifier updateReward(address account) {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = block.timestamp;
lastUpdateTime = block.timestamp < periodFinish ? block.timestamp : periodFinish;
if (account != address(0)) {
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
Expand Down Expand Up @@ -77,9 +80,9 @@ contract YieldVault {
}
}

// BUG: No access control — anyone can call
// BUG: Precision loss in rewardRate calculation
// FIX: Added access control
function notifyRewardAmount(uint256 reward, uint256 duration) external updateReward(address(0)) {
require(msg.sender == rewardDistributor, "Not distributor");
rewardRate = reward / duration;
lastUpdateTime = block.timestamp;
periodFinish = block.timestamp + duration;
Expand Down
Loading