This repository contains the staking contracts for the Meme Coin Prediction Market (MCPM).
The contracts are based on well-known and audited implementations by Swapsicle. Below are the main contracts included in this repository:
- IceCreamVan: A simplified version of MasterChefV2, with rewards distributed based on blocks.
- IceCreamVanV2: A simplified version of MasterChefV2, with rewards distributed based on seconds.
The initial version of the IceCreamVan contract has been audited by Vibranium Audits. You can find the audit report here or download the PDF directly.
The MCPMFarm contract is a fork of the IceCreamVanV2 contract, tailored to meet the needs of the Meme Coin Prediction Market. It introduces several enhancements and features:
-
Vesting:
- Allows external contracts (e.g., airdrop contracts) to deposit tokens for users with a lockup period.
- Vested tokens earn rewards during the lockup period but cannot be withdrawn until the vesting period ends.
- The vesting period must be at least
MINIMUM_VESTING_SECONDS(1 year).
-
Rewards Distribution:
- Rewards are distributed based on seconds rather than blocks.
- Includes logic to calculate overpaid rewards when distributions are delayed beyond the cycle duration.
-
Cycle Management:
- Supports configurable reward cycles (
cycleDuration) and calculates rewards per second for each cycle. - Tracks overpaid rewards when distributions are late.
- Supports configurable reward cycles (
vest: Deposits tokens for users with a lockup period, allowing them to earn rewards while holding their tokens.distributeRewards: Updates therewardsPerSecondvariable and distributes rewards to stakers. Handles overpaid rewards when distributions are delayed.getWithdrawableAmount: Calculates the amount of staked tokens that can be withdrawn, excluding vested tokens.sweepErc20: Allows the operator to withdraw non-staking and non-reward tokens sent to the contract by mistake.
Deposit: Emitted when a user deposits tokens.Withdraw: Emitted when a user withdraws tokens.EmergencyWithdraw: Emitted when a user withdraws tokens without claiming rewards.UpdateRewardsPerSecond: Emitted when the rewards per second are updated.RewardsDistribution: Emitted when rewards are distributed.
The contract uses custom errors for better gas efficiency and clarity:
InvalidAmountInvalidCycleDurationInsufficientBalanceSweepingContractTokensNotAllowed- And others.
Below is a dummy function illustrating how rewards might be distributed from an external betting contract:
/// @notice Dummy distribute function for the external distributor, to distribute rewards.
function _distribute() private {
uint256 rewardsAmount; // dummy variable, this should be a global variable (or similar) in the betting contract
IMCPMFarm farm = IMCPMFarm(address(this));
if (block.timestamp >= farm.nextRewardsDistribution()) { // nextRewardsDistribution is when the next rewards distribution should occur
farm.distributeRewards(rewardsAmount);
rewardsAmount = 0; // assuming there is a global rewardsAmount variable, reset it to 0 after distribution
}
}