| Overview | Design | Implementation | Setting the Hook | Use Cases |
In this hook example, we'll demonstrate how a custom hook can be used to boost prizes on a specific vault.
To boost a prize, our hook contract will need to hold some boost tokens and then distribute them in the afterClaimPrize call to prize winners. We can also set a max eligible tier so that people can't easily game the system by claiming normally unprofitable canary prize wins. When the hook is called, it will check to see that the prize meets the tier requirements and that the hook contract holds enough boost tokens before sending a preset boost amount to the prize recipient.
import { IPrizeHooks } from "pt-v5-vault/interfaces/IPrizeHooks.sol";
contract PrizeBoostHook is IPrizeHooks {
// hook code goes here...
}import { IERC20 } from "openzeppelin-v5/interfaces/IERC20.sol";
// ...
address public immutable vault;
IERC20 public immutable boostToken;
uint256 public immutable boostAmount;
uint8 public immutable maxTier;
constructor(address _vault, IERC20 _boostToken, uint256 _boostAmount, uint8 _maxTier) {
vault = _vault;
boostToken = _boostToken;
boostAmount = _boostAmount;
maxTier = _maxTier;
}We set the vault that is eligible for prize boosts, the boost token that will be distributed, and the boost amount that will be sent each time an eligible prize is won. The max eligible tier is also set to allow additional configuration.
event PrizeBoosted(address indexed recipient, address indexed vault, uint256 boostAmount, uint8 tier);
function beforeClaimPrize(address, uint8, uint32, uint96, address) external pure returns (address, bytes memory) {
// We don't use this hook call, so we do nothing
}
function afterClaimPrize(address, uint8 tier, uint32, uint256, address recipient, bytes memory) external {
if (msg.sender == vault && tier <= maxTier && boostToken.balanceOf(address(this)) >= boostAmount) {
boostToken.transfer(recipient, boostAmount);
emit PrizeBoosted(recipient, vault, boostAmount, tier);
}
}Note that we check if the sender is the vault address. This is the simplest way to verify that a prize has actually been won by the recipient, but only works if the vault was deployed through the standard vault factory or supports the same prize hooks.
In the afterClaimPrize call, we check if the prize is valid and if the hook contract has enough boost tokens to transfer before sending the boost to the recipient. If any conditions fail, the hook will simply do nothing instead of reverting. This is to ensure that the depositor still receives their normal prize, even if the boost is no longer running. If the hook reverted, the entire prize claim would revert as well, and it would be impossible for a depositor to receive their prize until they removed the hook.
You can now automatically boost prizes on a vault by distributing additional tokens! See the full implementation here.
If a you want to set this hook on a prize vault, you will need to:
- Deploy the hook contract
- Call
setHookson the prize vault contract with the following information:
VaultHooks({
useBeforeClaimPrize: false;
useAfterClaimPrize: true;
implementation: 0x... // replace with the hook deployment contract
});There are already multiple ways to boost a vault's winning chances by contributing to the prize pool on behalf of the vault, or by using a Vault Booster, but both of those methods require the boost to be paid to the prize pool as prize tokens. By using this prize hook as an incentives program, depositors can opt-in to a prize boost paid directly to them as any token.