编译器
0.8.19+commit.7dd6d404
文件 1 的 10:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 10:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 10:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 4 的 10:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 5 的 10:IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 6 的 10:IFarmBooster.sol
pragma solidity ^0.8.19;
interface IFarmBooster {
function updatePositionBoostMultiplier(address user) external returns (uint256 _multiplier);
}
文件 7 的 10:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 8 的 10:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
文件 9 的 10:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
文件 10 的 10:V2Wrapper.sol
pragma solidity ^0.8.10;
pragma abicoder v2;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IFarmBooster.sol";
contract V2Wrapper is Ownable, ReentrancyGuard {
using SafeERC20 for IERC20Metadata;
using SafeERC20 for IERC20;
address public immutable WRAPPER_FACTORY;
bool public isInitialized;
uint256 public accTokenPerShare;
uint256 public startTimestamp;
uint256 public endTimestamp;
uint256 public lastRewardTimestamp;
uint256 public rewardPerSecond;
uint256 public PRECISION_FACTOR;
IERC20Metadata public stakedToken;
IERC20Metadata public rewardToken;
address public boostContract;
uint256 public totalBoostedShare;
uint256 public constant BOOST_PRECISION = 100 * 1e10;
uint256 public constant MAX_BOOST_PRECISION = 300 * 1e10;
mapping(address => UserInfo) public userInfo;
struct UserInfo {
uint256 amount;
uint256 rewardDebt;
uint256 boostMultiplier;
uint256 boostedAmount;
uint256 unsettledRewards;
}
event Deposit(address indexed user, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 amount);
event NewStartAndEndTimestamp(uint256 oldStartTimestamp, uint256 newStartTimestamp, uint256 oldEndTimestamp, uint256 newEndTimestamp, uint256 rewardPerSecond);
event Restart(uint256 startTimestamp, uint256 endTimestamp, uint256 rewardPerSecond);
event NewRewardPerSecond(uint256 oldRewardPerSecond, uint256 newRewardPerSecond, uint256 startTimestamp, uint256 endTimestamp);
event NewPoolLimit(uint256 poolLimitPerUser);
event RewardsStop(uint256 blockNumber);
event TokenRecovery(address indexed token, uint256 amount);
event Withdraw(address indexed user, uint256 amount);
event DepositAndExpend(address indexed user, uint256 amount, uint256 endTimestamp);
event BoostContractUpdated(address indexed boostContract);
event BoostMultiplierUpdated(address indexed user, uint256 oldMultiplier, uint256 newMultiplier);
constructor() {
WRAPPER_FACTORY = msg.sender;
}
modifier onlyBoostContract() {
require(boostContract == msg.sender, "Ownable: caller is not the boost contract");
_;
}
function initialize(
IERC20Metadata _stakedToken,
IERC20Metadata _rewardToken,
uint256 _rewardPerSecond,
uint256 _startTimestamp,
uint256 _endTimestamp,
address _admin,
address _boostContract
) external {
require(!isInitialized, "Already initialized");
require(msg.sender == WRAPPER_FACTORY, "Not factory");
require(_startTimestamp < _endTimestamp, "New startTimestamp must be lower than new endTimestamp");
require(block.timestamp < _startTimestamp, "New startTimestamp must be higher than current timestamp");
isInitialized = true;
stakedToken = _stakedToken;
rewardToken = _rewardToken;
rewardPerSecond = _rewardPerSecond;
startTimestamp = _startTimestamp;
endTimestamp = _endTimestamp;
boostContract = _boostContract;
uint256 decimalsRewardToken = uint256(rewardToken.decimals());
require(decimalsRewardToken < 30, "Must be inferior to 30");
PRECISION_FACTOR = uint256(10**(uint256(30) - decimalsRewardToken));
require(PRECISION_FACTOR * rewardPerSecond / (10**decimalsRewardToken) >= 10_000_000, "rewardPerSecond must be larger");
lastRewardTimestamp = startTimestamp;
transferOwnership(_admin);
}
function deposit(uint256 _amount, bool _noHarvest) external nonReentrant {
UserInfo storage user = userInfo[msg.sender];
_updatePool();
if (user.amount > 0) {
user.unsettledRewards += _pendingReward(msg.sender);
if (!_noHarvest && user.unsettledRewards > 0) {
rewardToken.safeTransfer(msg.sender, user.unsettledRewards);
user.unsettledRewards = 0;
}
}
if (_amount > 0) {
uint256 _amountBefore = IERC20Metadata(stakedToken).balanceOf(address(this));
stakedToken.safeTransferFrom(msg.sender, address(this), _amount);
uint256 _amountAfter = IERC20Metadata(stakedToken).balanceOf(address(this));
_amount = _amountAfter - _amountBefore;
user.amount = user.amount + _amount;
}
_updateBoostMultiplier(msg.sender, 0);
user.rewardDebt = (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR;
emit Deposit(msg.sender, _amount);
}
function depositRewardAndExpend(uint256 _amount) external nonReentrant {
require(block.timestamp < endTimestamp, "Pool should not ended");
uint256 _rewardAmountBefore = IERC20Metadata(rewardToken).balanceOf(address(this));
IERC20Metadata(rewardToken).safeTransferFrom(msg.sender, address(this), _amount);
uint256 _rewardAmountAfter = IERC20Metadata(rewardToken).balanceOf(address(this));
uint256 _rewardAmount = _rewardAmountAfter - _rewardAmountBefore;
uint256 newEndTimestamp = endTimestamp + _rewardAmount / rewardPerSecond;
require(endTimestamp < newEndTimestamp, "New endTimestamp must be larger than old endTimestamp");
endTimestamp = newEndTimestamp;
emit DepositAndExpend(msg.sender, _rewardAmount, endTimestamp);
}
function withdraw(uint256 _amount, bool _noHarvest) external nonReentrant {
UserInfo storage user = userInfo[msg.sender];
require(user.amount >= _amount, "Amount to withdraw too high");
_updatePool();
user.unsettledRewards += _pendingReward(msg.sender);
if (_amount > 0) {
user.amount = user.amount - _amount;
stakedToken.safeTransfer(msg.sender, _amount);
}
if (!_noHarvest && user.unsettledRewards > 0) {
rewardToken.safeTransfer(msg.sender, user.unsettledRewards);
user.unsettledRewards = 0;
}
_updateBoostMultiplier(msg.sender, 0);
user.rewardDebt = (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR;
emit Withdraw(msg.sender, _amount);
}
function emergencyWithdraw() external nonReentrant {
UserInfo storage user = userInfo[msg.sender];
uint256 amountToTransfer = user.amount;
totalBoostedShare = totalBoostedShare > user.boostedAmount ? totalBoostedShare - user.boostedAmount : 0;
user.amount = 0;
user.boostMultiplier = BOOST_PRECISION;
user.boostedAmount = 0;
user.rewardDebt = 0;
user.unsettledRewards = 0;
if (amountToTransfer > 0) {
stakedToken.safeTransfer(msg.sender, amountToTransfer);
}
emit EmergencyWithdraw(msg.sender, amountToTransfer);
}
function emergencyRewardWithdraw(uint256 _amount) external onlyOwner {
rewardToken.safeTransfer(msg.sender, _amount);
}
function recoverToken(address _token) external onlyOwner {
require(_token != address(stakedToken), "Operations: Cannot recover staked token");
require(_token != address(rewardToken), "Operations: Cannot recover reward token");
uint256 balance = IERC20Metadata(_token).balanceOf(address(this));
require(balance != 0, "Operations: Cannot recover zero balance");
IERC20Metadata(_token).safeTransfer(msg.sender, balance);
emit TokenRecovery(_token, balance);
}
function stopReward() external onlyOwner {
endTimestamp = block.timestamp;
emit RewardsStop(endTimestamp);
}
function updateRewardPerSecond(uint256 _rewardPerSecond) external onlyOwner {
require(block.timestamp < endTimestamp, "Pool should not ended");
uint256 decimalsRewardToken = uint256(rewardToken.decimals());
require(PRECISION_FACTOR * _rewardPerSecond / (10**decimalsRewardToken) >= 100_000_000, "rewardPerSecond must be larger");
_updatePool();
emit NewRewardPerSecond(rewardPerSecond, _rewardPerSecond, startTimestamp, endTimestamp);
rewardPerSecond = _rewardPerSecond;
}
function updateStartAndEndTimestamp(uint256 _startTimestamp, uint256 _endTimestamp) external onlyOwner {
require(block.timestamp < startTimestamp, "Pool has started");
require(_startTimestamp < _endTimestamp, "New startTimestamp must be lower than new endTimestamp");
require(block.timestamp < _startTimestamp, "New startTimestamp must be higher than current timestamp");
emit NewStartAndEndTimestamp(startTimestamp, _startTimestamp, endTimestamp, _endTimestamp, rewardPerSecond);
startTimestamp = _startTimestamp;
endTimestamp = _endTimestamp;
lastRewardTimestamp = startTimestamp;
}
function updateBoostContract(address _newBoostContract) external onlyOwner {
require(
_newBoostContract != address(0) && _newBoostContract != boostContract,
"New boost contract address must be valid"
);
boostContract = _newBoostContract;
emit BoostContractUpdated(_newBoostContract);
}
function updateBoostMultiplierByUser(
address _userAddress
) external nonReentrant {
UserInfo storage user = userInfo[_userAddress];
_updatePool();
if (user.amount > 0) {
user.unsettledRewards += _pendingReward(_userAddress);
}
_updateBoostMultiplier(_userAddress, 0);
user.rewardDebt = (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR;
}
function updateBoostMultiplier(
address _userAddress,
uint256 _newMultiplier
) external onlyBoostContract nonReentrant {
UserInfo storage user = userInfo[_userAddress];
_updatePool();
if (user.amount > 0) {
user.unsettledRewards += _pendingReward(_userAddress);
}
_updateBoostMultiplier(_userAddress, _newMultiplier);
user.rewardDebt = (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR;
}
function restart(uint256 _startTimestamp, uint256 _endTimestamp, uint256 _rewardPerSecond) external onlyOwner {
require(block.timestamp > endTimestamp, "Pool should be ended");
require(block.timestamp <= _startTimestamp, "New startTimestamp must be higher than current timestamp");
require(_startTimestamp < _endTimestamp, "New startTimestamp must be lower than new endTimestamp");
_updatePool();
startTimestamp = _startTimestamp;
endTimestamp = _endTimestamp;
rewardPerSecond = _rewardPerSecond;
lastRewardTimestamp = _startTimestamp;
emit Restart(_startTimestamp, _endTimestamp, _rewardPerSecond);
}
function pendingReward(address _userAddress) external view returns (uint256) {
UserInfo memory user = userInfo[_userAddress];
return user.unsettledRewards + _pendingReward(_userAddress);
}
function _pendingReward(address _userAddress) internal view returns (uint256) {
UserInfo storage user = userInfo[_userAddress];
if (block.timestamp > lastRewardTimestamp && totalBoostedShare != 0) {
uint256 multiplier = _getMultiplier(lastRewardTimestamp, block.timestamp);
uint256 cakeReward = multiplier * rewardPerSecond;
uint256 adjustedTokenPerShare = accTokenPerShare + (cakeReward * PRECISION_FACTOR) / totalBoostedShare;
return (user.boostedAmount * adjustedTokenPerShare) / PRECISION_FACTOR - user.rewardDebt;
} else {
return (user.boostedAmount * accTokenPerShare) / PRECISION_FACTOR - user.rewardDebt;
}
}
function _updatePool() internal {
if (block.timestamp <= lastRewardTimestamp) {
return;
}
if (totalBoostedShare == 0) {
lastRewardTimestamp = block.timestamp;
return;
}
uint256 multiplier = _getMultiplier(lastRewardTimestamp, block.timestamp);
uint256 cakeReward = multiplier * rewardPerSecond;
accTokenPerShare = accTokenPerShare + (cakeReward * PRECISION_FACTOR) / totalBoostedShare;
lastRewardTimestamp = block.timestamp;
}
function _getMultiplier(uint256 _from, uint256 _to) internal view returns (uint256) {
if (_to <= endTimestamp) {
return _to - _from;
} else if (_from >= endTimestamp) {
return 0;
} else {
return endTimestamp - _from;
}
}
function _updateBoostMultiplier(
address _userAddress,
uint256 _newMultiplier
) internal {
require(_userAddress != address(0), "The user address must be valid");
UserInfo storage user = userInfo[_userAddress];
if (_newMultiplier == 0) {
_newMultiplier = BOOST_PRECISION;
if (address(boostContract) != address(0)) {
_newMultiplier = IFarmBooster(boostContract).updatePositionBoostMultiplier(_userAddress);
}
}
if (_newMultiplier < BOOST_PRECISION) {
_newMultiplier = BOOST_PRECISION;
}
if (_newMultiplier > MAX_BOOST_PRECISION) {
_newMultiplier = MAX_BOOST_PRECISION;
}
uint256 _oldMultiplier = user.boostMultiplier;
uint256 _oldBoostedAmount = user.boostedAmount;
user.boostMultiplier = _newMultiplier;
user.boostedAmount = user.amount * _newMultiplier / BOOST_PRECISION;
totalBoostedShare = totalBoostedShare + user.boostedAmount - _oldBoostedAmount;
emit BoostMultiplierUpdated(_userAddress, _oldMultiplier, _newMultiplier);
}
}
{
"compilationTarget": {
"contracts/wrappers/V2Wrapper.sol": "V2Wrapper"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 10
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"boostContract","type":"address"}],"name":"BoostContractUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldMultiplier","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMultiplier","type":"uint256"}],"name":"BoostMultiplierUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"name":"DepositAndExpend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"poolLimitPerUser","type":"uint256"}],"name":"NewPoolLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRewardPerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRewardPerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"name":"NewRewardPerSecond","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldStartTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStartTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldEndTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newEndTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPerSecond","type":"uint256"}],"name":"NewStartAndEndTimestamp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPerSecond","type":"uint256"}],"name":"Restart","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"RewardsStop","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenRecovery","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"BOOST_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BOOST_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WRAPPER_FACTORY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accTokenPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"boostContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_noHarvest","type":"bool"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositRewardAndExpend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"emergencyRewardWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"_stakedToken","type":"address"},{"internalType":"contract IERC20Metadata","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_rewardPerSecond","type":"uint256"},{"internalType":"uint256","name":"_startTimestamp","type":"uint256"},{"internalType":"uint256","name":"_endTimestamp","type":"uint256"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_boostContract","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRewardTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"}],"name":"pendingReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"recoverToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startTimestamp","type":"uint256"},{"internalType":"uint256","name":"_endTimestamp","type":"uint256"},{"internalType":"uint256","name":"_rewardPerSecond","type":"uint256"}],"name":"restart","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakedToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stopReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalBoostedShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newBoostContract","type":"address"}],"name":"updateBoostContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"},{"internalType":"uint256","name":"_newMultiplier","type":"uint256"}],"name":"updateBoostMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"}],"name":"updateBoostMultiplierByUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardPerSecond","type":"uint256"}],"name":"updateRewardPerSecond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startTimestamp","type":"uint256"},{"internalType":"uint256","name":"_endTimestamp","type":"uint256"}],"name":"updateStartAndEndTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"boostMultiplier","type":"uint256"},{"internalType":"uint256","name":"boostedAmount","type":"uint256"},{"internalType":"uint256","name":"unsettledRewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_noHarvest","type":"bool"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]