Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pool 2870 update prizepool vault to be able to redistribute prizes #14

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
[submodule "lib/v5-prize-pool"]
path = lib/v5-prize-pool
url = https://github.com/pooltogether/v5-prize-pool
branch = pool-2870-update-prizepool-vault-to-be-able-to-redistribute-prizes
[submodule "lib/owner-manager-contracts"]
path = lib/owner-manager-contracts
url = https://github.com/pooltogether/owner-manager-contracts
[submodule "lib/v5-vrgda-claimer"]
path = lib/v5-vrgda-claimer
url = https://github.com/pooltogether/v5-vrgda-claimer
[submodule "lib/ring-buffer-lib"]
path = lib/ring-buffer-lib
url = https://github.com/pooltogether/ring-buffer-lib
Expand Down
1 change: 0 additions & 1 deletion lib/v5-vrgda-claimer
Submodule v5-vrgda-claimer deleted from a48b7b
1 change: 0 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ v5-liquidator-libraries/=lib/v5-liquidator/src/libraries/
v5-liquidator-test/=lib/v5-liquidator/test/
v5-prize-pool/=lib/v5-prize-pool/src/
v5-twab-controller/=lib/v5-twab-controller/src/
v5-vrgda-claimer/=lib/v5-vrgda-claimer/src/

src/=src/
test/=test/
103 changes: 92 additions & 11 deletions src/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { LiquidationPair } from "v5-liquidator/LiquidationPair.sol";
import { ILiquidationSource } from "v5-liquidator-interfaces/ILiquidationSource.sol";
import { PrizePool } from "v5-prize-pool/PrizePool.sol";
import { TwabController } from "v5-twab-controller/TwabController.sol";
import { Claimer } from "v5-vrgda-claimer/Claimer.sol";
import { VaultHooks } from "src/interfaces/IVaultHooks.sol";

