Skip to content

Commit

Permalink
Feature/pool 245 prizepool needs hard limits on exit fee (#64)
Browse files Browse the repository at this point in the history
* Set up limits on exit-fee and timelock-duration

* Update test coverage

* Feature/pool 284 update rng service to use rngveedo npm (#65)

* Update to lock block, switch to uint32 (#63)

Update to lock block, switch to uint32

* Update to use published package for RNG
  • Loading branch information
robsecord committed Jul 17, 2020
1 parent 468f153 commit b50130b
Show file tree
Hide file tree
Showing 16 changed files with 467 additions and 173 deletions.
22 changes: 21 additions & 1 deletion contracts/prize-pool/PrizePool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ abstract contract PrizePool is Initializable, BaseRelayRecipient, ReentrancyGuar
MappedSinglyLinkedList.Mapping internal _tokens;
PrizeStrategyInterface public prizeStrategy;

uint256 internal maxExitFeeMultiple;
uint256 internal maxTimelockDuration;

uint256 public timelockTotalSupply;
mapping(address => uint256) internal timelockBalances;
mapping(address => uint256) internal unlockTimestamps;
Expand All @@ -53,10 +56,14 @@ abstract contract PrizePool is Initializable, BaseRelayRecipient, ReentrancyGuar
/// @param _trustedForwarder Address of the Forwarding Contract for GSN Meta-Txs
/// @param _prizeStrategy Address of the component-controller that manages the prize-strategy
/// @param _controlledTokens Array of addresses for the Ticket and Sponsorship Tokens controlled by the Prize Pool
/// @param _maxExitFeeMultiple The maximum exit fee size, relative to the withdrawal amount
/// @param _maxTimelockDuration The maximum length of time the withdraw timelock could be
function initialize (
address _trustedForwarder,
PrizeStrategyInterface _prizeStrategy,
address[] memory _controlledTokens
address[] memory _controlledTokens,
uint256 _maxExitFeeMultiple,
uint256 _maxTimelockDuration
)
public
initializer
Expand All @@ -74,6 +81,8 @@ abstract contract PrizePool is Initializable, BaseRelayRecipient, ReentrancyGuar
__ReentrancyGuard_init();
trustedForwarder = _trustedForwarder;
prizeStrategy = _prizeStrategy;
maxExitFeeMultiple = _maxExitFeeMultiple;
maxTimelockDuration = _maxTimelockDuration;
}

/// @dev Inheriting contract must determine if a specific token type may be awarded as a prize enhancement
Expand Down Expand Up @@ -168,6 +177,12 @@ abstract contract PrizePool is Initializable, BaseRelayRecipient, ReentrancyGuar
exitFee = prizeStrategy.beforeWithdrawInstantlyFrom(from, amount, controlledToken);
}

uint256 mantissa = FixedPoint.calculateMantissa(maxExitFeeMultiple, 100);
uint256 maxFee = FixedPoint.multiplyUintByMantissa(amount, mantissa);
if (exitFee > maxFee) {
exitFee = maxFee;
}

address operator = _msgSender();
uint256 sponsoredExitFee = (exitFee > prepaidExitFee) ? prepaidExitFee : exitFee;
uint256 userExitFee = exitFee.sub(sponsoredExitFee);
Expand Down Expand Up @@ -209,13 +224,18 @@ abstract contract PrizePool is Initializable, BaseRelayRecipient, ReentrancyGuar
onlyControlledToken(controlledToken)
returns (uint256 unlockTimestamp)
{
uint256 blockTime = _currentTime();
_updateAwardBalance();

bool hasPrizeStrategy = _hasPrizeStrategy();
if (hasPrizeStrategy) {
unlockTimestamp = prizeStrategy.beforeWithdrawWithTimelockFrom(from, amount, controlledToken);
}

if (unlockTimestamp > 0 && unlockTimestamp.sub(blockTime) > maxTimelockDuration) {
unlockTimestamp = blockTime.add(maxTimelockDuration);
}

address operator = _msgSender();

ControlledToken(controlledToken).controllerBurnFrom(operator, from, amount);
Expand Down
8 changes: 7 additions & 1 deletion contracts/prize-pool/compound/CompoundPrizePool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ contract CompoundPrizePool is PrizePool {
/// @param _trustedForwarder Address of the Forwarding Contract for GSN Meta-Txs
/// @param _prizeStrategy Address of the component-controller that manages the prize-strategy
/// @param _controlledTokens Array of addresses for the Ticket and Sponsorship Tokens controlled by the Prize Pool
/// @param _maxExitFeeMultiple The maximum exit fee size, relative to the withdrawal amount
/// @param _maxTimelockDuration The maximum length of time the withdraw timelock could be
/// @param _cToken Address of the Compound cToken interface
function initialize (
address _trustedForwarder,
PrizeStrategyInterface _prizeStrategy,
address[] memory _controlledTokens,
uint256 _maxExitFeeMultiple,
uint256 _maxTimelockDuration,
CTokenInterface _cToken
)
public
Expand All @@ -33,7 +37,9 @@ contract CompoundPrizePool is PrizePool {
PrizePool.initialize(
_trustedForwarder,
_prizeStrategy,
_controlledTokens
_controlledTokens,
_maxExitFeeMultiple,
_maxTimelockDuration
);
cToken = _cToken;
}
Expand Down
18 changes: 15 additions & 3 deletions contracts/prize-strategy/PrizeStrategyBuilder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ contract PrizeStrategyBuilder is Initializable {
bytes memory ticketSymbol,
bytes memory sponsorshipName,
bytes memory sponsorshipSymbol,
uint256 _maxExitFeeMultiple,
uint256 _maxTimelockDuration,
address[] memory externalAwards
) public returns (PrizeStrategy) {
PrizeStrategy prizeStrategy = prizeStrategyProxyFactory.create();
Expand All @@ -62,7 +64,9 @@ contract PrizeStrategyBuilder is Initializable {
ticketName,
ticketSymbol,
sponsorshipName,
sponsorshipSymbol
sponsorshipSymbol,
_maxExitFeeMultiple,
_maxTimelockDuration
);

prizeStrategy.initialize(
Expand Down Expand Up @@ -91,7 +95,9 @@ contract PrizeStrategyBuilder is Initializable {
bytes memory ticketName,
bytes memory ticketSymbol,
bytes memory sponsorshipName,
bytes memory sponsorshipSymbol
bytes memory sponsorshipSymbol,
uint256 _maxExitFeeMultiple,
uint256 _maxTimelockDuration
) internal returns (CompoundPrizePool prizePool, address[] memory tokens) {
prizePool = compoundPrizePoolProxyFactory.create();
tokens = new address[](2);
Expand All @@ -101,6 +107,8 @@ contract PrizeStrategyBuilder is Initializable {
trustedForwarder,
prizeStrategy,
tokens,
_maxExitFeeMultiple,
_maxTimelockDuration,
_cToken
);
}
Expand All @@ -119,7 +127,9 @@ contract PrizeStrategyBuilder is Initializable {
PrizeStrategy prizeStrategy,
CTokenInterface _cToken,
ControlledToken ticket,
ControlledToken sponsorship
ControlledToken sponsorship,
uint256 _maxExitFeeMultiple,
uint256 _maxTimelockDuration
) internal returns (CompoundPrizePool) {
address[] memory tokens = new address[](2);
tokens[0] = address(ticket);
Expand All @@ -129,6 +139,8 @@ contract PrizeStrategyBuilder is Initializable {
trustedForwarder,
prizeStrategy,
tokens,
_maxExitFeeMultiple,
_maxTimelockDuration,
_cToken
);
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/prize-strategy/PrizeStrategyStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ pragma solidity ^0.6.4;

import "sortition-sum-tree-factory/contracts/SortitionSumTreeFactory.sol";
import "@pooltogether/governor-contracts/contracts/GovernorInterface.sol";
import "@pooltogether/pooltogether-rng-contracts/contracts/RNGInterface.sol";

import "../prize-pool/MappedSinglyLinkedList.sol";
import "../token/TokenControllerInterface.sol";
import "../token/ControlledToken.sol";
import "../prize-pool/PrizePool.sol";
import "../rng/RNGInterface.sol";
import "../Constants.sol";

contract PrizeStrategyStorage {
Expand Down
10 changes: 0 additions & 10 deletions contracts/rng/RNGInterface.sol

This file was deleted.

24 changes: 22 additions & 2 deletions contracts/test/CompoundPrizePoolHarness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,24 @@ contract CompoundPrizePoolHarness is CompoundPrizePool {

uint256 internal time;

function initialize(CTokenInterface _cToken) public {
cToken = _cToken;
function initializeAll(
address _trustedForwarder,
PrizeStrategyInterface _prizeStrategy,
address[] memory _controlledTokens,
uint256 _maxExitFeeMultiple,
uint256 _maxTimelockDuration,
CTokenInterface _cToken
)
public
{
CompoundPrizePool.initialize(
_trustedForwarder,
_prizeStrategy,
_controlledTokens,
_maxExitFeeMultiple,
_maxTimelockDuration,
_cToken
);
}

function supply(uint256 mintAmount) external {
Expand All @@ -23,6 +39,10 @@ contract CompoundPrizePoolHarness is CompoundPrizePool {
time = _time;
}

function setTimelockBalance(uint256 _timelockBalance) external {
timelockTotalSupply = _timelockBalance;
}

function _currentTime() internal override view returns (uint256) {
if (time == 0) {
return block.timestamp;
Expand Down
2 changes: 1 addition & 1 deletion contracts/test/RNGBlockhash.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pragma solidity ^0.6.4;

import "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol";

import "../rng/RNGInterface.sol";
import "@pooltogether/pooltogether-rng-contracts/contracts/RNGInterface.sol";

contract RNGBlockhash is RNGInterface {
using SafeMath for uint256;
Expand Down
2 changes: 1 addition & 1 deletion contracts/test/RNGServiceMock.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pragma solidity ^0.6.4;

import "../rng/RNGInterface.sol";
import "@pooltogether/pooltogether-rng-contracts/contracts/RNGInterface.sol";

contract RNGServiceMock is RNGInterface {

Expand Down
14 changes: 11 additions & 3 deletions js/deployTestPool.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ const { deployContract } = require('ethereum-waffle')

const debug = require('debug')('ptv3:deployTestPool')

async function deployTestPool(wallet, prizePeriodSeconds, overrides = { gasLimit: 20000000 }) {
async function deployTestPool({
wallet,
prizePeriodSeconds,
maxExitFeePercentage,
maxTimelockMultiple,
overrides = { gasLimit: 20000000 }
}) {
let registry = await deploy1820(wallet)

debug('beforeEach deploy rng, forwarder etc...')
Expand All @@ -28,7 +34,7 @@ async function deployTestPool(wallet, prizePeriodSeconds, overrides = { gasLimit
debug('Deploying Governor...')

let governor = await deployContract(wallet, MockGovernor, [], overrides)

debug('Deploying PrizeStrategy...')

let prizeStrategy = await deployContract(wallet, PrizeStrategyHarness, [], overrides)
Expand All @@ -49,10 +55,12 @@ async function deployTestPool(wallet, prizePeriodSeconds, overrides = { gasLimit

debug('Initializing CompoundPrizePoolHarness...')

await compoundPrizePool.initialize(
await compoundPrizePool.initializeAll(
forwarder.address,
prizeStrategy.address,
[ticket.address, sponsorship.address],
maxExitFeePercentage,
prizePeriodSeconds * maxTimelockMultiple,
cToken.address
)

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@
"prepack": "rm -rf build cache && buidler compile && truffle-extract -b build -o abis",
"postpublish": "PACKAGE_VERSION=$(./scripts/package-version.sh) && git tag -ae v$PACKAGE_VERSION && git push --tags"
},
"dependencies": {
},
"dependencies": {},
"devDependencies": {
"@nomiclabs/buidler": "^1.3.5",
"@nomiclabs/buidler-ethers": "^1.3.3",
Expand All @@ -44,6 +43,7 @@
"@pooltogether/fixed-point": "pooltogether/fixed-point.git#0.1.0-upgradeable.1",
"@pooltogether/governor-contracts": "^0.1.1",
"@pooltogether/oz-migrate": "^0.2.5",
"@pooltogether/pooltogether-rng-contracts": "^3.0.0-alpha.4",
"@pooltogether/uniform-random-number": "pooltogether/uniform-random-number#solidity-0.6",
"@resolver-engine/core": "^0.3.3",
"@truffle/hdwallet-provider": "^1.0.34",
Expand Down
Loading

0 comments on commit b50130b

Please sign in to comment.