Skip to content

Commit

Permalink
Removed smoothing to reduce contract size
Browse files Browse the repository at this point in the history
  • Loading branch information
asselstine committed Feb 13, 2024
1 parent 8cbf8aa commit 1ac4db0
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 134 deletions.
2 changes: 2 additions & 0 deletions src/abstract/TieredLiquidityDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

pragma solidity ^0.8.19;

import "forge-std/console2.sol";

import { SafeCast } from "openzeppelin/utils/math/SafeCast.sol";
import { SD59x18, sd } from "prb-math/SD59x18.sol";
import { UD60x18, ud, convert } from "prb-math/UD60x18.sol";
Expand Down
101 changes: 25 additions & 76 deletions src/libraries/DrawAccumulatorLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

pragma solidity ^0.8.19;

import "forge-std/console2.sol";

import { SafeCast } from "openzeppelin/utils/math/SafeCast.sol";
import { RingBufferLib } from "ring-buffer-lib/RingBufferLib.sol";

Expand Down Expand Up @@ -155,10 +157,11 @@ library DrawAccumulatorLib {
firstObservationDrawIdOccurringAtOrAfterStart = drawIds.first;
} else {
// The start must be between newest and oldest
uint24 beforeOrAtDrawId;
// binary search
(
,
,
beforeOrAtDrawId,
,
firstObservationDrawIdOccurringAtOrAfterStart
) = binarySearch(
Expand All @@ -168,98 +171,44 @@ library DrawAccumulatorLib {
ringBufferInfo.cardinality,
_startDrawId
);
if (beforeOrAtDrawId == _startDrawId) {
firstObservationDrawIdOccurringAtOrAfterStart = _startDrawId;
}
}

uint24 lastObservationDrawIdOccurringAtOrBeforeEnd;
if (_endDrawId >= drawIds.second || ringBufferInfo.cardinality == 1) {
// then it must be the end
lastObservationDrawIdOccurringAtOrBeforeEnd = drawIds.second;
} else {
(, lastObservationDrawIdOccurringAtOrBeforeEnd, ,) = binarySearch(
_accumulator.drawRingBuffer,
uint16(indexes.first),
uint16(indexes.second),
ringBufferInfo.cardinality,
_endDrawId
);
}

/*
uint24 lastObservationDrawIdOccurringAtOrBeforeEnd;
if (_endDrawId >= drawIds.second) {
// then it must be the end
lastObservationDrawIdOccurringAtOrBeforeEnd = drawIds.second;
} else if (_endDrawId == drawIds.first) {
// then it must be the first
lastObservationDrawIdOccurringAtOrBeforeEnd = drawIds.first;
} else if (_endDrawId == drawIds.second - 1) {
// then it must be the one before the end
// (we check this case since it is common and we want to avoid the extra binary search)
lastObservationDrawIdOccurringAtOrBeforeEnd = _accumulator.drawRingBuffer[
uint16(RingBufferLib.offset(indexes.second, 1, ringBufferInfo.cardinality))
];
} else {
// The last obs before or at end must be between newest and oldest
// binary search
(, uint24 beforeOrAtDrawId, , uint24 afterOrAtDrawId) = binarySearch(
uint24 afterOrAtDrawId;
(, lastObservationDrawIdOccurringAtOrBeforeEnd, ,afterOrAtDrawId) = binarySearch(
_accumulator.drawRingBuffer,
uint16(indexes.first),
uint16(indexes.second),
ringBufferInfo.cardinality,
_endDrawId
);
lastObservationDrawIdOccurringAtOrBeforeEnd = afterOrAtDrawId == _endDrawId
? afterOrAtDrawId
: beforeOrAtDrawId;
}
uint24 observationDrawIdBeforeOrAtStart;
uint24 firstObservationDrawIdOccurringAtOrAfterStart;
// if there is only one observation, or startId is after the newest record
if (_startDrawId >= drawIds.second) {
// then use the newest record
observationDrawIdBeforeOrAtStart = drawIds.second;
} else if (_startDrawId <= drawIds.first) {
// if the start is before the oldest record
// then set to the oldest record.
firstObservationDrawIdOccurringAtOrAfterStart = drawIds.first;
} else {
// The start must be between newest and oldest
// binary search
(
,
observationDrawIdBeforeOrAtStart,
,
firstObservationDrawIdOccurringAtOrAfterStart
) = binarySearch(
_accumulator.drawRingBuffer,
uint16(indexes.first),
uint16(indexes.second),
ringBufferInfo.cardinality,
_startDrawId
);
if (afterOrAtDrawId == _endDrawId) {
lastObservationDrawIdOccurringAtOrBeforeEnd = _endDrawId;
}
}
*/
// if at or after != at or before

/**
* 1. at or after start
* 2. if the start and end are different, then the total disbursed is the difference between the two
*/
Observation memory atOrAfterStart = _accumulator.observations[
firstObservationDrawIdOccurringAtOrAfterStart
];
// console2.log("atOrAfterStart drawId", firstObservationDrawIdOccurringAtOrAfterStart);
// console2.log("atOrAfterStart available", atOrAfterStart.available);
// console2.log("atOrAfterStart disbursed", atOrAfterStart.disbursed);

if (firstObservationDrawIdOccurringAtOrAfterStart == lastObservationDrawIdOccurringAtOrBeforeEnd) {
return _accumulator.observations[lastObservationDrawIdOccurringAtOrBeforeEnd].available;
} else {
Observation memory atOrAfterStart = _accumulator.observations[
firstObservationDrawIdOccurringAtOrAfterStart
];
Observation memory atOrBeforeEnd = _accumulator.observations[
lastObservationDrawIdOccurringAtOrBeforeEnd
];
Observation memory atOrBeforeEnd = _accumulator.observations[
lastObservationDrawIdOccurringAtOrBeforeEnd
];

return atOrBeforeEnd.available + atOrAfterStart.disbursed - atOrBeforeEnd.disbursed;
}
// console2.log("atOrBeforeEnd drawId", lastObservationDrawIdOccurringAtOrBeforeEnd);
// console2.log("atOrBeforeEnd available", atOrBeforeEnd.available);
// console2.log("atOrBeforeEnd disbursed", atOrBeforeEnd.disbursed);
return atOrBeforeEnd.available + atOrBeforeEnd.disbursed - atOrAfterStart.disbursed;
}

