Skip to content

Commit

Permalink
Merge 6f9b7ed into 9ebbb42
Browse files Browse the repository at this point in the history
  • Loading branch information
kamescg committed Oct 8, 2021
2 parents 9ebbb42 + 6f9b7ed commit e2fd737
Show file tree
Hide file tree
Showing 6 changed files with 381 additions and 10 deletions.
5 changes: 1 addition & 4 deletions contracts/PrizeFlush.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.6;

import "@pooltogether/owner-manager-contracts/contracts/Manageable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@pooltogether/owner-manager-contracts/contracts/Manageable.sol";

import "./interfaces/IPrizeFlush.sol";

Expand All @@ -28,8 +27,6 @@ contract PrizeFlush is IPrizeFlush, Manageable {
/// @notice Strategy address.
IStrategy internal strategy;

/* ============ Events ============ */

/**
* @notice Emitted when contract has been deployed.
* @param destination Destination address
Expand Down
135 changes: 135 additions & 0 deletions contracts/PrizeTierHIstory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.6;
import "@pooltogether/owner-manager-contracts/contracts/Manageable.sol";
import "./interfaces/IPrizeTierHistory.sol";

/**
* @title PoolTogether V4 IPrizeTierHistory
* @author PoolTogether Inc Team
* @notice IPrizeTierHistory is the base contract for PrizeTierHistory
*/
contract PrizeTierHistory is IPrizeTierHistory, Manageable {

/* ============ Global Variables ============ */
/**
* @notice History of PrizeTier updates
*/
PrizeTier[] internal history;

/* ============ Constructor ============ */
constructor(address _owner) Ownable(_owner) {}

/* ============ External Functions ============ */

// @inheritdoc IPrizeTierHistory
function push(PrizeTier calldata _nextPrizeTier)
external
override
onlyManagerOrOwner
returns (uint32)
{
PrizeTier[] memory _history = history;

if (_history.length > 0) {
// READ the newest PrizeTier struct
PrizeTier memory _newestPrizeTier = history[history.length - 1];
// New PrizeTier ID must only be 1 greater than the last PrizeTier ID.
require(
_nextPrizeTier.drawId > _newestPrizeTier.drawId,
"PrizeTierHistory/non-sequential-prize-tier"
);
}

history.push(_nextPrizeTier);

emit PrizeTierPushed(_nextPrizeTier.drawId, _nextPrizeTier);
}

/* ============ Setter Functions ============ */

// @inheritdoc IPrizeTierHistory
function setPrizeTier(PrizeTier calldata _prizeTier) external override onlyOwner returns (uint32) {
require(history.length > 0, "PrizeTierHistory/history-empty");
uint32 _idx = _prizeTier.drawId - history[0].drawId;
history[_idx] = _prizeTier;
emit PrizeTierSet(_prizeTier.drawId, _prizeTier);
}

/* ============ Getter Functions ============ */

// @inheritdoc IPrizeTierHistory
function getPrizeTier(uint32 _drawId) external view override returns (PrizeTier memory) {
require(_drawId > 0, "PrizeTierHistory/draw-id-not-zero");
return _getPrizeTier(_drawId);
}
// @inheritdoc IPrizeTierHistory
function getOldestDrawId() external view override returns (uint32) {
return history[0].drawId;
}

// @inheritdoc IPrizeTierHistory
function getNewestDrawId() external view override returns (uint32) {
return history[history.length - 1].drawId;
}

// @inheritdoc IPrizeTierHistory
function getPrizeTierList(uint32[] calldata _drawIds)
external
view
override
returns (PrizeTier[] memory)
{
PrizeTier[] memory _data = new PrizeTier[](_drawIds.length) ;
for (uint256 index = 0; index < _drawIds.length; index++) {
_data[index] = _getPrizeTier(_drawIds[index]); // SLOAD each struct instead of the whole array before the FOR loop.
}
return _data;
}

function _getPrizeTier(uint32 _drawId) internal view returns (PrizeTier memory) {
uint256 cardinality = history.length;
uint256 leftSide = 0;
uint256 rightSide = cardinality - 1;
uint32 oldestDrawId = history[leftSide].drawId;
uint32 newestDrawId = history[rightSide].drawId;

require(_drawId >= oldestDrawId && _drawId <= newestDrawId, "PrizeTierHistory/draw-id-out-of-range");

if (_drawId == newestDrawId) return history[rightSide];
if (_drawId == oldestDrawId) return history[leftSide];

return _binarySearch(_drawId, leftSide, rightSide, history);
}


function _binarySearch(
uint32 _drawId,
uint256 leftSide,
uint256 rightSide,
PrizeTier[] storage _history
) internal view returns (PrizeTier memory) {

while (true) {
uint256 center = leftSide + (rightSide - leftSide) / 2;
uint32 centerPrizeTierID = _history[center].drawId;

if (centerPrizeTierID == _drawId) {
return _history[center];
}

if (centerPrizeTierID < _drawId) {
leftSide = center + 1;
} else if (centerPrizeTierID > _drawId) {
rightSide = center - 1;
}

if (leftSide == rightSide) {
if (centerPrizeTierID >= _drawId) {
return _history[center - 1];
} else {
return _history[center];
}
}
}
}
}
77 changes: 77 additions & 0 deletions contracts/interfaces/IPrizeTierHistory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.6;
import "@pooltogether/v4-core/contracts/DrawBeacon.sol";

/**
* @title PoolTogether V4 IPrizeTierHistory
* @author PoolTogether Inc Team
* @notice IPrizeTierHistory is the base contract for PrizeTierHistory
*/
interface IPrizeTierHistory {
/**
* @notice Linked Draw and PrizeDistribution parameters storage schema
*/
struct PrizeTier {
uint8 bitRangeSize;
uint32 drawId;
uint32 maxPicksPerUser;
uint256 prize;
uint32[16] tiers;
uint32 validityDuration;
}

/**
* @notice Emit when new PrizeTier is added to history
* @param drawId Draw ID
* @param prizeTier PrizeTier parameters
*/
event PrizeTierPushed(uint32 indexed drawId, PrizeTier prizeTier);

/**
* @notice Emit when existing PrizeTier is updated in history
* @param drawId Draw ID
* @param prizeTier PrizeTier parameters
*/
event PrizeTierSet(uint32 indexed drawId, PrizeTier prizeTier);

/**
* @notice Push PrizeTierHistory struct onto history array.
* @dev Callable only by owner or manager,
* @param drawPrizeDistribution New PrizeTierHistory struct
* @return drawId Draw ID linked to PrizeTierHistory
*/
function push(PrizeTier calldata drawPrizeDistribution) external returns (uint32 drawId);

/**
* @notice Read PrizeTierHistory struct from history array.
* @param drawId Draw ID
* @return prizeTier
*/
function getPrizeTier(uint32 drawId) external view returns (PrizeTier memory prizeTier);

/**
* @notice Read first Draw ID used to initialize history
* @return Draw ID of first PrizeTier record
*/
function getOldestDrawId() external view returns (uint32);

function getNewestDrawId() external view returns (uint32);

/**
* @notice Read PrizeTierHistory List from history array.
* @param drawIds Draw ID array
* @return prizeTierList
*/
function getPrizeTierList(uint32[] calldata drawIds)
external
view
returns (PrizeTier[] memory prizeTierList);

/**
* @notice Push PrizeTierHistory struct onto history array.
* @dev Callable only by owner.
* @param prizeTier Updated PrizeTierHistory struct
* @return drawId Draw ID linked to PrizeTierHistory
*/
function setPrizeTier(PrizeTier calldata prizeTier) external returns (uint32 drawId);
}
13 changes: 7 additions & 6 deletions test/PrizeFlush.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import { expect } from 'chai';
import { ethers, artifacts } from 'hardhat';
import { Contract, ContractFactory } from 'ethers';
import { deployMockContract, MockContract } from 'ethereum-waffle';
import { Signer } from '@ethersproject/abstract-signer';
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import { Contract, ContractFactory } from 'ethers';

const { constants, getSigners, utils } = ethers;
const { AddressZero } = constants;
Expand Down Expand Up @@ -34,7 +35,7 @@ describe('PrizeFlush', () => {
prizeSplitStrategyFactory = await ethers.getContractFactory('PrizeSplitStrategy');

let PrizeSplitStrategy = await artifacts.readArtifact('PrizeSplitStrategy');
strategy = await deployMockContract(wallet1, PrizeSplitStrategy.abi);
strategy = await deployMockContract(wallet1 as unknown as Signer, PrizeSplitStrategy.abi);
});

beforeEach(async () => {
Expand Down Expand Up @@ -64,7 +65,7 @@ describe('PrizeFlush', () => {
describe('Setters', () => {
it('should fail to set the destination address if not called by owner', async () => {
await expect(
prizeFlush.connect(wallet3).setDestination(wallet3.address),
prizeFlush.connect(wallet3 as unknown as Signer).setDestination(wallet3.address),
).to.revertedWith('Ownable/caller-not-owner');
});

Expand All @@ -82,7 +83,7 @@ describe('PrizeFlush', () => {
});

it('should fail to set the strategy address', async () => {
await expect(prizeFlush.connect(wallet3).setStrategy(wallet3.address)).to.revertedWith(
await expect(prizeFlush.connect(wallet3 as unknown as Signer).setStrategy(wallet3.address)).to.revertedWith(
'Ownable/caller-not-owner',
);
});
Expand All @@ -101,7 +102,7 @@ describe('PrizeFlush', () => {
});

it('should fail to set the reserve address', async () => {
await expect(prizeFlush.connect(wallet3).setReserve(wallet3.address)).to.revertedWith(
await expect(prizeFlush.connect(wallet3 as unknown as Signer).setReserve(wallet3.address)).to.revertedWith(
'Ownable/caller-not-owner',
);
});
Expand Down

0 comments on commit e2fd737

Please sign in to comment.