-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(contracts): add PrizeConfigHistory
- Loading branch information
1 parent
a3bafe5
commit 78164ce
Showing
4 changed files
with
286 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
|
||
pragma solidity 0.8.6; | ||
|
||
import "@pooltogether/owner-manager-contracts/contracts/Manageable.sol"; | ||
import "@pooltogether/v4-periphery/contracts/libraries/BinarySearchLib.sol"; | ||
|
||
import "./interfaces/IPrizeConfigHistory.sol"; | ||
|
||
/** | ||
* @title PoolTogether V4 PrizeConfigHistory | ||
* @author PoolTogether Inc Team | ||
* @notice Contract to store prize configurations | ||
*/ | ||
contract PrizeConfigHistory is IPrizeConfigHistory, Manageable { | ||
/// @dev The uint32[] type is extended with a binarySearch(uint32) function. | ||
using BinarySearchLib for uint32[]; | ||
|
||
/* ============ Variables ============ */ | ||
|
||
/** | ||
* @notice Ordered array of Draw IDs. | ||
* @dev The history, with sequentially ordered ids, can be searched using binary search. | ||
The binary search will find index of a drawId (atOrBefore) using a specific drawId (at). | ||
When a new Draw ID is added to the history, a corresponding mapping of the ID is | ||
updated in the prizeConfigs mapping. | ||
*/ | ||
uint32[] internal history; | ||
|
||
/** | ||
* @notice Mapping of Draw ID to PrizeConfig struct. | ||
* @dev drawId -> PrizeConfig | ||
* @dev The prizeConfigs mapping is updated when a new Draw ID is added to the history. | ||
*/ | ||
mapping(uint32 => PrizeConfig) internal prizeConfigs; | ||
|
||
/* ============ Events ============ */ | ||
|
||
/** | ||
* @notice Emit when a new PrizeConfig is added to history | ||
* @param drawId Draw ID at which the PrizeConfig was pushed and is since valid | ||
* @param prizeConfig PrizeConfig struct | ||
*/ | ||
event PrizeConfigPushed(uint32 indexed drawId, PrizeConfig prizeConfig); | ||
|
||
/** | ||
* @notice Emit when existing PrizeConfig is updated in history | ||
* @param drawId Draw ID at which the PrizeConfig was set and is since valid | ||
* @param prizeConfig PrizeConfig struct | ||
*/ | ||
event PrizeConfigSet(uint32 indexed drawId, PrizeConfig prizeConfig); | ||
|
||
/* ============ Constructor ============ */ | ||
|
||
/** | ||
* @notice PrizeConfigHistory constructor | ||
* @param _owner Address of the owner | ||
*/ | ||
constructor(address _owner) Ownable(_owner) {} | ||
|
||
/* ============ External Functions ============ */ | ||
|
||
/// @inheritdoc IPrizeConfigHistory | ||
function count() external view override returns (uint256) { | ||
return history.length; | ||
} | ||
|
||
/// @inheritdoc IPrizeConfigHistory | ||
function getNewestDrawId() external view override returns (uint32) { | ||
return history[history.length - 1]; | ||
} | ||
|
||
/// @inheritdoc IPrizeConfigHistory | ||
function getOldestDrawId() external view override returns (uint32) { | ||
return history[0]; | ||
} | ||
|
||
/// @inheritdoc IPrizeConfigHistory | ||
function getPrizeConfig(uint32 _drawId) | ||
external | ||
view | ||
override | ||
returns (PrizeConfig memory prizeConfig) | ||
{ | ||
require(_drawId > 0, "PrizeConfHistory/draw-id-gt-zero"); | ||
return prizeConfigs[history.binarySearch(_drawId)]; | ||
} | ||
|
||
/// @inheritdoc IPrizeConfigHistory | ||
function getPrizeConfigAtIndex(uint256 _index) | ||
external | ||
view | ||
override | ||
returns (PrizeConfig memory prizeConfig) | ||
{ | ||
return prizeConfigs[uint32(_index)]; | ||
} | ||
|
||
// @inheritdoc IPrizeConfigHistory | ||
function getPrizeConfigList(uint32[] calldata _drawIds) | ||
external | ||
view | ||
override | ||
returns (PrizeConfig[] memory prizeConfigList) | ||
{ | ||
uint256 _length = _drawIds.length; | ||
PrizeConfig[] memory _data = new PrizeConfig[](_length); | ||
|
||
for (uint256 index = 0; index < _length; index++) { | ||
_data[index] = prizeConfigs[history.binarySearch(_drawIds[index])]; | ||
} | ||
|
||
return _data; | ||
} | ||
|
||
/// @inheritdoc IPrizeConfigHistory | ||
function popAndPush(PrizeConfig calldata _newPrizeConfig) | ||
external | ||
override | ||
onlyOwner | ||
returns (uint32) | ||
{ | ||
uint256 length = history.length; | ||
|
||
require(length > 0, "PrizeConfHistory/history-empty"); | ||
require(history[length - 1] == _newPrizeConfig.drawId, "PrizeConfHistory/invalid-draw-id"); | ||
|
||
_replace(_newPrizeConfig); | ||
|
||
return _newPrizeConfig.drawId; | ||
} | ||
|
||
/// @inheritdoc IPrizeConfigHistory | ||
function push(PrizeConfig calldata _nextPrizeConfig) external override onlyManagerOrOwner { | ||
_push(_nextPrizeConfig); | ||
} | ||
|
||
/// @inheritdoc IPrizeConfigHistory | ||
function replace(PrizeConfig calldata _newPrizeConfig) external override onlyOwner { | ||
_replace(_newPrizeConfig); | ||
} | ||
|
||
/* ============ Internal Functions ============ */ | ||
|
||
/** | ||
* @notice Push PrizeConfigHistory struct onto history array. | ||
* @param _prizeConfig New PrizeConfig struct to push onto history array | ||
*/ | ||
function _push(PrizeConfig memory _prizeConfig) internal { | ||
uint32 _historyLength = uint32(history.length); | ||
|
||
if (_historyLength > 0) { | ||
// TODO: Check if cheaper in gas to only cast to uint32 below | ||
uint32 _id = history[_historyLength - 1]; | ||
|
||
require(_prizeConfig.drawId > _id, "PrizeConfHistory/nonsequentialId"); | ||
} | ||
|
||
history.push(_prizeConfig.drawId); | ||
prizeConfigs[_historyLength] = _prizeConfig; | ||
|
||
emit PrizeConfigPushed(_prizeConfig.drawId, _prizeConfig); | ||
} | ||
|
||
/** | ||
* @notice Replace PrizeConfig struct from history array. | ||
* @dev Performs a binary search to find which index in the history array contains the drawId to replace. | ||
* @param _prizeConfig New PrizeConfig struct that will replace the previous PrizeConfig at the corresponding index. | ||
*/ | ||
function _replace(PrizeConfig calldata _prizeConfig) internal { | ||
require(history.length > 0, "PrizeConfHistory/no-prize-conf"); | ||
|
||
uint32 oldestDrawId = history[0]; | ||
require(_prizeConfig.drawId >= oldestDrawId, "PrizeConfHistory/drawId-beyond"); | ||
|
||
uint32 index = history.binarySearch(_prizeConfig.drawId); | ||
require(history[index] == _prizeConfig.drawId, "PrizeConfHistory/drawId-mismatch"); | ||
|
||
prizeConfigs[index] = _prizeConfig; | ||
emit PrizeConfigSet(_prizeConfig.drawId, _prizeConfig); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
|
||
pragma solidity 0.8.6; | ||
|
||
/** | ||
* @title PoolTogether V4 IPrizeConfigHistory | ||
* @author PoolTogether Inc Team | ||
* @notice IPrizeConfigHistory is the base contract for PrizeConfigHistory | ||
*/ | ||
interface IPrizeConfigHistory { | ||
/** | ||
* @notice PrizeConfig struct read every draw. | ||
* @param bitRangeSize Number of bits in decimal allocated to each division | ||
* @param matchCardinality Number of numbers to consider in the 256 bit random number. Must be > 1 and < 256/bitRangeSize. | ||
* @param maxPicksPerUser Maximum number of picks a user can make in this draw | ||
* @param drawId Draw ID at which the PrizeConfig was pushed and is since valid | ||
* @param expiryDuration Length of time in seconds the PrizeDistribution is valid for. Relative to the Draw.timestamp. | ||
* @param endTimestampOffset The end time offset in seconds from which Ticket balances are calculated. | ||
* @param poolStakeCeiling Total globally configured POOL staking ceiling | ||
* @param prize Total prize amount available for this draw | ||
* @param tiers Array of prize tiers percentages, expressed in fraction form with base 1e9. Ordering: index0: grandPrize, index1: runnerUp, etc. | ||
*/ | ||
struct PrizeConfig { | ||
uint8 bitRangeSize; | ||
uint8 matchCardinality; | ||
uint16 maxPicksPerUser; | ||
uint32 drawId; | ||
uint32 expiryDuration; | ||
uint32 endTimestampOffset; | ||
uint128 poolStakeCeiling; | ||
uint256 prize; | ||
uint32[16] tiers; | ||
} | ||
|
||
/** | ||
* @notice Returns the number of PrizeConfig structs pushed | ||
* @return The number of prize config that have been pushed | ||
*/ | ||
function count() external view returns (uint256); | ||
|
||
/** | ||
* @notice Returns last Draw ID recorded in the history. | ||
* @return Draw ID of the last PrizeConfig record | ||
*/ | ||
function getNewestDrawId() external view returns (uint32); | ||
|
||
/** | ||
* @notice Returns first Draw ID used to initialize history. | ||
* @return Draw ID of the first PrizeConfig record | ||
*/ | ||
function getOldestDrawId() external view returns (uint32); | ||
|
||
/** | ||
* @notice Returns PrizeConfig struct for the passed Draw ID. | ||
* @param drawId Draw ID for which to return PrizeConfig struct | ||
* @return The PrizeConfig struct for the passed Draw ID | ||
*/ | ||
function getPrizeConfig(uint32 drawId) external view returns (PrizeConfig memory); | ||
|
||
/** | ||
* @notice Returns the PrizeConfig struct at the given index. | ||
* @param index Index at which the PrizeConfig struct is stored | ||
* @return The PrizeConfig struct at the given index | ||
*/ | ||
function getPrizeConfigAtIndex(uint256 index) external view returns (PrizeConfig memory); | ||
|
||
/** | ||
* @notice Returns a list of PrizeConfig from the history array. | ||
* @param drawIds List of Draw IDs for which to return PrizeConfig structs | ||
* @return The list of PrizeConfig structs for the passed Draw IDs | ||
*/ | ||
function getPrizeConfigList(uint32[] calldata drawIds) | ||
external | ||
view | ||
returns (PrizeConfig[] memory); | ||
|
||
/** | ||
* @notice Push PrizeConfigHistory struct onto history array. | ||
* @dev Callable only by the owner. | ||
* @param prizeConfig Updated PrizeConfigHistory struct | ||
* @return Draw ID at which the PrizeConfig was pushed and is since valid | ||
*/ | ||
function popAndPush(PrizeConfig calldata prizeConfig) external returns (uint32); | ||
|
||
/** | ||
* @notice Push PrizeConfig struct onto history array. | ||
* @dev Callable only by the owner or manager. | ||
* @param prizeConfig New PrizeConfig struct to push onto the history array | ||
*/ | ||
function push(PrizeConfig calldata prizeConfig) external; | ||
|
||
/** | ||
* @notice Replace PrizeConfig struct from history array. | ||
* @dev Callable only by the owner. | ||
* @param prizeConfig New PrizeConfig struct that will replace the previous PrizeConfig at the corresponding index | ||
*/ | ||
function replace(PrizeConfig calldata prizeConfig) external; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters