Skip to content

Commit

Permalink
Limited tier changes to one per draw
Browse files Browse the repository at this point in the history
  • Loading branch information
asselstine committed Jan 30, 2024
1 parent 2133913 commit 1b4b5cd
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 39 deletions.
10 changes: 9 additions & 1 deletion src/PrizePool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,15 @@ contract PrizePool is TieredLiquidityDistributor, Ownable {
/// @return The estimated number of tiers + the canary tier
function _computeNextNumberOfTiers(uint32 _claimCount) internal view returns (uint8) {
// claimCount is expected to be the estimated number of claims for the current prize tier.
return _estimateNumberOfTiersUsingPrizeCountPerDraw(_claimCount) + 1;
uint8 nextNumberOfTiers = _estimateNumberOfTiersUsingPrizeCountPerDraw(_claimCount) + 1;
// limit change to 1 tier
uint8 _numTiers = numberOfTiers;
if (nextNumberOfTiers > _numTiers) {
nextNumberOfTiers = _numTiers + 1;
} else if (nextNumberOfTiers < _numTiers) {
nextNumberOfTiers = _numTiers - 1;
}
return nextNumberOfTiers;
}

/// @notice Calculates the number of tiers given the number of prize claims
Expand Down
26 changes: 15 additions & 11 deletions src/abstract/TieredLiquidityDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@ contract TieredLiquidityDistributor {
// need to redistribute to the canary tier and any new tiers (if expanding)
uint8 start;
uint8 end;
uint8 shares = tierShares;
// if we are shrinking, we need to reclaim including the new canary tier
if (_nextNumberOfTiers < _numberOfTiers) {
start = _nextNumberOfTiers - 1;
Expand All @@ -263,7 +262,6 @@ contract TieredLiquidityDistributor {
for (uint8 i = start; i < end; i++) {
reclaimedLiquidity = reclaimedLiquidity.add(
_getTierRemainingLiquidity(
shares,
fromUD34x4toUD60x18(_tiers[i].prizeTokenPerShare),
_currentPrizeTokenPerShare
)
Expand Down Expand Up @@ -350,7 +348,6 @@ contract TieredLiquidityDistributor {
uint104 remainingLiquidity = SafeCast.toUint104(
convert(
_getTierRemainingLiquidity(
_shares,
fromUD34x4toUD60x18(_tierStruct.prizeTokenPerShare),
fromUD34x4toUD60x18(prizeTokenPerShare)
)
Expand Down Expand Up @@ -443,35 +440,42 @@ contract TieredLiquidityDistributor {
/// @notice Computes the remaining liquidity available to a tier.
/// @param _tier The tier to compute the liquidity for
/// @return The remaining liquidity
function getTierRemainingLiquidity(uint8 _tier) external view returns (uint256) {
uint8 _numTiers = numberOfTiers;
function getTierRemainingLiquidity(uint8 _tier) public view returns (uint256) {
return _getTierRemainingLiquidity(_tier, fromUD34x4toUD60x18(prizeTokenPerShare));
}

/// @notice Computes the remaining liquidity available to a tier.
/// @param _tier The tier to compute the liquidity for
/// @param _prizeTokenPerShare The global prizeTokenPerShare
/// @return The remaining liquidity
function _getTierRemainingLiquidity(
uint8 _tier,
UD60x18 _prizeTokenPerShare
) internal view returns (uint256) {
uint8 _numTiers = numberOfTiers;
return
!TierCalculationLib.isValidTier(_tier, _numTiers)
? 0
: convert(
_getTierRemainingLiquidity(
tierShares,
fromUD34x4toUD60x18(_getTier(_tier, _numTiers).prizeTokenPerShare),
fromUD34x4toUD60x18(prizeTokenPerShare)
_prizeTokenPerShare
)
);
}

/// @notice Computes the remaining tier liquidity.
/// @param _shares The number of shares that the tier has (can be tierShares or canaryShares)
/// @param _tierPrizeTokenPerShare The prizeTokenPerShare of the Tier struct
/// @param _prizeTokenPerShare The global prizeTokenPerShare
/// @return The remaining available liquidity
function _getTierRemainingLiquidity(
uint256 _shares,
UD60x18 _tierPrizeTokenPerShare,
UD60x18 _prizeTokenPerShare
) internal pure returns (UD60x18) {
) internal view returns (UD60x18) {
return
_tierPrizeTokenPerShare.gte(_prizeTokenPerShare)
? ud(0)
: _prizeTokenPerShare.sub(_tierPrizeTokenPerShare).mul(convert(_shares));
: _prizeTokenPerShare.sub(_tierPrizeTokenPerShare).mul(convert(tierShares));
}

/// @notice Estimates the number of prizes for the current number of tiers, including the canary tier
Expand Down
40 changes: 28 additions & 12 deletions test/PrizePool.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,13 @@ contract PrizePoolTest is Test {

contribute(510e18);

assertEq(prizePool.estimateNextNumberOfTiers(), 3, "will reduce to 3");
assertEq(prizePool.estimateNextNumberOfTiers(), 4, "will reduce to 4");

// first draw (same num tiers)
// total for first draw = 0.1 * 510e18 = 51e18
// 5th tier (canary tier) = (100/510)*51e18 = 10e18
// 4th tier (daily tier) = (100/510)*51.18 = 10e18
// reserve = 51e18 * (10 / 510) = 1e18
awardDraw(1234);

assertEq(prizePool.reserve(), 1e18, "reserve after first draw");
Expand All @@ -637,24 +642,28 @@ contract PrizePoolTest is Test {
2,
4567,
startingTiers,
3,
3448387096774193470 /*reserve from output*/,
UD34x4.wrap(3448387096774193330000) /*prize tokens per share from output*/,
4, // change is limited to 1 tier
2607317073170731770 /*reserve from output*/,
UD34x4.wrap(2607317073170731540000) /*prize tokens per share from output*/,
firstDrawOpensAt + drawPeriodSeconds
);

// award second draw
// reclaimed tiers: 10e18 + 10e18 = 20e18
// liquidity for second draw = 0.1 * (510e18 - 51e18) + 20e18 = 65.9e18
// reserve for second draw = 65.9e18 * (10 / 410) = 1607317073170731800
// total reserve = 1e18 + 1607317073170731800 = 2607317073170732000
awardDraw(4567);

assertEq(prizePool.numberOfTiers(), 3, "number of tiers");
assertEq(prizePool.numberOfTiers(), 4, "number of tiers");

// two tiers + canary tier = 30e18
// total liquidity for second draw is 45.9e18
// new liquidity for second draw = 75.9e18
// reserve for second draw = (10/310)*75.9e18 = 2.445e18
// total reserve = 3.445e18

assertEq(prizePool.reserve(), 3.44838709677419347e18, "size of reserve");
assertEq(prizePool.reserve(), 2607317073170731770, "size of reserve");
}

function testAwardDraw_expandingTiers() public {
Expand Down Expand Up @@ -1003,19 +1012,26 @@ contract PrizePoolTest is Test {
assertEq(prizePool.computeNextNumberOfTiers(24), 4);
}

function testComputeNextNumberOfTiers_beyondMinimum() public {
function testComputeNextNumberOfTiers_beyondMinimum_maxIncreaseBy1() public {
// canary prizes were taken for tier 4!
assertEq(prizePool.computeNextNumberOfTiers(80), 5);
// should crank up to 5, but limit increasee to 1
assertEq(prizePool.computeNextNumberOfTiers(80), 4);
}

function testComputeNextNumberOfTiers_beyondMinimum_bigDeviation() public {
function testComputeNextNumberOfTiers_beyondMinimum_bigDeviation_maxIncreaseBy1() public {
// half the canary prizes were taken
assertEq(prizePool.computeNextNumberOfTiers(150), 5);
assertEq(prizePool.computeNextNumberOfTiers(150), 4);
}

function testComputeNextNumberOfTiers_beyondMinimum_nextLevelUp() public {
function testComputeNextNumberOfTiers_beyondMinimum_nextLevelUp_maxIncreaseBy1() public {
// half the canary prizes were taken
assertEq(prizePool.computeNextNumberOfTiers(200), 6);
assertEq(prizePool.computeNextNumberOfTiers(200), 4);
}

function testComputeNextNumberOfTiers_drop_maxDecreaseBy1() public {
params.numberOfTiers = 5;
prizePool = new PrizePool(params);
assertEq(prizePool.computeNextNumberOfTiers(0), 4);
}

function testClaimPrize_secondTier_claimTwice() public {
Expand Down
44 changes: 44 additions & 0 deletions test/abstract/TieredLiquidityDistributor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,36 @@ contract TieredLiquidityDistributorTest is Test {
distributor.awardDraw(1, 100);
}

function testAwardDraw_liquidity_shrinkTiers1() public {
distributor.awardDraw(5, 100e18);
distributor.awardDraw(4, 100e18);
assertEq(_computeLiquidity(), 200e18);
}

function testAwardDraw_liquidity_shrinkTiers2() public {
distributor.awardDraw(5, 100e18);
distributor.awardDraw(3, 100e18);
assertEq(_computeLiquidity(), 200e18);
}

function testAwardDraw_liquidity_sameTiers() public {
distributor.awardDraw(5, 100e18);
distributor.awardDraw(5, 100e18);
assertEq(_computeLiquidity(), 200e18);
}

function testAwardDraw_liquidity_growTiers1() public {
distributor.awardDraw(5, 100e18);
distributor.awardDraw(6, 100e18);
assertEq(_computeLiquidity(), 200e18);
}

function testAwardDraw_liquidity_growTiers2() public {
distributor.awardDraw(5, 100e18);
distributor.awardDraw(7, 100e18);
assertEq(_computeLiquidity(), 200e18);
}

function testConstructor_numberOfTiersTooLarge() public {
vm.expectRevert(abi.encodeWithSelector(NumberOfTiersGreaterThanMaximum.selector, 16));
new TieredLiquidityDistributorWrapper(16, tierShares, reserveShares, 365);
Expand Down Expand Up @@ -295,4 +325,18 @@ contract TieredLiquidityDistributorTest is Test {
summed += distributor.reserve();
return summed;
}

function _computeLiquidity() internal view returns (uint256) {
uint256 liquidity = _getTierLiquidity(distributor.numberOfTiers(), fromUD34x4toUD60x18(distributor.prizeTokenPerShare()));
liquidity += distributor.reserve();
return liquidity;
}

function _getTierLiquidity(uint8 _numberOfTiers, UD60x18 _prizeTokenPerShare) internal view returns (uint256) {
uint256 liquidity = 0;
for (uint8 i = 0; i < _numberOfTiers; i++) {
liquidity += distributor.getTierRemainingLiquidity(i, _prizeTokenPerShare);
}
return liquidity;
}
}
45 changes: 33 additions & 12 deletions test/abstract/helper/TieredLiquidityDistributorWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.19;
import "forge-std/console2.sol";

import { TieredLiquidityDistributor, Tier, fromUD34x4toUD60x18, convert } from "../../../src/abstract/TieredLiquidityDistributor.sol";
import { UD60x18 } from "prb-math/UD60x18.sol";

contract TieredLiquidityDistributorWrapper is TieredLiquidityDistributor {
constructor(
Expand All @@ -25,18 +26,33 @@ contract TieredLiquidityDistributorWrapper is TieredLiquidityDistributor {
}

function remainingTierLiquidity(uint8 _tier) external view returns (uint112) {
uint8 shares = tierShares;
Tier memory tier = _getTier(_tier, numberOfTiers);
return
uint112(
convert(
_getTierRemainingLiquidity(
shares,
fromUD34x4toUD60x18(tier.prizeTokenPerShare),
fromUD34x4toUD60x18(prizeTokenPerShare)
)
)
);
return uint112(getTierRemainingLiquidity(_tier));
// uint8 shares = tierShares;
// Tier memory tier = _getTier(_tier, numberOfTiers);
// return
// uint112(
// convert(
// _getTierRemainingLiquidity(
// fromUD34x4toUD60x18(tier.prizeTokenPerShare),
// fromUD34x4toUD60x18(prizeTokenPerShare)
// )
// )
// );
}

function computeNewDistributions(
uint8 _numberOfTiers,
uint8 _nextNumberOfTiers,
UD60x18 _currentPrizeTokenPerShare,
uint256 _prizeTokenLiquidity
) external view returns (uint96, UD60x18) {
(uint96 newReserve, UD60x18 newPrizeTokenPerShare) = _computeNewDistributions(
_numberOfTiers,
_nextNumberOfTiers,
_currentPrizeTokenPerShare,
_prizeTokenLiquidity
);
return (newReserve, newPrizeTokenPerShare);
}

function estimateNumberOfTiersUsingPrizeCountPerDraw(
Expand All @@ -50,4 +66,9 @@ contract TieredLiquidityDistributorWrapper is TieredLiquidityDistributor {
uint32 result = _sumTierPrizeCounts(_numTiers);
return result;
}

function getTierRemainingLiquidity(uint8 _tier, UD60x18 _prizeTokenPerShare) external view returns (uint256) {
uint256 result = _getTierRemainingLiquidity(_tier, _prizeTokenPerShare);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ contract TieredLiquidityDistributorFuzzHarness is TieredLiquidityDistributor {
Tier memory tier = _getTier(i, numberOfTiers);
availableLiquidity += convert(
_getTierRemainingLiquidity(
tierShares,
fromUD34x4toUD60x18(tier.prizeTokenPerShare),
fromUD34x4toUD60x18(prizeTokenPerShare)
)
Expand All @@ -43,11 +42,9 @@ contract TieredLiquidityDistributorFuzzHarness is TieredLiquidityDistributor {
uint8 tier = _tier % numberOfTiers;

Tier memory tier_ = _getTier(tier, numberOfTiers);
uint8 shares = tierShares;
uint104 liq = uint104(
convert(
_getTierRemainingLiquidity(
shares,
fromUD34x4toUD60x18(tier_.prizeTokenPerShare),
fromUD34x4toUD60x18(prizeTokenPerShare)
)
Expand Down

0 comments on commit 1b4b5cd

Please sign in to comment.