/// @notice Computes the first and last indices of observations for the given ring buffer info.
Expand Down
93 changes: 43 additions & 50 deletions test/PrizePool.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ contract PrizePoolTest is Test {
awardDraw(winningRandomNumber);

// reserve + remainder
assertEq(prizePool.reserve(), 1e18);
assertEq(prizePool.reserve(), 10e18);
}

event ClaimedPrize(
Expand All @@ -222,8 +222,8 @@ contract PrizePoolTest is Test {
contribute(100e18);
awardDraw(winningRandomNumber);

uint256 prizesPerShare = 10e18 / prizePool.getTotalShares();
uint256 remainder = 10e18 - prizesPerShare * prizePool.getTotalShares();
uint256 prizesPerShare = 100e18 / prizePool.getTotalShares();
uint256 remainder = 100e18 - prizesPerShare * prizePool.getTotalShares();

uint256 reserve = (prizesPerShare * RESERVE_SHARES) + remainder;

Expand Down Expand Up @@ -255,33 +255,26 @@ contract PrizePoolTest is Test {
function testReserve_withRemainder() public {
contribute(100e18);
awardDraw(winningRandomNumber);
assertEq(prizePool.reserve(), 0.322580645161290400e18);
assertEq(prizePool.reserve(), 3.22580645161290340e18);
}

function testPendingReserveContributions_noDraw() public {
contribute(100e18);
uint256 reserve = 0.322580645161290400e18;
assertEq(prizePool.pendingReserveContributions(), reserve);
awardDraw(winningRandomNumber);
assertEq(prizePool.reserve(), reserve);
uint256 firstPrizesPerShare = 100e18 / prizePool.getTotalShares();
uint256 remainder = 100e18 - (firstPrizesPerShare * prizePool.getTotalShares());
assertEq(prizePool.pendingReserveContributions(), remainder + (firstPrizesPerShare * RESERVE_SHARES));
}

function testPendingReserveContributions_existingDraw() public {
contribute(100e18);
uint256 firstPrizesPerShare = 10e18 / prizePool.getTotalShares();
// 0.322580645161290400 in reserve
awardDraw(winningRandomNumber);

// new liq + reclaimed canary
uint256 draw2Liquidity = 8999999999999998700;
// reclaim from two tiers
uint256 reclaimedLiquidity = (2 * TIER_SHARES * firstPrizesPerShare);
uint256 newLiquidity = draw2Liquidity + reclaimedLiquidity;
uint256 newPrizesPerShare = newLiquidity / prizePool.getTotalShares();
uint256 remainder = newLiquidity - newPrizesPerShare * prizePool.getTotalShares();
uint256 newReserve = (newPrizesPerShare * RESERVE_SHARES) + remainder;

assertEq(prizePool.pendingReserveContributions(), newReserve);
contribute(310e18);
uint256 firstPrizesPerShare = 310e18 / prizePool.getTotalShares();
uint256 remainder = 310e18 - (firstPrizesPerShare * prizePool.getTotalShares());
assertEq(prizePool.pendingReserveContributions(), remainder + (firstPrizesPerShare * RESERVE_SHARES), "pending reserve contributions");
awardDraw(winningRandomNumber);
// reclaim daily and canary => 200e18 reclaimed
uint reclaimedReserve = 200e18 * RESERVE_SHARES / prizePool.getTotalShares();
assertApproxEqAbs(prizePool.pendingReserveContributions(), reclaimedReserve, 1000, "no pending reserve contributions");
}

function testAllocateRewardFromReserve_notManager() public {
Expand Down Expand Up @@ -317,20 +310,20 @@ contract PrizePoolTest is Test {

function testGetTotalContributedBetween() public {
contribute(10e18);
assertEq(prizePool.getTotalContributedBetween(1, 1), 1e18);
assertEq(prizePool.getTotalContributedBetween(1, 1), 10e18);
}

function testGetTotalContributedBetween_oneBeforeLastContribution() public {
contribute(10e18); // 1
awardDraw(12345); // award 1
awardDraw(123456); // award 2
contribute(10e18); // 3
assertApproxEqAbs(prizePool.getTotalContributedBetween(1, 2), 19e17, 1000);
assertEq(prizePool.getTotalContributedBetween(1, 2), 10e18);
}

function testGetContributedBetween() public {
contribute(10e18);
assertEq(prizePool.getContributedBetween(address(this), 1, 1), 1e18);
assertEq(prizePool.getContributedBetween(address(this), 1, 1), 10e18);
}

function testGetTierAccrualDurationInDraws() public {
Expand All @@ -350,8 +343,8 @@ contract PrizePoolTest is Test {
// contribute and verify that contributions go to open draw (not awarding draw)
contribute(1e18);
assertEq(prizePool.getTotalContributedBetween(1, 1), 0);
assertEq(prizePool.getTotalContributedBetween(2, 2), 1e17); // e17 since smoothing is in effect
assertEq(prizePool.getTotalContributedBetween(1, 2), 1e17); // e17 since smoothing is in effect
assertEq(prizePool.getTotalContributedBetween(2, 2), 1e18); // e17 since smoothing is in effect
assertEq(prizePool.getTotalContributedBetween(1, 2), 1e18); // e17 since smoothing is in effect
}

function testContributePrizeTokens_notLostOnSkippedDraw() public {
Expand All @@ -367,9 +360,9 @@ contract PrizePoolTest is Test {
awardDraw(1234);

// check if tier liquidity includes contribution from draws 1 + 2
assertEq(prizePool.getTotalContributedBetween(1, 1), 31e18);
assertApproxEqAbs(prizePool.getTotalContributedBetween(2, 2), 279e17, 10000);
assertApproxEqAbs(prizePool.getTierRemainingLiquidity(0), 10e18 + 9e18, 10000);
assertEq(prizePool.getTotalContributedBetween(1, 1), 310e18);
assertEq(prizePool.getTotalContributedBetween(2, 2), 0);
assertEq(prizePool.getTierRemainingLiquidity(0), 100e18);
}

function testContributePrizeTokens_emitsEvent() public {
Expand All @@ -390,8 +383,8 @@ contract PrizePoolTest is Test {
// reserve = 10e18 * (10 / 310) = 0.3225806451612903e18
assertApproxEqAbs(
prizePool.reserve(),
(10e18 * RESERVE_SHARES) / prizePool.getTotalShares(),
100
(100e18 * RESERVE_SHARES) / prizePool.getTotalShares(),
200
);
prizePool.allocateRewardFromReserve(address(this), prizePool.reserve());
assertEq(prizePool.accountedBalance(), prizeToken.balanceOf(address(prizePool)));
Expand Down Expand Up @@ -613,8 +606,8 @@ contract PrizePoolTest is Test {
contribute(100e18);
awardDraw(winningRandomNumber);

uint256 liquidityPerShare = 10e18 / prizePool.getTotalShares();
uint256 remainder = 10e18 - liquidityPerShare * prizePool.getTotalShares();
uint256 liquidityPerShare = 100e18 / prizePool.getTotalShares();
uint256 remainder = 100e18 - liquidityPerShare * prizePool.getTotalShares();

assertEq(
fromUD34x4(prizePool.prizeTokenPerShare()),
Expand All @@ -625,7 +618,7 @@ contract PrizePoolTest is Test {
uint256 reserve = remainder + RESERVE_SHARES * liquidityPerShare;

assertEq(prizePool.reserve(), reserve, "reserve"); // remainder of the complex fraction
assertEq(prizePool.getTotalContributedBetween(1, 1), 10e18); // ensure not a single wei is lost!
assertEq(prizePool.getTotalContributedBetween(1, 1), 100e18); // ensure not a single wei is lost!
}

function testDrawIdPriorToShutdown_init() public {
Expand Down Expand Up @@ -722,23 +715,23 @@ contract PrizePoolTest is Test {
// we want shutdown draw id === draw id to award
vm.warp(prizePool.lastAwardedDrawAwardedAt() + drawTimeout*drawPeriodSeconds);
mockShutdownTwab(0.5e18, 1e18);
assertApproxEqAbs(prizePool.shutdownBalanceOf(address(this), msg.sender), 150e18, 10000);
assertEq(prizePool.shutdownBalanceOf(address(this), msg.sender), 150e18);
}

function testShutdownBalanceOf_shutdown_noDraws_withBalance_withContributions_multiple_claims() public {
contribute(100e18);
vm.warp(firstDrawOpensAt + drawPeriodSeconds + drawTimeout*drawPeriodSeconds);
mockShutdownTwab(0.5e18, 1e18);
vm.startPrank(msg.sender);
assertApproxEqAbs(prizePool.withdrawShutdownBalance(address(this), msg.sender), 50e18, 1000, "first claim");
assertEq(prizePool.withdrawShutdownBalance(address(this), msg.sender), 50e18, "first claim");
vm.stopPrank();

vm.warp(firstDrawOpensAt + drawPeriodSeconds + drawTimeout*drawPeriodSeconds + 49*drawPeriodSeconds);
contribute(100e18); // contributed to last closed draw. Means 10e18 is distributed to the next draw
vm.warp(firstDrawOpensAt + drawPeriodSeconds + drawTimeout*drawPeriodSeconds + 50*drawPeriodSeconds); // move forward 1 draw

// should be 50% of last amount
assertApproxEqAbs(prizePool.shutdownBalanceOf(address(this), msg.sender), 5e18, 1000, "second claim");
// should be 50% of last contribution
assertEq(prizePool.shutdownBalanceOf(address(this), msg.sender), 50e18, "second claim");
}

function testWithdrawShutdownBalance_notShutdown() public {
Expand Down Expand Up @@ -821,10 +814,10 @@ contract PrizePoolTest is Test {
function testTotalContributionsForClosedDraw_noClaims() public {
contribute(100e18);
awardDraw(winningRandomNumber);
assertEq(prizePool.getTotalContributedBetween(1, 1), 10e18, "first draw"); // 10e18
assertEq(prizePool.getTotalContributedBetween(1, 1), 100e18, "first draw"); // 10e18
awardDraw(winningRandomNumber);
// liquidity should carry over!
assertEq(prizePool.getTotalContributedBetween(2, 2), 8.999999999999998700e18, "second draw"); // 10e18 + 9e18
assertEq(prizePool.getTotalContributedBetween(2, 2), 0, "second draw");
}

function testAwardDraw_shouldNotShrinkOnFirst() public {
Expand Down Expand Up @@ -927,8 +920,8 @@ contract PrizePoolTest is Test {
245,
3,
4,
5612826466581395 /*reserve from output*/,
UD34x4.wrap(5612826466580940000) /*prize tokens per share from output*/,
34177045153614792 /*reserve from output*/,
UD34x4.wrap(34177045153614390000) /*prize tokens per share from output*/,
firstDrawOpensAt + drawPeriodSeconds
);
awardDraw(245);
Expand Down Expand Up @@ -963,7 +956,7 @@ contract PrizePoolTest is Test {
contribute(100e18);
awardDraw(winningRandomNumber);

uint256 tierLiquidity = TIER_SHARES * (10e18 / prizePool.getTotalShares());
uint256 tierLiquidity = TIER_SHARES * (100e18 / prizePool.getTotalShares());

assertEq(prizePool.getTierRemainingLiquidity(1), tierLiquidity, "second tier");

Expand All @@ -982,9 +975,9 @@ contract PrizePoolTest is Test {
function testGetRemainingTierLiquidity_allTiers() public {
contribute(310e18);
awardDraw(winningRandomNumber);
assertEq(prizePool.getTierRemainingLiquidity(0), 10e18);
assertEq(prizePool.getTierRemainingLiquidity(1), 10e18);
assertEq(prizePool.getTierRemainingLiquidity(2), 10e18);
assertEq(prizePool.getTierRemainingLiquidity(0), 100e18);
assertEq(prizePool.getTierRemainingLiquidity(1), 100e18);
assertEq(prizePool.getTierRemainingLiquidity(2), 100e18);
}

function testSetDrawManager() public {
Expand Down Expand Up @@ -1211,8 +1204,8 @@ contract PrizePoolTest is Test {
awardDraw(winningRandomNumber);
mockTwab(address(this), msg.sender, 0);
uint256 prize = prizePool.getTierPrizeSize(0);
vm.expectRevert(abi.encodeWithSelector(RewardTooLarge.selector, 10e18, prize));
claimPrize(msg.sender, 0, 0, 10e18, address(this));
vm.expectRevert(abi.encodeWithSelector(RewardTooLarge.selector, 100e18, prize));
claimPrize(msg.sender, 0, 0, 100e18, address(this));
}

function testClaimPrize_grandPrize_cannotClaimTwice() public {
Expand Down Expand Up @@ -1721,7 +1714,7 @@ contract PrizePoolTest is Test {

function mockShutdownTwab(uint256 userTwab, uint256 totalSupplyTwab) public {
(uint24 startDrawId, uint24 shutdownDrawId) = shutdownRangeDrawIds();
console2.log("mockShutdownTwab ", startDrawId, shutdownDrawId);
// console2.log("mockShutdownTwab ", startDrawId, shutdownDrawId);
mockTwabDrawRange(address(this), msg.sender, startDrawId, shutdownDrawId, userTwab);
mockTwabTotalSupplyDrawRange(address(this), startDrawId, shutdownDrawId, totalSupplyTwab);
}
Expand Down
Loading

0 comments on commit 1ac4db0

Please sign in to comment.