// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IGhostWarmup} from "./interfaces/IGhostWarmup.sol"; import {IGHST} from "./interfaces/IGHST.sol"; import {FullMath} from "./libraries/FullMath.sol"; contract GhostWarmup is IGhostWarmup { address public immutable STAKING; address public immutable GHST; uint256 private _ghstInWarmup; mapping(address => Claim) private _warmupInfo; constructor(address ghst) { STAKING = msg.sender; GHST = ghst; } function addToWarmup( uint256 payout, address who, uint48 expiry ) external override { if (msg.sender != STAKING) revert NotStakingContract(); Claim storage info = _warmupInfo[who]; uint256 ghstPayout = IGHST(GHST).balanceTo(payout); info.deposit += payout; info.payout += ghstPayout; info.expiry = expiry; _ghstInWarmup += ghstPayout; } function claim( address to, uint256 epochNumber ) external override returns (uint256 claimedAmount) { if (msg.sender != STAKING) revert NotStakingContract(); Claim memory info = _warmupInfo[to]; if (epochNumber >= info.expiry && info.expiry > 0) { delete _warmupInfo[to]; _ghstInWarmup -= info.payout; claimedAmount = info.payout; } } function breakout(address who, uint256 payout) external override { if (msg.sender != STAKING) revert NotStakingContract(); Claim storage info = _warmupInfo[who]; uint256 depositReduction = FullMath.mulDiv(info.deposit, payout, info.payout); info.deposit -= depositReduction; info.payout -= payout; _ghstInWarmup -= payout; } function forfeit(address who) external override returns (uint256) { if (msg.sender != STAKING) revert NotStakingContract(); Claim memory info = _warmupInfo[who]; delete _warmupInfo[who]; _ghstInWarmup -= info.payout; return info.deposit; } function ghstInWarmup() external view override returns (uint256) { return _ghstInWarmup; } function warmupInfo(address who) external view override returns (uint256, uint256, uint48) { Claim memory info = _warmupInfo[who]; return (info.deposit, info.payout, info.expiry); } }