diff --git a/README.md b/README.md index b2abf092..6c665f39 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ https://docs.pooltogether.com - [DrawBeacon](/contracts/DrawBeacon.sol) - [DrawCalculator](/contracts/DrawCalculator.sol) - [DrawHistory](/contracts/DrawHistory.sol) -- [DrawPrize](/contracts/DrawPrize.sol) +- [PrizeDistributor](/contracts/PrizeDistributor.sol) - [PrizeSplitStrategy](/contracts/PrizeSplitStrategy.sol) - [Reserve](/contracts/Reserve.sol) diff --git a/contracts/DrawCalculator.sol b/contracts/DrawCalculator.sol index dc1c426d..6f2f7a44 100644 --- a/contracts/DrawCalculator.sol +++ b/contracts/DrawCalculator.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.6; import "@pooltogether/owner-manager-contracts/contracts/Ownable.sol"; -import "./DrawPrize.sol"; +import "./PrizeDistributor.sol"; import "./interfaces/IDrawCalculator.sol"; import "./interfaces/ITicket.sol"; diff --git a/contracts/DrawPrize.sol b/contracts/PrizeDistributor.sol similarity index 78% rename from contracts/DrawPrize.sol rename to contracts/PrizeDistributor.sol index f8b5e128..7607a9ef 100644 --- a/contracts/DrawPrize.sol +++ b/contracts/PrizeDistributor.sol @@ -6,20 +6,20 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@pooltogether/owner-manager-contracts/contracts/Ownable.sol"; -import "./interfaces/IDrawPrize.sol"; +import "./interfaces/IPrizeDistributor.sol"; import "./interfaces/IDrawCalculator.sol"; import "./interfaces/IDrawBeacon.sol"; /** - * @title PoolTogether V4 DrawPrize + * @title PoolTogether V4 PrizeDistributor * @author PoolTogether Inc Team - * @notice The DrawPrize contract holds Tickets (captured interest) and distributes tickets to users with winning draw claims. - DrawPrize uses an external IDrawCalculator to validate a users draw claim, before awarding payouts. To prevent users + * @notice The PrizeDistributor contract holds Tickets (captured interest) and distributes tickets to users with winning draw claims. + PrizeDistributor uses an external IDrawCalculator to validate a users draw claim, before awarding payouts. To prevent users from reclaiming prizes, a payout history for each draw claim is mapped to user accounts. Reclaiming a draw can occur if an "optimal" prize was not included in previous claim pick indices and the new claims updated payout is greater then - the previous draw prize claim payout. + the previous prize distributor claim payout. */ -contract DrawPrize is IDrawPrize, Ownable { +contract PrizeDistributor is IPrizeDistributor, Ownable { using SafeERC20 for IERC20; /* ============ Global Variables ============ */ @@ -36,7 +36,7 @@ contract DrawPrize is IDrawPrize, Ownable { /* ============ Initialize ============ */ /** - * @notice Initialize DrawPrize smart contract. + * @notice Initialize PrizeDistributor smart contract. * @param _owner Owner address * @param _token Token address * @param _drawCalculator DrawCalculator address @@ -47,14 +47,14 @@ contract DrawPrize is IDrawPrize, Ownable { IDrawCalculator _drawCalculator ) Ownable(_owner) { _setDrawCalculator(_drawCalculator); - require(address(_token) != address(0), "DrawPrize/token-not-zero-address"); + require(address(_token) != address(0), "PrizeDistributor/token-not-zero-address"); token = _token; emit TokenSet(_token); } /* ============ External Functions ============ */ - /// @inheritdoc IDrawPrize + /// @inheritdoc IPrizeDistributor function claim( address _user, uint32[] calldata _drawIds, @@ -75,7 +75,7 @@ contract DrawPrize is IDrawPrize, Ownable { } // helpfully short-circuit, in case the user screwed something up. - require(payoutDiff > 0, "DrawPrize/zero-payout"); + require(payoutDiff > 0, "PrizeDistributor/zero-payout"); totalPayout += payoutDiff; @@ -87,14 +87,14 @@ contract DrawPrize is IDrawPrize, Ownable { return totalPayout; } - /// @inheritdoc IDrawPrize + /// @inheritdoc IPrizeDistributor function withdrawERC20( IERC20 _erc20Token, address _to, uint256 _amount ) external override onlyOwner returns (bool) { - require(_to != address(0), "DrawPrize/recipient-not-zero-address"); - require(address(_erc20Token) != address(0), "DrawPrize/ERC20-not-zero-address"); + require(_to != address(0), "PrizeDistributor/recipient-not-zero-address"); + require(address(_erc20Token) != address(0), "PrizeDistributor/ERC20-not-zero-address"); _erc20Token.safeTransfer(_to, _amount); @@ -103,12 +103,12 @@ contract DrawPrize is IDrawPrize, Ownable { return true; } - /// @inheritdoc IDrawPrize + /// @inheritdoc IPrizeDistributor function getDrawCalculator() external view override returns (IDrawCalculator) { return drawCalculator; } - /// @inheritdoc IDrawPrize + /// @inheritdoc IPrizeDistributor function getDrawPayoutBalanceOf(address _user, uint32 _drawId) external view @@ -118,12 +118,12 @@ contract DrawPrize is IDrawPrize, Ownable { return _getDrawPayoutBalanceOf(_user, _drawId); } - /// @inheritdoc IDrawPrize + /// @inheritdoc IPrizeDistributor function getToken() external view override returns (IERC20) { return token; } - /// @inheritdoc IDrawPrize + /// @inheritdoc IPrizeDistributor function setDrawCalculator(IDrawCalculator _newCalculator) external override @@ -157,7 +157,7 @@ contract DrawPrize is IDrawPrize, Ownable { * @param _newCalculator DrawCalculator address */ function _setDrawCalculator(IDrawCalculator _newCalculator) internal { - require(address(_newCalculator) != address(0), "DrawPrize/calc-not-zero"); + require(address(_newCalculator) != address(0), "PrizeDistributor/calc-not-zero"); drawCalculator = _newCalculator; emit DrawCalculatorSet(_newCalculator); diff --git a/contracts/interfaces/IDrawCalculator.sol b/contracts/interfaces/IDrawCalculator.sol index 7dfdbfbc..85f53b58 100644 --- a/contracts/interfaces/IDrawCalculator.sol +++ b/contracts/interfaces/IDrawCalculator.sol @@ -5,7 +5,7 @@ pragma solidity 0.8.6; import "./ITicket.sol"; import "./IDrawHistory.sol"; import "../PrizeDistributionHistory.sol"; -import "../DrawPrize.sol"; +import "../PrizeDistributor.sol"; /** * @title PoolTogether V4 IDrawCalculator @@ -23,11 +23,11 @@ interface IDrawCalculator { IDrawHistory indexed drawHistory, IPrizeDistributionHistory indexed prizeDistributionHistory); - ///@notice Emitted when the drawPrize is set/updated - event DrawPrizeSet(DrawPrize indexed drawPrize); + ///@notice Emitted when the prizeDistributor is set/updated + event PrizeDistributorSet(PrizeDistributor indexed prizeDistributor); /** - * @notice Calculates the prize amount for a user for Multiple Draws. Typically called by a DrawPrize. + * @notice Calculates the prize amount for a user for Multiple Draws. Typically called by a PrizeDistributor. * @param user User for which to calculate prize amount. * @param drawIds drawId array for which to calculate prize amounts for. * @param data The ABI encoded pick indices for all Draws. Expected to be winning picks. Pick indices must be less than the totalUserPicks. diff --git a/contracts/interfaces/IDrawPrize.sol b/contracts/interfaces/IPrizeDistributor.sol similarity index 95% rename from contracts/interfaces/IDrawPrize.sol rename to contracts/interfaces/IPrizeDistributor.sol index 43467d40..b92031f4 100644 --- a/contracts/interfaces/IDrawPrize.sol +++ b/contracts/interfaces/IPrizeDistributor.sol @@ -1,15 +1,17 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.6; + import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + import "./IDrawHistory.sol"; import "./IDrawCalculator.sol"; -/** @title IDrawPrize +/** @title IPrizeDistributor * @author PoolTogether Inc Team - * @notice The DrawPrize interface. + * @notice The PrizeDistributor interface. */ -interface IDrawPrize { - +interface IPrizeDistributor { + /** * @notice Emit when user has claimed token from the PrizeDistributor. * @param user User address receiving draw claim payouts @@ -45,7 +47,7 @@ interface IDrawPrize { Prizes are always paid out to the designated user account and not the caller (msg.sender). Claiming prizes is not limited to a single transaction. Reclaiming can be executed subsequentially if an "optimal" prize was not included in previous claim pick indices. The - payout difference for the new claim is calculated during the award process and transfered to user. + payout difference for the new claim is calculated during the award process and transfered to user. * @param user Address of user to claim awards for. Does NOT need to be msg.sender * @param drawIds Draw IDs from global DrawHistory reference * @param data The data to pass to the draw calculator diff --git a/contracts/interfaces/IPrizePool.sol b/contracts/interfaces/IPrizePool.sol index 68a71344..d809623b 100644 --- a/contracts/interfaces/IPrizePool.sol +++ b/contracts/interfaces/IPrizePool.sol @@ -179,8 +179,8 @@ interface IPrizePool { function setLiquidityCap(uint256 liquidityCap) external; /// @notice Sets the prize strategy of the prize pool. Only callable by the owner. - /// @param prizeStrategy The new prize strategy. Must implement DrawPrizePrizeStrategy - function setPrizeStrategy(address prizeStrategy) external; + /// @param _prizeStrategy The new prize strategy. + function setPrizeStrategy(address _prizeStrategy) external; /// @notice Set prize pool ticket. /// @param ticket Address of the ticket to set. diff --git a/deploy/deploy.js b/deploy/deploy.js index b8787fa0..e1869ea8 100644 --- a/deploy/deploy.js +++ b/deploy/deploy.js @@ -183,12 +183,12 @@ module.exports = async (hardhat) => { }); displayResult('DrawCalculator', drawCalculatorResult); - cyan('\nDeploying DrawPrize...'); - const drawPrizeResult = await deploy('DrawPrize', { + cyan('\nDeploying PrizeDistributor...'); + const prizeDistributorResult = await deploy('PrizeDistributor', { from: deployer, args: [deployer, ticketResult.address, drawCalculatorResult.address], }); - displayResult('DrawPrize', drawPrizeResult); + displayResult('PrizeDistributor', prizeDistributorResult); cyan('\nDeploying PrizeSplitStrategy...'); const prizeSplitStrategyResult = await deploy('PrizeSplitStrategy', { diff --git a/test/DrawHistory.test.ts b/test/DrawHistory.test.ts index e277182a..24d6ccee 100644 --- a/test/DrawHistory.test.ts +++ b/test/DrawHistory.test.ts @@ -115,9 +115,9 @@ describe('DrawHistory', () => { describe('pushDraw()', () => { it('should fail to create a new draw when called from non-draw-manager', async () => { - const drawPrizeWallet2 = drawHistory.connect(wallet2); + const prizeDistributorWallet2 = drawHistory.connect(wallet2); - await expect(drawPrizeWallet2.pushDraw(newDraw({ drawId: 1 }))).to.be.revertedWith( + await expect(prizeDistributorWallet2.pushDraw(newDraw({ drawId: 1 }))).to.be.revertedWith( 'Manageable/caller-not-manager', ); }); diff --git a/test/PrizeDistributionHistory.test.ts b/test/PrizeDistributionHistory.test.ts index 39bc75f6..650b6136 100644 --- a/test/PrizeDistributionHistory.test.ts +++ b/test/PrizeDistributionHistory.test.ts @@ -211,10 +211,10 @@ describe('PrizeDistributionHistory', () => { }); it('should fail to create a new draw when called from non-draw-manager', async () => { - const drawPrizeWallet2 = prizeDistributionHistory.connect(wallet2); + const prizeDistributorWallet2 = prizeDistributionHistory.connect(wallet2); await expect( - drawPrizeWallet2.pushPrizeDistribution(1, newPrizeDistribution()), + prizeDistributorWallet2.pushPrizeDistribution(1, newPrizeDistribution()), ).to.be.revertedWith('Manageable/caller-not-manager-or-owner'); }); diff --git a/test/DrawPrizes.test.ts b/test/PrizeDistributor.test.ts similarity index 65% rename from test/DrawPrizes.test.ts rename to test/PrizeDistributor.test.ts index 795d9154..5164245b 100644 --- a/test/DrawPrizes.test.ts +++ b/test/PrizeDistributor.test.ts @@ -7,13 +7,13 @@ const { getSigners } = ethers; const { parseEther: toWei } = utils; const { AddressZero } = constants; -describe('DrawPrize', () => { +describe('PrizeDistributor', () => { let wallet1: any; let wallet2: any; let wallet3: any; let dai: Contract; let ticket: Contract; - let drawPrize: Contract; + let prizeDistributor: Contract; let drawCalculator: MockContract; before(async () => { @@ -31,15 +31,15 @@ describe('DrawPrize', () => { let IDrawCalculator = await artifacts.readArtifact('IDrawCalculator'); drawCalculator = await deployMockContract(wallet1, IDrawCalculator.abi); - const drawPrizeFactory: ContractFactory = await ethers.getContractFactory('DrawPrize'); + const prizeDistributorFactory: ContractFactory = await ethers.getContractFactory('PrizeDistributor'); - drawPrize = await drawPrizeFactory.deploy( + prizeDistributor = await prizeDistributorFactory.deploy( wallet1.address, ticket.address, drawCalculator.address, ); - await ticket.mint(drawPrize.address, toWei('1000')); + await ticket.mint(prizeDistributor.address, toWei('1000')); }); /* =============================== */ @@ -49,19 +49,19 @@ describe('DrawPrize', () => { describe('Getter Functions', () => { describe('getDrawCalculator()', () => { it('should succeed to read an empty Draw ID => DrawCalculator mapping', async () => { - expect(await drawPrize.getDrawCalculator()).to.equal(drawCalculator.address); + expect(await prizeDistributor.getDrawCalculator()).to.equal(drawCalculator.address); }); }); describe('getDrawPayoutBalanceOf()', () => { it('should return the user payout for draw before claiming a payout', async () => { - expect(await drawPrize.getDrawPayoutBalanceOf(wallet1.address, 0)).to.equal('0'); + expect(await prizeDistributor.getDrawPayoutBalanceOf(wallet1.address, 0)).to.equal('0'); }); }); describe('getToken()', () => { it('should succesfully read global token variable', async () => { - expect(await drawPrize.getToken()).to.equal(ticket.address); + expect(await prizeDistributor.getToken()).to.equal(ticket.address); }); }); }); @@ -72,29 +72,29 @@ describe('DrawPrize', () => { describe('Setter Functions', () => { describe('setDrawCalculator()', () => { it('should fail to set draw calculator from unauthorized wallet', async () => { - const drawPrizeUnauthorized = drawPrize.connect(wallet2); + const prizeDistributorUnauthorized = prizeDistributor.connect(wallet2); await expect( - drawPrizeUnauthorized.setDrawCalculator(AddressZero), + prizeDistributorUnauthorized.setDrawCalculator(AddressZero), ).to.be.revertedWith('Ownable/caller-not-owner'); }); it('should succeed to set new draw calculator for target draw id as owner', async () => { - expect(await drawPrize.setDrawCalculator(wallet2.address)) - .to.emit(drawPrize, 'DrawCalculatorSet') + expect(await prizeDistributor.setDrawCalculator(wallet2.address)) + .to.emit(prizeDistributor, 'DrawCalculatorSet') .withArgs(wallet2.address); }); it('should not allow a zero calculator', async () => { - await expect(drawPrize.setDrawCalculator(AddressZero)).to.be.revertedWith( - 'DrawPrize/calc-not-zero', + await expect(prizeDistributor.setDrawCalculator(AddressZero)).to.be.revertedWith( + 'PrizeDistributor/calc-not-zero', ); }); it('should succeed to update draw calculator for target draw id as owner', async () => { - await drawPrize.setDrawCalculator(wallet2.address); + await prizeDistributor.setDrawCalculator(wallet2.address); - expect(await drawPrize.setDrawCalculator(wallet3.address)) - .to.emit(drawPrize, 'DrawCalculatorSet') + expect(await prizeDistributor.setDrawCalculator(wallet3.address)) + .to.emit(prizeDistributor, 'DrawCalculatorSet') .withArgs(wallet3.address); }); }); @@ -109,8 +109,8 @@ describe('DrawPrize', () => { .withArgs(wallet1.address, [1], '0x') .returns([toWei('10')]); - await expect(drawPrize.claim(wallet1.address, [1], '0x')) - .to.emit(drawPrize, 'ClaimedDraw') + await expect(prizeDistributor.claim(wallet1.address, [1], '0x')) + .to.emit(prizeDistributor, 'ClaimedDraw') .withArgs(wallet1.address, 1, toWei('10')); }); @@ -120,11 +120,11 @@ describe('DrawPrize', () => { .returns([toWei('10')]); // updated - await drawPrize.claim(wallet1.address, [0], '0x'); + await prizeDistributor.claim(wallet1.address, [0], '0x'); // try again: should fail! - await expect(drawPrize.claim(wallet1.address, [0], '0x')).to.be.revertedWith( - 'DrawPrize/zero-payout', + await expect(prizeDistributor.claim(wallet1.address, [0], '0x')).to.be.revertedWith( + 'PrizeDistributor/zero-payout', ); }); @@ -134,9 +134,9 @@ describe('DrawPrize', () => { .withArgs(wallet1.address, [1], '0x') .returns([toWei('10')]); - await drawPrize.claim(wallet1.address, [1], '0x'); + await prizeDistributor.claim(wallet1.address, [1], '0x'); - expect(await drawPrize.getDrawPayoutBalanceOf(wallet1.address, 1)).to.equal( + expect(await prizeDistributor.getDrawPayoutBalanceOf(wallet1.address, 1)).to.equal( toWei('10'), ); @@ -146,11 +146,11 @@ describe('DrawPrize', () => { .returns([toWei('20')]); // try again; should reward diff - await expect(drawPrize.claim(wallet1.address, [1], '0x')) - .to.emit(drawPrize, 'ClaimedDraw') + await expect(prizeDistributor.claim(wallet1.address, [1], '0x')) + .to.emit(prizeDistributor, 'ClaimedDraw') .withArgs(wallet1.address, 1, toWei('10')); - expect(await drawPrize.getDrawPayoutBalanceOf(wallet1.address, 1)).to.equal( + expect(await prizeDistributor.getDrawPayoutBalanceOf(wallet1.address, 1)).to.equal( toWei('20'), ); }); @@ -160,12 +160,12 @@ describe('DrawPrize', () => { let withdrawAmount: BigNumber = toWei('100'); beforeEach(async () => { - await dai.mint(drawPrize.address, toWei('1000')); + await dai.mint(prizeDistributor.address, toWei('1000')); }); it('should fail to withdraw ERC20 tokens as unauthorized account', async () => { expect( - drawPrize + prizeDistributor .connect(wallet3) .withdrawERC20(dai.address, wallet1.address, withdrawAmount), ).to.be.revertedWith('Ownable/caller-not-owner'); @@ -173,19 +173,19 @@ describe('DrawPrize', () => { it('should fail to withdraw ERC20 tokens if recipient address is address zero', async () => { await expect( - drawPrize.withdrawERC20(dai.address, AddressZero, withdrawAmount), - ).to.be.revertedWith('DrawPrize/recipient-not-zero-address'); + prizeDistributor.withdrawERC20(dai.address, AddressZero, withdrawAmount), + ).to.be.revertedWith('PrizeDistributor/recipient-not-zero-address'); }); it('should fail to withdraw ERC20 tokens if token address is address zero', async () => { await expect( - drawPrize.withdrawERC20(AddressZero, wallet1.address, withdrawAmount), - ).to.be.revertedWith('DrawPrize/ERC20-not-zero-address'); + prizeDistributor.withdrawERC20(AddressZero, wallet1.address, withdrawAmount), + ).to.be.revertedWith('PrizeDistributor/ERC20-not-zero-address'); }); it('should succeed to withdraw ERC20 tokens as owner', async () => { - await expect(drawPrize.withdrawERC20(dai.address, wallet1.address, withdrawAmount)) - .to.emit(drawPrize, 'ERC20Withdrawn') + await expect(prizeDistributor.withdrawERC20(dai.address, wallet1.address, withdrawAmount)) + .to.emit(prizeDistributor, 'ERC20Withdrawn') .withArgs(dai.address, wallet1.address, withdrawAmount); }); }); diff --git a/test/features/support/PoolEnv.js b/test/features/support/PoolEnv.js index 6309a422..89a411dc 100644 --- a/test/features/support/PoolEnv.js +++ b/test/features/support/PoolEnv.js @@ -45,7 +45,7 @@ function PoolEnv() { this.drawCalculator = async () => await ethers.getContract('DrawCalculator'); - this.drawPrize = async (wallet) => (await ethers.getContract('DrawPrize')).connect(wallet); + this.prizeDistributor = async (wallet) => (await ethers.getContract('PrizeDistributor')).connect(wallet); this.rng = async () => await ethers.getContract('RNGServiceStub'); @@ -76,7 +76,7 @@ function PoolEnv() { debug(`Bought tickets`); }; - this.buyTicketsForDrawPrize = async function ({ user, tickets, drawPrize }) { + this.buyTicketsForPrizeDistributor = async function ({ user, tickets, prizeDistributor }) { debug(`Buying tickets...`); const owner = await this.wallet(0); let wallet = await this.wallet(user); @@ -100,9 +100,9 @@ function PoolEnv() { await prizePool.depositTo(wallet.address, amount, this.overrides); debug(`Bought tickets`); - ticket.transfer(drawPrize, amount); + ticket.transfer(prizeDistributor, amount); - debug(`Transfer tickets to drawPrize`); + debug(`Transfer tickets to prizeDistributor`); }; this.expectUserToHaveTickets = async function ({ user, tickets }) { @@ -123,10 +123,10 @@ function PoolEnv() { this.claim = async function ({ user, drawId, picks }) { const wallet = await this.wallet(user); - const drawPrize = await this.drawPrize(wallet); + const prizeDistributor = await this.prizeDistributor(wallet); const encoder = ethers.utils.defaultAbiCoder; const pickIndices = encoder.encode(['uint256[][]'], [[picks]]); - await drawPrize.claim(wallet.address, [drawId], pickIndices); + await prizeDistributor.claim(wallet.address, [drawId], pickIndices); }; this.withdraw = async function ({ user, tickets }) { diff --git a/test/features/ticket.test.js b/test/features/ticket.test.js index 311e8119..00c23cd4 100644 --- a/test/features/ticket.test.js +++ b/test/features/ticket.test.js @@ -30,10 +30,10 @@ describe('Tickets', () => { // NOT a COMPLETE test. Needs to be fixed - out of scope for this PR. it.skip('should allow a user to pull their prizes', async () => { await env.buyTickets({ user: 1, tickets: 100 }); - await env.buyTicketsForDrawPrize({ + await env.buyTicketsForPrizeDistributor({ user: 1, tickets: 100, - drawPrize: (await env.drawPrize()).address, + prizeDistributor: (await env.prizeDistributor()).address, }); const wallet = await env.wallet(1);