diff --git a/src/DrawManager.sol b/src/DrawManager.sol index 86c7f86..efda70a 100644 --- a/src/DrawManager.sol +++ b/src/DrawManager.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; +import "forge-std/console2.sol"; + import { PrizePool } from "pt-v5-prize-pool/PrizePool.sol"; import { IERC20 } from "openzeppelin/token/ERC20/IERC20.sol"; import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; @@ -332,38 +334,6 @@ contract DrawManager { return _lastStartDrawAuction; } - /// ================= Internal ================= - - /// @notice Checks if the auction has expired. - /// @param startedAt The time at which the auction started - /// @return True if the auction has expired, false otherwise - function _hasAuctionExpired(uint256 startedAt) internal view returns (bool) { - return uint48(block.timestamp - startedAt) > auctionDuration; - } - - /// @notice Allocates the reward to the recipient. - /// @param _recipient The recipient of the reward - /// @param _amount The amount of the reward - function _reward(address _recipient, uint256 _amount) internal { - if (_amount > 0) { - prizePool.allocateRewardFromReserve(_recipient, SafeCast.toUint96(_amount)); - } - } - - /// @notice Computes the rewards for the start and finish draw auctions. - /// @param _drawId The draw id to compute rewards for - /// @param _startDrawOccurredAt The time at which the start rng request occurred. Must be in the past. - /// @return rewards The computed rewards for the start and finish draw auctions - /// @return remainingReserve The remaining reserve after the rewards have been allocated - function _computeRewards(uint24 _drawId, uint256 _startDrawOccurredAt) internal view returns (uint256[] memory rewards, uint256 remainingReserve) { - uint totalReserve = prizePool.reserve() + prizePool.pendingReserveContributions(); - uint48 closesAt = prizePool.drawClosesAt(_drawId); - uint48 startDrawElapsedTime = _elapsedTimeSinceDrawClosed(_startDrawOccurredAt, closesAt); - uint48 finishDrawElapsedTime = uint48(block.timestamp - _startDrawOccurredAt); - - return computeRewards(startDrawElapsedTime, finishDrawElapsedTime, totalReserve); - } - /// @notice Computes the start draw and finish draw rewards. /// @param _startDrawElapsedTime The elapsed time between draw close and startDraw() /// @param _finishDrawElapsedTime The elapsed time between startDraw() and finishDraw() @@ -384,6 +354,15 @@ contract DrawManager { remainingReserve = _totalReserve - totalRewards; } + /// @notice Computes the start draw reward. + /// @param _startDrawElapsedTime The elapsed time between draw close and startDraw() + /// @param _totalReserve The total reserve available to allocate rewards from + /// @return reward The computed reward for start draw + function computeStartDrawReward(uint48 _startDrawElapsedTime, uint256 _totalReserve) public view returns (uint256) { + (uint256[] memory rewards,) = computeRewards(_startDrawElapsedTime, 0, _totalReserve); + return rewards[0]; + } + /// @notice Computes the reward fraction for the start draw auction. /// @param _elapsedTime The elapsed time since the draw closed in seconds /// @return The computed reward fraction for the start draw auction @@ -408,9 +387,41 @@ contract DrawManager { ); } + /// ================= Internal ================= + + /// @notice Checks if the auction has expired. + /// @param startedAt The time at which the auction started + /// @return True if the auction has expired, false otherwise + function _hasAuctionExpired(uint256 startedAt) internal view returns (bool) { + return uint48(block.timestamp - startedAt) > auctionDuration; + } + + /// @notice Allocates the reward to the recipient. + /// @param _recipient The recipient of the reward + /// @param _amount The amount of the reward + function _reward(address _recipient, uint256 _amount) internal { + if (_amount > 0) { + prizePool.allocateRewardFromReserve(_recipient, SafeCast.toUint96(_amount)); + } + } + + /// @notice Computes the rewards for the start and finish draw auctions. + /// @param _drawId The draw id to compute rewards for + /// @param _startDrawOccurredAt The time at which the start rng request occurred. Must be in the past. + /// @return rewards The computed rewards for the start and finish draw auctions + /// @return remainingReserve The remaining reserve after the rewards have been allocated + function _computeRewards(uint24 _drawId, uint256 _startDrawOccurredAt) internal view returns (uint256[] memory rewards, uint256 remainingReserve) { + uint totalReserve = prizePool.reserve() + prizePool.pendingReserveContributions(); + uint48 closesAt = prizePool.drawClosesAt(_drawId); + uint48 startDrawElapsedTime = _elapsedTimeSinceDrawClosed(_startDrawOccurredAt, closesAt); + uint48 finishDrawElapsedTime = uint48(block.timestamp - _startDrawOccurredAt); + + return computeRewards(startDrawElapsedTime, finishDrawElapsedTime, totalReserve); + } + /// @notice Calculates the elapsed time for the current RNG auction. /// @return The elapsed time since the start of the current RNG auction in seconds. - function _elapsedTimeSinceDrawClosed(uint256 _timestamp, uint256 _drawClosedAt) public pure returns (uint48) { + function _elapsedTimeSinceDrawClosed(uint256 _timestamp, uint256 _drawClosedAt) internal pure returns (uint48) { return uint48(_drawClosedAt < _timestamp ? _timestamp - _drawClosedAt : 0); } diff --git a/test/DrawManager.t.sol b/test/DrawManager.t.sol index 9af6a2b..106bf9f 100644 --- a/test/DrawManager.t.sol +++ b/test/DrawManager.t.sol @@ -302,6 +302,10 @@ contract DrawManagerTest is Test { drawManager.finishDraw(address(0)); } + function testComputeStartDrawRewardFraction() public { + assertEq(drawManager.computeStartDrawRewardFraction(auctionTargetTime).unwrap(), 0.1e18); + } + function testComputeRewards() public { UD2x18[] memory rewardFractions = new UD2x18[](2); rewardFractions[0] = UD2x18.wrap(0.5e18); @@ -311,6 +315,16 @@ contract DrawManagerTest is Test { assertEq(rewards[1], 20e18, "second reward"); } + function testComputeStartDrawReward_atZero() public { + // tiny amount at zero + assertEq(drawManager.computeStartDrawReward(0, 100e18), 280); + } + + function testComputeStartDrawReward_atTarget() public { + // tiny amount at zero + assertEq(drawManager.computeStartDrawReward(auctionTargetTime, 5e18), 0.5e18); + } + function startFirstDraw() public { vm.warp(1 days); mockReserve(1e18, 0);