Skip to content

Commit

Permalink
Renamed to RewardBurner
Browse files Browse the repository at this point in the history
  • Loading branch information
asselstine committed Mar 22, 2024
1 parent 5d3edcc commit a438974
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 55 deletions.
14 changes: 2 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
# Foundry template
# PoolTogether V5 Reward Burner

Template to kickstart a Foundry project.

## Getting started

The easiest way to get started is by clicking the [Use this template](https://github.com/GenerationSoftware/foundry-template/generate) button at the top right of this page.

If you prefer to go the CLI way:

```
forge init my-project --template https://github.com/GenerationSoftware/foundry-template
```
This contract is a liquidation source that exposes any accrued rewards from a Prize Pool. Liquidations are sent to the "dead" address.

## Development

Expand Down
34 changes: 24 additions & 10 deletions src/FeeBurner.sol → src/RewardBurner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,80 @@ pragma solidity ^0.8.24;
import { ILiquidationSource } from "pt-v5-liquidator-interfaces/ILiquidationSource.sol";
import { PrizePool } from "pt-v5-prize-pool/PrizePool.sol";

contract FeeBurner is ILiquidationSource {
/// @title RewardBurner
/// @notice Exposes it's Prize Pool rewards as an ILiquidationSource
contract RewardBurner is ILiquidationSource {

/// @notice The address to which tokens are sent to be burned
address public constant DEAD_ADDRESS = 0x000000000000000000000000000000000000dEaD;

/// @notice The prize pool from whom the rewards will be burned.
PrizePool public immutable prizePool;
address public immutable burnToken;

/// @notice The address that deployed this contract
address public immutable creator;

/// @notice The liquidation pair that is authorized to liquidate the rewards
address public liquidationPair;

constructor(PrizePool _prizePool, address _burnToken, address _creator) {
/// @notice Constructs a new RewardBurner
constructor(PrizePool _prizePool, address _creator) {
prizePool = _prizePool;
burnToken = _burnToken;
creator = _creator;
}

/// @notice Allows the creator to set the liquidation pair; can only be called if the pair has not been set.
/// @param _liquidationPair The address of the liquidation pair
function setLiquidationPair(address _liquidationPair) external {
require(liquidationPair == address(0), "FeeBurner: Liquidation pair already set");
require(msg.sender == creator, "FeeBurner: Only creator can set liquidation pair");
require(liquidationPair == address(0), "RewardBurner: Liquidation pair already set");
require(msg.sender == creator, "RewardBurner: Only creator can set liquidation pair");
liquidationPair = _liquidationPair;
emit LiquidationPairSet(address(prizePool.prizeToken()), _liquidationPair);
}

/// @inheritdoc ILiquidationSource
function liquidatableBalanceOf(address tokenOut) external returns (uint256) {
if (tokenOut != address(prizePool.prizeToken())) {
return 0;
}
return prizePool.rewardBalance(address(this));
}

/// @inheritdoc ILiquidationSource
function transferTokensOut(
address sender,
address receiver,
address tokenOut,
uint256 amountOut
) external onlyLiquidationPair returns (bytes memory) {
require(tokenOut == address(prizePool.prizeToken()), "FeeBurner: Invalid tokenOut");
require(tokenOut == address(prizePool.prizeToken()), "RewardBurner: Invalid tokenOut");
prizePool.withdrawRewards(receiver, amountOut);
}

/// @inheritdoc ILiquidationSource
function verifyTokensIn(
address tokenIn,
uint256 amountIn,
bytes calldata transferTokensOutData
) external {
require(tokenIn == burnToken, "FeeBurner: Invalid tokenIn");
}

/// @inheritdoc ILiquidationSource
function targetOf(address tokenIn) external returns (address) {
return DEAD_ADDRESS;
}

/// @inheritdoc ILiquidationSource
function isLiquidationPair(address _tokenOut, address _liquidationPair) external returns (bool) {
if (_tokenOut != address(prizePool.prizeToken())) {
return false;
}
return liquidationPair == _liquidationPair;
}

/// @notice Modifier that only allows the liquidation pair to call the function
modifier onlyLiquidationPair() {
require(msg.sender == liquidationPair, "FeeBurner: Only liquidation pair");
require(msg.sender == liquidationPair, "RewardBurner: Only liquidation pair");
_;
}
}
}
40 changes: 20 additions & 20 deletions src/FeeBurnerFactory.sol → src/RewardBurnerFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,33 @@ pragma solidity ^0.8.24;
import { IERC20, IERC4626 } from "openzeppelin/token/ERC20/extensions/ERC4626.sol";
import { PrizePool } from "pt-v5-prize-pool/PrizePool.sol";

import { FeeBurner } from "./FeeBurner.sol";
import { RewardBurner } from "./RewardBurner.sol";

/**
* @title PoolTogether V5 Prize Vault Factory
* @author PoolTogether Inc. & G9 Software Inc.
* @notice Factory contract for deploying new prize vaults using a standard underlying ERC4626 yield vault.
*/
contract FeeBurnerFactory {
contract RewardBurnerFactory {
/* ============ Events ============ */

/**
* @notice Emitted when a new FeeBurner has been deployed by this factory.
* @notice Emitted when a new RewardBurner has been deployed by this factory.
* @param feeBurner The Fee Burner that was created
* @param prizePool The prize pool the vault contributes to
*/
event NewFeeBurner(
FeeBurner indexed feeBurner,
event NewRewardBurner(
RewardBurner indexed feeBurner,
PrizePool indexed prizePool
);

/* ============ Variables ============ */

/// @notice List of all vaults deployed by this factory.
FeeBurner[] public allFeeBurners;
RewardBurner[] public allRewardBurners;

/// @notice Mapping to verify if a Vault has been deployed via this factory.
mapping(address vault => bool deployedByFactory) public deployedFeeBurners;
mapping(address vault => bool deployedByFactory) public deployedRewardBurners;

/// @notice Mapping to store deployer nonces for CREATE2
mapping(address deployer => uint256 nonce) public deployerNonces;
Expand All @@ -39,44 +39,44 @@ contract FeeBurnerFactory {

/**
* @notice Deploy a new Fee Burner
* @return FeeBurner The newly deployed FeeBurner
* @return RewardBurner The newly deployed RewardBurner
*/
function deployFeeBurner(
function deployRewardBurner(
PrizePool _prizePool,
address _burnToken,
address _creator
) external returns (FeeBurner) {
FeeBurner _feeBurner = new FeeBurner{
) external returns (RewardBurner) {
RewardBurner _feeBurner = new RewardBurner{
salt: keccak256(abi.encode(msg.sender, deployerNonces[msg.sender]++))
}(
_prizePool,
_burnToken,
_creator
);

allFeeBurners.push(_feeBurner);
deployedFeeBurners[address(_feeBurner)] = true;
allRewardBurners.push(_feeBurner);
deployedRewardBurners[address(_feeBurner)] = true;

emit NewFeeBurner(
emit NewRewardBurner(
_feeBurner,
_prizePool
);

return _feeBurner;
}

/// @notice Computes the deployment address for a new Reward Burner contract
/// @param _prizePool The prize pool that the rewards are coming from
/// @param _creator The address that will be the creator of the vault
function computeDeploymentAddress(
PrizePool _prizePool,
address _burnToken,
address _creator
) external view returns (address) {
return address(uint160(uint(keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
keccak256(abi.encode(msg.sender, deployerNonces[msg.sender])),
keccak256(abi.encodePacked(
type(FeeBurner).creationCode,
abi.encode(_prizePool, _burnToken, _creator)
type(RewardBurner).creationCode,
abi.encode(_prizePool, _creator)
))
)))));
}
Expand All @@ -86,6 +86,6 @@ contract FeeBurnerFactory {
* @return uint256 Number of vaults deployed by this factory.
*/
function totalVaults() external view returns (uint256) {
return allFeeBurners.length;
return allRewardBurners.length;
}
}
6 changes: 3 additions & 3 deletions test/FeeBurner.t.sol → test/RewardBurner.t.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.21;
pragma solidity ^0.8.24;

import "forge-std/Test.sol";

import { FeeBurner } from "../src/FeeBurner.sol";
import { RewardBurner } from "../src/RewardBurner.sol";

/// @dev See the "Writing Tests" section in the Foundry Book if this is your first time with Forge.
/// https://book.getfoundry.sh/forge/writing-tests
contract FeeBurnerTest is Test {
contract RewardBurnerTest is Test {

function setUp() public {
}
Expand Down
17 changes: 7 additions & 10 deletions test/FeeBurnerFactory.t.sol → test/RewardBurnerFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,32 @@ pragma solidity ^0.8.21;
import "forge-std/Test.sol";

import { PrizePool } from "pt-v5-prize-pool/PrizePool.sol";
import { FeeBurner } from "../src/FeeBurner.sol";
import { FeeBurnerFactory } from "../src/FeeBurnerFactory.sol";
import { RewardBurner } from "../src/RewardBurner.sol";
import { RewardBurnerFactory } from "../src/RewardBurnerFactory.sol";

/// @dev See the "Writing Tests" section in the Foundry Book if this is your first time with Forge.
/// https://book.getfoundry.sh/forge/writing-tests
contract FeeBurnerTest is Test {
contract RewardBurnerTest is Test {

FeeBurnerFactory factory;
RewardBurnerFactory factory;

PrizePool prizePool = PrizePool(makeAddr("prizePool"));
address burnToken = makeAddr("burnToken");
address prizeToken = makeAddr("prizeToken");
address liquidationPair = makeAddr("liquidationPair");

function setUp() public {
factory = new FeeBurnerFactory();
factory = new RewardBurnerFactory();
vm.mockCall(address(prizePool), abi.encodeWithSelector(prizePool.prizeToken.selector), abi.encode(prizeToken));
}

/// @dev Simple test. Run Forge with `-vvvv` to see stack traces.
function test() external {
address expectedAddress = factory.computeDeploymentAddress(prizePool, burnToken, address(this));
FeeBurner burner = factory.deployFeeBurner(
address expectedAddress = factory.computeDeploymentAddress(prizePool, address(this));
RewardBurner burner = factory.deployRewardBurner(
prizePool,
burnToken,
address(this)
);
assertEq(address(burner), expectedAddress, "address was computed correctly");
assertEq(burner.burnToken(), burnToken, "burn token");
assertEq(address(burner.prizePool()), address(prizePool), "prize pool");
assertEq(burner.creator(), address(this), "creator");
assertEq(burner.liquidationPair(), address(0), "liquidation pair");
Expand Down

0 comments on commit a438974

Please sign in to comment.