Skip to content

Commit d3d0343

Browse files
committed
add boost hook draft code
1 parent c7171f9 commit d3d0343

4 files changed

Lines changed: 133 additions & 9 deletions

File tree

.gitmodules

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
[submodule "lib/openzeppelin-contracts"]
99
path = lib/openzeppelin-contracts
1010
url = https://github.com/OpenZeppelin/openzeppelin-contracts
11+
branch = release-v5.0

remappings.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
forge-std/=lib/forge-std/src/
1+
forge-std/=lib/forge-std/src/

src/Foo.sol

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.24;
3+
4+
import { IPrizeHooks } from "../lib/pt-v5-vault/src/interfaces/IPrizeHooks.sol";
5+
import { PrizePool } from "../lib/pt-v5-vault/lib/pt-v5-prize-pool/src/PrizePool.sol";
6+
import { IERC20 } from "../lib/pt-v5-vault/lib/pt-v5-prize-pool/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol";
7+
import { Ownable2Step, Ownable } from "../lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol";
8+
9+
/// @title PoolTogether V5 - World Verified Prize Boost Hook
10+
/// @notice This contract is a prize hook for PoolTogether V5 that sends an additional multiplier of prize tokens to the winner
11+
/// if the winning address is verified with a world ID.
12+
/// @author G9 Software Inc.
13+
contract WorldVerifiedPrizeBoostHook is Ownable2Step, IPrizeHooks {
14+
/// @notice Emitted when a prize win is boosted
15+
/// @param recipient The recipient of the prize and boost
16+
/// @param vault The vault the prize was won through
17+
/// @param prizeAmount The original prize tokens won
18+
/// @param boostAmount The amount of boosted prize tokens sent to the recipient
19+
/// @param tier The prize tier won
20+
event VerifiedPrizeBoosted(address indexed recipient, address indexed vault, uint256 prizeAmount, uint256 boostAmount, uint8 tier);
21+
22+
/// @notice Emitted when the boost multiplier is set
23+
/// @param boostMultiplier The new boost multiplier
24+
event SetBoostMultiplier(uint256 boostMultiplier);
25+
26+
/// @notice Emitted when the per winner boost limit is set
27+
/// @param perWinnerBoostLimit The new boost limit in prize tokens
28+
event SetPerWinnerBoostLimit(uint256 perWinnerBoostLimit);
29+
30+
/// @notice The prize pool that is eligible for boosting
31+
PrizePool public immutable PRIZE_POOL;
32+
33+
/// @notice The prize token used for boosting
34+
IERC20 public immutable PRIZE_TOKEN;
35+
36+
/// @notice Mapping to keep track of boosted prizes and prevent replay attacks
37+
mapping(
38+
address vault => mapping(
39+
address account => mapping(
40+
uint24 drawId => mapping(
41+
uint8 tier => mapping(
42+
uint32 prizeIndex => bool hooked
43+
)
44+
)
45+
)
46+
)
47+
) public isPrizeBoosted;
48+
49+
/// @notice The prize boost multiplier
50+
uint256 public boostMultiplier;
51+
52+
/// @notice The maximum total boost tokens that can be won by each verified address
53+
uint256 public perWinnerBoostLimit;
54+
55+
/// @notice The total boost tokens that have been received by an address
56+
mapping(address => uint256) public boostTokensReceived;
57+
58+
/// @notice Constructor to set parameters for the vault hook
59+
/// @param _prizePool The prize pool to boost wins from
60+
/// @param _initialOwner The initial owner of the vault hook
61+
/// @param _boostMultiplier The integer multipler that determines the boost amount from the prize won
62+
/// (ex. **1x** boost Multiplier will send **1x** the prize amount as a boost to the winner, effectively creating a **2x** prize multiplier)
63+
/// @param _perWinnerBoostLimit The initial max amount of total boosted prize tokens that will be sent to any verified address over any amount of time
64+
constructor(PrizePool _prizePool, address _initialOwner, uint256 _boostMultiplier, uint256 _perWinnerBoostLimit) Ownable(_initialOwner) {
65+
PRIZE_POOL = _prizePool;
66+
PRIZE_TOKEN = _prizePool.prizeToken();
67+
_setBoostMultiplier(_boostMultiplier);
68+
_setPerWinnerBoostLimit(_perWinnerBoostLimit);
69+
}
70+
71+
/// @inheritdoc IPrizeHooks
72+
/// @dev This prize hook does not implement the `beforeClaimPrize` call, but it is still required in the
73+
/// IPrizeHooks interface.
74+
function beforeClaimPrize(address, uint8, uint32, uint96, address) external pure returns (address, bytes memory) {}
75+
76+
/// @inheritdoc IPrizeHooks
77+
/// @notice Sends `boostMultiplier` times the prize amount in *extra* prize tokens to the winner if the winner's address
78+
/// is verified and the prize hasn't already been boosted.
79+
/// @dev Ensures the winner is the recipient (this will always be the case on standard vaults using this hook)
80+
/// @dev Caps the boost amount to prevent the total amount of boost tokens the winner receives from exceeding the
81+
/// `perWinnerBoostLimit`.
82+
/// @dev Fails silently as to not interrupt a prize claim if the prize is not eligible for a boost or if
83+
/// this contract runs out of boost funds.
84+
function afterClaimPrize(address winner, uint8 tier, uint32 prizeIndex, uint256 prizeAmount, address recipient, bytes memory) external {
85+
uint24 awardedDrawId = PRIZE_POOL.getLastAwardedDrawId();
86+
uint256 winnerPreviousBoostReceived = boostTokensReceived[winner];
87+
if (
88+
winner == recipient &&
89+
PRIZE_POOL.isWinner(msg.sender, winner, tier, prizeIndex) &&
90+
!isPrizeBoosted[msg.sender][winner][awardedDrawId][tier][prizeIndex] &&
91+
winnerPreviousBoostReceived < perWinnerBoostLimit
92+
) {
93+
uint256 boostAmount = prizeAmount * boostMultiplier;
94+
if (winnerPreviousBoostReceived + boostAmount > perWinnerBoostLimit) {
95+
boostAmount = perWinnerBoostLimit - winnerPreviousBoostReceived;
96+
}
97+
if (
98+
boostAmount > 0 &&
99+
PRIZE_TOKEN.balanceOf(address(this)) >= boostAmount
100+
) {
101+
isPrizeBoosted[msg.sender][winner][awardedDrawId][tier][prizeIndex] = true;
102+
PRIZE_TOKEN.transfer(winner, boostAmount);
103+
emit VerifiedPrizeBoosted(winner, msg.sender, prizeAmount, boostAmount, tier);
104+
}
105+
}
106+
}
107+
108+
/// @notice ONLY OWNER function to change the boost multiplier
109+
/// @param _boostMultiplier The new integer boost multiplier
110+
function setBoostMultiplier(uint256 _boostMultiplier) external onlyOwner {
111+
_setBoostMultiplier(_boostMultiplier);
112+
}
113+
114+
/// @notice ONLY OWNER function to change the per winner boost limit
115+
/// @param _perWinnerBoostLimit The new per winner boost limit
116+
function setPerWinnerBoostLimit(uint256 _perWinnerBoostLimit) external onlyOwner {
117+
_setPerWinnerBoostLimit(_perWinnerBoostLimit);
118+
}
119+
120+
/// @notice Sets the boost multiplier and emits an event
121+
function _setBoostMultiplier(uint256 _boostMultiplier) internal {
122+
boostMultiplier = _boostMultiplier;
123+
emit SetBoostMultiplier(_boostMultiplier);
124+
}
125+
126+
/// @notice Sets the per winner boost limit and emits an event
127+
function _setPerWinnerBoostLimit(uint256 _perWinnerBoostLimit) internal {
128+
perWinnerBoostLimit = _perWinnerBoostLimit;
129+
emit SetPerWinnerBoostLimit(_perWinnerBoostLimit);
130+
}
131+
}

0 commit comments

Comments
 (0)