The contract implements a tournament-style ERC-4626 vault, where deposits are only allowed before the event starts and withdrawals only after the winner is finalized.
However, not all ERC-4626 interface functions enforce these timing restrictions:
While no direct loss of funds is possible, these inconsistencies can confuse wallets, explorers, and DeFi protocols that rely on ERC-4626 introspection (e.g., for displaying available deposit/withdraw limits), leading to a poor or misleading user experience.
To align behavior with the intended tournament rules and ERC-4626 best practices, implement the following overrides:
/**
* @notice Override ERC4626 mint to prevent bypassing deposit logic
* @dev Users must use custom deposit() function
*/
function mint(uint256 shares, address receiver) public pure override returns (uint256) {
revert("Use deposit(uint256 assets, address receiver) instead");
}
/**
* @notice Override maxWithdraw to return 0 until event ends
* @dev Prevents wallet UIs from showing withdraw button
*/
function maxWithdraw(address owner) public view override returns (uint256) {
// Can't withdraw until winner is set and event ended
if (!_setWinner || block.timestamp < eventEndDate) {
return 0;
}
// Check if user won
if (
keccak256(abi.encodePacked(userToCountry[owner])) !=
keccak256(abi.encodePacked(winner))
) {
return 0;
}
// Calculate winner's share
uint256 shares = balanceOf(owner);
if (shares == 0 || totalWinnerShares == 0) {
return 0;
}
uint256 vaultAsset = finalizedVaultAsset;
return Math.mulDiv(shares, vaultAsset, totalWinnerShares);
}
/**
* @notice Override maxRedeem to return 0 until event ends
* @dev Prevents wallet UIs from showing redeem button
*/
function maxRedeem(address owner) public view override returns (uint256) {
// Can't redeem until winner is set and event ended
if (!_setWinner || block.timestamp < eventEndDate) {
return 0;
}
// Check if user won
if (
keccak256(abi.encodePacked(userToCountry[owner])) !=
keccak256(abi.encodePacked(winner))
) {
return 0;
}
// Return user's shares if they won
return balanceOf(owner);
}
/**
* @notice Override maxDeposit to prevent deposits after event starts
* @dev Prevents bypassing deposit time restrictions
*/
function maxDeposit(address) public view override returns (uint256) {
if (block.timestamp >= eventStartDate) {
return 0;
}
// Otherwise allow unlimited deposits
return type(uint256).max;
}
/**
* @notice Override maxMint to prevent minting after event starts
* @dev Prevents bypassing deposit time restrictions
*/
function maxMint(address) public view override returns (uint256) {
if (block.timestamp >= eventStartDate) {
return 0;
}
return type(uint256).max;
}