// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import "@equilibria/root/token/types/Token18.sol"; import "../IProduct.sol"; import "./Position.sol"; import "./Accumulator.sol"; /// @dev ProgramInfo type struct ProgramInfo { /// @dev Coordinator for this program uint256 coordinatorId; /// @dev Amount of total maker and taker rewards Position amount; /// @dev start timestamp of the program uint256 start; /// @dev duration of the program (in seconds) uint256 duration; /** * @dev Reward ERC20 token contract * @notice Perennial does not support non-standard ERC20s as reward tokens for incentive programs, including, but not limited to: fee on transfer and rebase tokens. Using such a non-standard token will likely result in loss of funds. */ Token18 token; } using ProgramInfoLib for ProgramInfo global; /** * @title ProgramInfoLib * @notice Library that snapshots the static information for a single program. * @dev This information does not change during the operation of a program. */ library ProgramInfoLib { uint256 private constant MIN_DURATION = 1 days; uint256 private constant MAX_DURATION = 2 * 365 days; error ProgramInvalidStartError(); error ProgramInvalidDurationError(); /** * @notice Validates and creates a new Program * @dev Reverts for invalid programInfos * @param programInfo Un-sanitized static program information */ function validate(ProgramInfo memory programInfo) internal view { if (isStarted(programInfo, block.timestamp)) revert ProgramInvalidStartError(); if (programInfo.duration < MIN_DURATION || programInfo.duration > MAX_DURATION) revert ProgramInvalidDurationError(); } /** * @notice Computes a new program info with the fee taken out of the amount * @param programInfo Original program info * @param incentivizationFee The incentivization fee * @return New program info * @return Fee amount */ function deductFee(ProgramInfo memory programInfo, UFixed18 incentivizationFee) internal pure returns (ProgramInfo memory, UFixed18) { Position memory newProgramAmount = programInfo.amount.mul(UFixed18Lib.ONE.sub(incentivizationFee)); UFixed18 programFeeAmount = programInfo.amount.sub(newProgramAmount).sum(); programInfo.amount = newProgramAmount; return (programInfo, programFeeAmount); } /** * @notice Returns the maker and taker amounts per position share * @param self The ProgramInfo to operate on * @return programFee Amounts per share */ function amountPerShare(ProgramInfo memory self) internal pure returns (Accumulator memory) { return self.amount.div(self.duration); } /** * @notice Returns whether the program has started by timestamp `timestamp` * @param self The ProgramInfo to operate on * @param timestamp Timestamp to check for * @return Whether the program has started */ function isStarted(ProgramInfo memory self, uint256 timestamp) internal pure returns (bool) { return timestamp >= self.start; } /** * @notice Returns whether the program is completed by timestamp `timestamp` * @param self The ProgramInfo to operate on * @param timestamp Timestamp to check for * @return Whether the program is completed */ function isComplete(ProgramInfo memory self, uint256 timestamp) internal pure returns (bool) { return timestamp >= (self.start + self.duration); } }