Skip to content

Commit

Permalink
feat(contracts): add PrizeConfigHistory
Browse files Browse the repository at this point in the history
  • Loading branch information
PierrickGT committed May 11, 2022
1 parent a3bafe5 commit 78164ce
Show file tree
Hide file tree
Showing 4 changed files with 286 additions and 0 deletions.
182 changes: 182 additions & 0 deletions contracts/PrizeConfigHistory.sol
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);
}
}
98 changes: 98 additions & 0 deletions contracts/interfaces/IPrizeConfigHistory.sol
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;
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@pooltogether/fixed-point": "1.0.0",
"@pooltogether/owner-manager-contracts": "1.1.0",
"@pooltogether/pooltogether-rng-contracts": "1.4.0",
"@pooltogether/v4-periphery": "1.2.3",
"@pooltogether/yield-source-interface": "1.3.0",
"deploy-eip-1820": "1.0.0"
},
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,11 @@
resolved "https://registry.yarnpkg.com/@pooltogether/uniform-random-number/-/uniform-random-number-1.0.0-beta.2.tgz#fcc388269098a7303c83de6f07cdc5d46dede0e9"
integrity sha512-xwEpcg+WXcoWtRdG9WPmE5B93YvkhBi4XCEVQ/kfkXS5tVsrhCjFHWQOuqvX2P7zMyCuI/Bq6Y84QQJnRywJhg==

"@pooltogether/v4-periphery@1.2.3":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@pooltogether/v4-periphery/-/v4-periphery-1.2.3.tgz#59e64b12da30c8ce92351b3016a3f3709065b29f"
integrity sha512-l1Yh/TF0vys+/bsHk3oBMgdcS5gVnTlhPssVOaG6CSajf4XNed39AaInA5vDRcREeA8ya3/R9p4czAeeuMM55A==

"@pooltogether/yield-source-interface@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@pooltogether/yield-source-interface/-/yield-source-interface-1.3.0.tgz#93e9c12bb2d62e2215bb2f9c9d391a092e6eb6d5"
Expand Down

0 comments on commit 78164ce

Please sign in to comment.