/// @notice Emitted when the TWAB controller is set to the zero address
error TwabControllerZeroAddress();
Expand Down Expand Up @@ -133,7 +133,7 @@ contract Vault is ERC4626, ERC20Permit, ILiquidationSource, Ownable {
TwabController twabController,
IERC4626 indexed yieldVault,
PrizePool indexed prizePool,
Claimer claimer,
address claimer,
address yieldFeeRecipient,
uint256 yieldFeePercentage,
address owner
Expand All @@ -144,7 +144,14 @@ contract Vault is ERC4626, ERC20Permit, ILiquidationSource, Ownable {
* @param previousClaimer Address of the previous claimer
* @param newClaimer Address of the new claimer
*/
event ClaimerSet(Claimer previousClaimer, Claimer newClaimer);
event ClaimerSet(address previousClaimer, address newClaimer);

/**
* @notice Emitted when an account sets new hooks
* @param account The account whose hooks are being configured
* @param hooks The hooks being set
*/
event SetHooks(address account, VaultHooks hooks);

/**
* @notice Emitted when a new LiquidationPair has been set.
Expand Down Expand Up @@ -195,7 +202,7 @@ contract Vault is ERC4626, ERC20Permit, ILiquidationSource, Ownable {
PrizePool private immutable _prizePool;

/// @notice Address of the claimer.
Claimer private _claimer;
address private _claimer;

/// @notice Address of the LiquidationPair used to liquidate yield for prize token.
LiquidationPair private _liquidationPair;
Expand All @@ -218,6 +225,9 @@ contract Vault is ERC4626, ERC20Permit, ILiquidationSource, Ownable {
/// @notice Fee precision denominated in 9 decimal places and used to calculate yield fee percentage.
uint256 private constant FEE_PRECISION = 1e9;

/// @notice Allows users to add hooks that execute code when prizes are won
mapping(address => VaultHooks) internal _hooks;

/* ============ Constructor ============ */

/**
Expand All @@ -241,7 +251,7 @@ contract Vault is ERC4626, ERC20Permit, ILiquidationSource, Ownable {
TwabController twabController_,
IERC4626 yieldVault_,
PrizePool prizePool_,
Claimer claimer_,
address claimer_,
address yieldFeeRecipient_,
uint256 yieldFeePercentage_,
address _owner
Expand Down Expand Up @@ -569,20 +579,72 @@ contract Vault is ERC4626, ERC20Permit, ILiquidationSource, Ownable {
* - caller can be any address except claimer address
* @param _tier Tier to claim prize for
* @param _winners Addresses of the winners to claim prizes
* @param _prizes The prizes to claim for each winner
* @param _prizeIndices The prizes to claim for each winner
* @param _feePerClaim Fee to be charged per prize claim
* @param _claimFeeRecipient Address that will receive `_claimFee` amount
*/
function claimPrizes(
uint8 _tier,
address[] calldata _winners,
uint32[][] calldata _prizes,
uint32[][] calldata _prizeIndices,
uint96 _feePerClaim,
address _claimFeeRecipient
) external returns (uint256) {
if (msg.sender != address(_claimer)) revert CallerNotClaimer(msg.sender, address(_claimer));

return _prizePool.claimPrizes(_tier, _winners, _prizes, _feePerClaim, _claimFeeRecipient);
uint totalPrizes;

for (uint w = 0; w < _winners.length; w++) {
uint prizeIndicesLength = _prizeIndices[w].length;
for (uint p = 0; p < prizeIndicesLength; p++) {
totalPrizes += _claimPrize(
_winners[w],
_tier,
_prizeIndices[w][p],
_feePerClaim,
_claimFeeRecipient
);
}
}

return totalPrizes;
}

function _claimPrize(
address _winner,
uint8 _tier,
uint32 _prizeIndex,
uint96 _fee,
address _feeRecipient
) internal returns (uint256) {
VaultHooks memory hooks = _hooks[_winner];
address recipient;
if (hooks.useBeforeClaimPrize) {
recipient = hooks.implementation.beforeClaimPrize(_winner, _tier, _prizeIndex);
} else {
recipient = _winner;
}

uint prizeTotal = _prizePool.claimPrize(
_winner,
_tier,
_prizeIndex,
recipient,
_fee,
_feeRecipient
);

if (hooks.useAfterClaimPrize) {
hooks.implementation.afterClaimPrize(
_winner,
_tier,
_prizeIndex,
prizeTotal - _fee,
recipient
);
}

return prizeTotal;
}

/**
Expand All @@ -609,14 +671,33 @@ contract Vault is ERC4626, ERC20Permit, ILiquidationSource, Ownable {
* @param claimer_ Address of the claimer
* return address New claimer address
*/
function setClaimer(Claimer claimer_) external onlyOwner returns (address) {
Claimer _previousClaimer = _claimer;
function setClaimer(address claimer_) external onlyOwner returns (address) {
address _previousClaimer = _claimer;
_setClaimer(claimer_);

emit ClaimerSet(_previousClaimer, claimer_);
return address(claimer_);
}

/**
* @notice Sets the hooks for a winner
* @param hooks The hooks to set.
*/
function setHooks(VaultHooks memory hooks) external {
_hooks[msg.sender] = hooks;

emit SetHooks(msg.sender, hooks);
}

/**
* @notice Gets the hooks for the given user
* @param _account The user to retrieve the hooks for
* @return The hooks for the given user
*/
function getHooks(address _account) external view returns (VaultHooks memory) {
return _hooks[_account];
}

/**
* @notice Set liquidationPair.
* @dev We reset approval of the previous liquidationPair and approve max for new one.
Expand Down Expand Up @@ -1075,7 +1156,7 @@ contract Vault is ERC4626, ERC20Permit, ILiquidationSource, Ownable {
* @notice Set claimer address.
* @param claimer_ Address of the claimer
*/
function _setClaimer(Claimer claimer_) internal {
function _setClaimer(address claimer_) internal {
_claimer = claimer_;
}

Expand Down
3 changes: 1 addition & 2 deletions src/VaultFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { IERC20, IERC4626 } from "openzeppelin/token/ERC20/extensions/ERC4626.so
import { LiquidationPair } from "v5-liquidator/LiquidationPair.sol";
import { PrizePool } from "v5-prize-pool/PrizePool.sol";
import { TwabController } from "v5-twab-controller/TwabController.sol";
import { Claimer } from "v5-vrgda-claimer/Claimer.sol";

import { Vault } from "./Vault.sol";

Expand Down Expand Up @@ -55,7 +54,7 @@ contract VaultFactory {
TwabController _twabController,
IERC4626 _yieldVault,
PrizePool _prizePool,
Claimer _claimer,
address _claimer,
address _yieldFeeRecipient,
uint256 _yieldFeePercentage,
address _owner
Expand Down
39 changes: 39 additions & 0 deletions src/interfaces/IVaultHooks.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

struct VaultHooks {
/// @notice If true, the vault will call the beforeClaimPrize hook on the implementation
bool useBeforeClaimPrize;
/// @notice If true, the vault will call the afterClaimPrize hook on the implementation
bool useAfterClaimPrize;
/// @notice The address of the smart contract implementing the hooks
IVaultHooks implementation;
}

/// @notice Allows winners to attach smart contract hooks to their prize winnings
interface IVaultHooks {
/// @notice Triggered before the prize pool claim prize function is called.
/// @param winner The user who won the prize and for whom this hook is attached
/// @param tier The tier of the prize
/// @param prizeIndex The index of the prize in the tier
/// @return The address of the recipient of the prize
function beforeClaimPrize(
address winner,
uint8 tier,
uint32 prizeIndex
) external returns (address);

/// @notice Triggered after the prize pool claim prize function is called.
/// @param winner The user who won the prize and for whom this hook is attached
/// @param tier The tier of the prize
/// @param prizeIndex The index of the prize
/// @param payout The amount of tokens paid out to the recipient
/// @param recipient The recipient of the prize
function afterClaimPrize(
address winner,
uint8 tier,
uint32 prizeIndex,
uint256 payout,
address recipient
) external returns (bool);
}
4 changes: 2 additions & 2 deletions test/contracts/mock/Vault.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import { IERC20, IERC4626, Claimer, PrizePool, TwabController, Vault } from "src/Vault.sol";
import { IERC20, IERC4626, PrizePool, TwabController, Vault } from "src/Vault.sol";

contract VaultMock is Vault {
constructor(
Expand All @@ -11,7 +11,7 @@ contract VaultMock is Vault {
TwabController twabController_,
IERC4626 yieldVault_,
PrizePool prizePool_,
Claimer claimer_,
address claimer_,
address yieldFeeRecipient_,
uint256 yieldFeePercentage_,
address _owner
Expand Down
5 changes: 2 additions & 3 deletions test/fuzz/Vault.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Strings } from "openzeppelin/utils/Strings.sol";
import { LiquidationPair } from "v5-liquidator/LiquidationPair.sol";
import { PrizePool } from "v5-prize-pool/PrizePool.sol";
import { TwabController } from "v5-twab-controller/TwabController.sol";
import { Claimer } from "v5-vrgda-claimer/Claimer.sol";

import { Vault } from "src/Vault.sol";

Expand Down Expand Up @@ -47,7 +46,7 @@ contract VaultFuzzTest is ERC4626Test, Helpers {

prizeToken = new ERC20Mock();

twabController = new TwabController();
twabController = new TwabController(1 days, uint32(block.timestamp));

prizePool = new PrizePoolMock(prizeToken);

Expand All @@ -64,7 +63,7 @@ contract VaultFuzzTest is ERC4626Test, Helpers {
twabController,
yieldVault,
PrizePool(address(prizePool)),
Claimer(address(0x2faD9255711A4d22C35a003b3E723D9271aeA51d)),
address(0x2faD9255711A4d22C35a003b3E723D9271aeA51d),
address(this),
0,
address(this)
Expand Down
Loading
Loading