编译器
0.8.16+commit.07a7930e
文件 1 的 9: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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 9:BoringERC20.sol
pragma solidity 0.8.16;
import "./IBoringERC20.sol";
library BoringERC20 {
bytes4 private constant SIG_SYMBOL = 0x95d89b41;
bytes4 private constant SIG_NAME = 0x06fdde03;
bytes4 private constant SIG_DECIMALS = 0x313ce567;
bytes4 private constant SIG_TRANSFER = 0xa9059cbb;
bytes4 private constant SIG_TRANSFER_FROM = 0x23b872dd;
function returnDataToString(bytes memory data)
internal
pure
returns (string memory)
{
if (data.length >= 64) {
return abi.decode(data, (string));
} else if (data.length == 32) {
uint8 i = 0;
while (i < 32 && data[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (i = 0; i < 32 && data[i] != 0; i++) {
bytesArray[i] = data[i];
}
return string(bytesArray);
} else {
return "???";
}
}
function safeSymbol(IBoringERC20 token)
internal
view
returns (string memory)
{
(bool success, bytes memory data) = address(token).staticcall(
abi.encodeWithSelector(SIG_SYMBOL)
);
return success ? returnDataToString(data) : "???";
}
function safeName(IBoringERC20 token)
internal
view
returns (string memory)
{
(bool success, bytes memory data) = address(token).staticcall(
abi.encodeWithSelector(SIG_NAME)
);
return success ? returnDataToString(data) : "???";
}
function safeDecimals(IBoringERC20 token) internal view returns (uint8) {
(bool success, bytes memory data) = address(token).staticcall(
abi.encodeWithSelector(SIG_DECIMALS)
);
return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
}
function safeTransfer(
IBoringERC20 token,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(SIG_TRANSFER, to, amount)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"BoringERC20: Transfer failed"
);
}
function safeTransferFrom(
IBoringERC20 token,
address from,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(SIG_TRANSFER_FROM, from, to, amount)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"BoringERC20: TransferFrom failed"
);
}
}
文件 3 的 9: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;
}
}
文件 4 的 9:IBoringERC20.sol
pragma solidity 0.8.16;
interface IBoringERC20 {
function mint(address to, uint256 amount) external;
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender)
external
view
returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
文件 5 的 9:IMultipleRewards.sol
pragma solidity 0.8.16;
import "../libraries/IBoringERC20.sol";
interface IMultipleRewards {
function onZyberReward(
uint256 pid,
address user,
uint256 newLpAmount
) external;
function pendingTokens(
uint256 pid,
address user
) external view returns (uint256 pending);
function rewardToken() external view returns (IBoringERC20);
function poolRewardsPerSec(uint256 pid) external view returns (uint256);
}
文件 6 的 9:IZyberPair.sol
pragma solidity 0.8.16;
interface IZyberPair {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function initialize(address, address) external;
}
文件 7 的 9: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());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
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 的 9: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() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 9 的 9:ZyberChef.sol
pragma solidity 0.8.16;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "./rewarders/IMultipleRewards.sol";
import "./libraries/BoringERC20.sol";
import "./IZyberPair.sol";
contract ZyberChef is Ownable, ReentrancyGuard {
using BoringERC20 for IBoringERC20;
struct UserInfo {
uint256 amount;
uint256 rewardDebt;
uint256 rewardLockedUp;
uint256 nextHarvestUntil;
}
struct PoolInfo {
IBoringERC20 lpToken;
uint256 allocPoint;
uint256 lastRewardTimestamp;
uint256 accZyberPerShare;
uint16 depositFeeBP;
uint256 harvestInterval;
uint256 totalLp;
IMultipleRewards[] rewarders;
}
IBoringERC20 public zyber;
uint256 public zyberPerSec;
uint256 public constant MAXIMUM_HARVEST_INTERVAL = 14 days;
uint16 public constant MAXIMUM_DEPOSIT_FEE_RATE = 1000;
PoolInfo[] public poolInfo;
mapping(uint256 => mapping(address => UserInfo)) public userInfo;
uint256 public totalAllocPoint;
uint256 public startTimestamp;
uint256 public totalLockedUpRewards;
uint256 public totalZyberInPools;
address public marketingAddress;
address public feeAddress;
uint256 public marketingPercent = 45;
uint256 public teamPercent = 90;
address public teamAddress;
uint256 private constant ACC_TOKEN_PRECISION = 1e12;
modifier validatePoolByPid(uint256 _pid) {
require(_pid < poolInfo.length, "Pool does not exist");
_;
}
event Add(
uint256 indexed pid,
uint256 allocPoint,
IBoringERC20 indexed lpToken,
uint16 depositFeeBP,
uint256 harvestInterval,
IMultipleRewards[] indexed rewarders
);
event Set(
uint256 indexed pid,
uint256 allocPoint,
uint16 depositFeeBP,
uint256 harvestInterval,
IMultipleRewards[] indexed rewarders
);
event UpdatePool(
uint256 indexed pid,
uint256 lastRewardTimestamp,
uint256 lpSupply,
uint256 accZyberPerShare
);
event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
event EmergencyWithdraw(
address indexed user,
uint256 indexed pid,
uint256 amount
);
event EmissionRateUpdated(
address indexed caller,
uint256 previousValue,
uint256 newValue
);
event RewardLockedUp(
address indexed user,
uint256 indexed pid,
uint256 amountLockedUp
);
event AllocPointsUpdated(
address indexed caller,
uint256 previousAmount,
uint256 newAmount
);
event SetmarketingAddress(
address indexed oldAddress,
address indexed newAddress
);
event SetTeamAddress(
address indexed oldAddress,
address indexed newAddress
);
event SetFeeAddress(address indexed oldAddress, address indexed newAddress);
event SetInvestorAddress(
address indexed oldAddress,
address indexed newAddress
);
event SetmarketingPercent(uint256 oldPercent, uint256 newPercent);
event SetTeamPercent(uint256 oldPercent, uint256 newPercent);
constructor(
IBoringERC20 _zyber,
uint256 _zyberPerSec,
address _marketingAddress,
uint256 _marketingPercent,
address _teamAddress,
uint256 _teamPercent,
address _feeAddress
) {
require(
_marketingPercent <= 1000,
"constructor: invalid marketing percent value"
);
startTimestamp = block.timestamp + (60 * 60 * 24 * 365);
zyber = _zyber;
zyberPerSec = _zyberPerSec;
marketingAddress = _marketingAddress;
teamAddress = _teamAddress;
feeAddress = _feeAddress;
teamPercent = _teamPercent;
}
function startFarming() public onlyOwner {
require(block.timestamp < startTimestamp, "farm already started");
uint256 length = poolInfo.length;
for (uint256 pid = 0; pid < length; ++pid) {
PoolInfo storage pool = poolInfo[pid];
pool.lastRewardTimestamp = block.timestamp;
}
startTimestamp = block.timestamp;
}
function poolLength() external view returns (uint256) {
return poolInfo.length;
}
function add(
uint256 _allocPoint,
IBoringERC20 _lpToken,
uint16 _depositFeeBP,
uint256 _harvestInterval,
IMultipleRewards[] calldata _rewarders
) public onlyOwner {
require(_rewarders.length <= 10, "add: too many rewarders");
require(
_depositFeeBP <= MAXIMUM_DEPOSIT_FEE_RATE,
"add: deposit fee too high"
);
require(
_harvestInterval <= MAXIMUM_HARVEST_INTERVAL,
"add: invalid harvest interval"
);
for (
uint256 rewarderId = 0;
rewarderId < _rewarders.length;
++rewarderId
) {
require(
Address.isContract(address(_rewarders[rewarderId])),
"add: rewarder must be contract"
);
}
_massUpdatePools();
uint256 lastRewardTimestamp = block.timestamp > startTimestamp
? block.timestamp
: startTimestamp;
totalAllocPoint += _allocPoint;
poolInfo.push(
PoolInfo({
lpToken: _lpToken,
allocPoint: _allocPoint,
lastRewardTimestamp: lastRewardTimestamp,
accZyberPerShare: 0,
depositFeeBP: _depositFeeBP,
harvestInterval: _harvestInterval,
totalLp: 0,
rewarders: _rewarders
})
);
emit Add(
poolInfo.length - 1,
_allocPoint,
_lpToken,
_depositFeeBP,
_harvestInterval,
_rewarders
);
}
function set(
uint256 _pid,
uint256 _allocPoint,
uint16 _depositFeeBP,
uint256 _harvestInterval,
IMultipleRewards[] calldata _rewarders
) public onlyOwner validatePoolByPid(_pid) {
require(_rewarders.length <= 10, "set: too many rewarders");
require(
_depositFeeBP <= MAXIMUM_DEPOSIT_FEE_RATE,
"set: deposit fee too high"
);
require(
_harvestInterval <= MAXIMUM_HARVEST_INTERVAL,
"set: invalid harvest interval"
);
for (
uint256 rewarderId = 0;
rewarderId < _rewarders.length;
++rewarderId
) {
require(
Address.isContract(address(_rewarders[rewarderId])),
"set: rewarder must be contract"
);
}
_massUpdatePools();
totalAllocPoint =
totalAllocPoint -
poolInfo[_pid].allocPoint +
_allocPoint;
poolInfo[_pid].allocPoint = _allocPoint;
poolInfo[_pid].depositFeeBP = _depositFeeBP;
poolInfo[_pid].harvestInterval = _harvestInterval;
poolInfo[_pid].rewarders = _rewarders;
emit Set(
_pid,
_allocPoint,
_depositFeeBP,
_harvestInterval,
_rewarders
);
}
function pendingTokens(
uint256 _pid,
address _user
)
external
view
validatePoolByPid(_pid)
returns (
address[] memory addresses,
string[] memory symbols,
uint256[] memory decimals,
uint256[] memory amounts
)
{
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][_user];
uint256 accZyberPerShare = pool.accZyberPerShare;
uint256 lpSupply = pool.totalLp;
if (block.timestamp > pool.lastRewardTimestamp && lpSupply != 0) {
uint256 multiplier = block.timestamp - pool.lastRewardTimestamp;
uint256 total = 1000;
uint256 lpPercent = total - marketingPercent;
uint256 zyberReward = (multiplier *
zyberPerSec *
pool.allocPoint *
lpPercent) /
totalAllocPoint /
total;
accZyberPerShare += (
((zyberReward * ACC_TOKEN_PRECISION) / lpSupply)
);
}
uint256 pendingZyber = (((user.amount * accZyberPerShare) /
ACC_TOKEN_PRECISION) - user.rewardDebt) + user.rewardLockedUp;
addresses = new address[](pool.rewarders.length + 1);
symbols = new string[](pool.rewarders.length + 1);
amounts = new uint256[](pool.rewarders.length + 1);
decimals = new uint256[](pool.rewarders.length + 1);
addresses[0] = address(zyber);
symbols[0] = IBoringERC20(zyber).safeSymbol();
decimals[0] = IBoringERC20(zyber).safeDecimals();
amounts[0] = pendingZyber;
for (
uint256 rewarderId = 0;
rewarderId < pool.rewarders.length;
++rewarderId
) {
addresses[rewarderId + 1] = address(
pool.rewarders[rewarderId].rewardToken()
);
symbols[rewarderId + 1] = IBoringERC20(
pool.rewarders[rewarderId].rewardToken()
).safeSymbol();
decimals[rewarderId + 1] = IBoringERC20(
pool.rewarders[rewarderId].rewardToken()
).safeDecimals();
amounts[rewarderId + 1] = pool.rewarders[rewarderId].pendingTokens(
_pid,
_user
);
}
}
function poolRewardsPerSec(
uint256 _pid
)
external
view
validatePoolByPid(_pid)
returns (
address[] memory addresses,
string[] memory symbols,
uint256[] memory decimals,
uint256[] memory rewardsPerSec
)
{
PoolInfo storage pool = poolInfo[_pid];
addresses = new address[](pool.rewarders.length + 1);
symbols = new string[](pool.rewarders.length + 1);
decimals = new uint256[](pool.rewarders.length + 1);
rewardsPerSec = new uint256[](pool.rewarders.length + 1);
addresses[0] = address(zyber);
symbols[0] = IBoringERC20(zyber).safeSymbol();
decimals[0] = IBoringERC20(zyber).safeDecimals();
uint256 total = 1000;
uint256 lpPercent = total - marketingPercent;
rewardsPerSec[0] =
(pool.allocPoint * zyberPerSec * lpPercent) /
totalAllocPoint /
total;
for (
uint256 rewarderId = 0;
rewarderId < pool.rewarders.length;
++rewarderId
) {
addresses[rewarderId + 1] = address(
pool.rewarders[rewarderId].rewardToken()
);
symbols[rewarderId + 1] = IBoringERC20(
pool.rewarders[rewarderId].rewardToken()
).safeSymbol();
decimals[rewarderId + 1] = IBoringERC20(
pool.rewarders[rewarderId].rewardToken()
).safeDecimals();
rewardsPerSec[rewarderId + 1] = pool
.rewarders[rewarderId]
.poolRewardsPerSec(_pid);
}
}
function poolRewarders(
uint256 _pid
)
external
view
validatePoolByPid(_pid)
returns (address[] memory rewarders)
{
PoolInfo storage pool = poolInfo[_pid];
rewarders = new address[](pool.rewarders.length);
for (
uint256 rewarderId = 0;
rewarderId < pool.rewarders.length;
++rewarderId
) {
rewarders[rewarderId] = address(pool.rewarders[rewarderId]);
}
}
function canHarvest(
uint256 _pid,
address _user
) public view validatePoolByPid(_pid) returns (bool) {
UserInfo storage user = userInfo[_pid][_user];
return
block.timestamp >= startTimestamp &&
block.timestamp >= user.nextHarvestUntil;
}
function massUpdatePools() external nonReentrant {
_massUpdatePools();
}
function _massUpdatePools() internal {
for (uint256 pid = 0; pid < poolInfo.length; ++pid) {
_updatePool(pid);
}
}
function updatePool(uint256 _pid) external nonReentrant {
_updatePool(_pid);
}
function _updatePool(uint256 _pid) internal validatePoolByPid(_pid) {
PoolInfo storage pool = poolInfo[_pid];
if (block.timestamp <= pool.lastRewardTimestamp) {
return;
}
uint256 lpSupply = pool.totalLp;
if (lpSupply == 0 || pool.allocPoint == 0) {
pool.lastRewardTimestamp = block.timestamp;
return;
}
uint256 multiplier = block.timestamp - pool.lastRewardTimestamp;
uint256 zyberReward = ((multiplier * zyberPerSec) * pool.allocPoint) /
totalAllocPoint;
uint256 total = 1000;
uint256 lpPercent = total - marketingPercent - teamPercent;
if (marketingPercent > 0) {
zyber.mint(
marketingAddress,
(zyberReward * marketingPercent) / total
);
}
if (teamPercent > 0) {
zyber.mint(teamAddress, (zyberReward * teamPercent) / total);
}
zyber.mint(address(this), (zyberReward * lpPercent) / total);
pool.accZyberPerShare +=
(zyberReward * ACC_TOKEN_PRECISION * lpPercent) /
pool.totalLp /
total;
pool.lastRewardTimestamp = block.timestamp;
emit UpdatePool(
_pid,
pool.lastRewardTimestamp,
lpSupply,
pool.accZyberPerShare
);
}
function depositWithPermit(
uint256 pid,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public nonReentrant validatePoolByPid(pid) {
PoolInfo storage pool = poolInfo[pid];
IZyberPair pair = IZyberPair(address(pool.lpToken));
pair.permit(msg.sender, address(this), amount, deadline, v, r, s);
_deposit(pid, amount);
}
function deposit(uint256 _pid, uint256 _amount) public nonReentrant {
_deposit(_pid, _amount);
}
function _deposit(
uint256 _pid,
uint256 _amount
) internal validatePoolByPid(_pid) {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
_updatePool(_pid);
payOrLockupPendingZyber(_pid);
if (_amount > 0) {
uint256 beforeDeposit = pool.lpToken.balanceOf(address(this));
pool.lpToken.safeTransferFrom(msg.sender, address(this), _amount);
uint256 afterDeposit = pool.lpToken.balanceOf(address(this));
_amount = afterDeposit - beforeDeposit;
if (pool.depositFeeBP > 0) {
uint256 depositFee = (_amount * pool.depositFeeBP) / 10000;
pool.lpToken.safeTransfer(feeAddress, depositFee);
_amount = _amount - depositFee;
}
user.amount += _amount;
if (address(pool.lpToken) == address(zyber)) {
totalZyberInPools += _amount;
}
}
user.rewardDebt =
(user.amount * pool.accZyberPerShare) /
ACC_TOKEN_PRECISION;
for (
uint256 rewarderId = 0;
rewarderId < pool.rewarders.length;
++rewarderId
) {
pool.rewarders[rewarderId].onZyberReward(
_pid,
msg.sender,
user.amount
);
}
if (_amount > 0) {
pool.totalLp += _amount;
}
emit Deposit(msg.sender, _pid, _amount);
}
function withdraw(
uint256 _pid,
uint256 _amount
) public nonReentrant validatePoolByPid(_pid) {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
require(user.amount >= _amount, "withdraw: user amount not enough");
require(pool.totalLp >= _amount, "withdraw: pool total not enough");
_updatePool(_pid);
payOrLockupPendingZyber(_pid);
if (_amount > 0) {
user.amount -= _amount;
if (address(pool.lpToken) == address(zyber)) {
totalZyberInPools -= _amount;
}
pool.lpToken.safeTransfer(msg.sender, _amount);
}
user.rewardDebt =
(user.amount * pool.accZyberPerShare) /
ACC_TOKEN_PRECISION;
for (
uint256 rewarderId = 0;
rewarderId < pool.rewarders.length;
++rewarderId
) {
pool.rewarders[rewarderId].onZyberReward(
_pid,
msg.sender,
user.amount
);
}
if (_amount > 0) {
pool.totalLp -= _amount;
}
emit Withdraw(msg.sender, _pid, _amount);
}
function emergencyWithdraw(uint256 _pid) public nonReentrant {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
uint256 amount = user.amount;
require(
pool.totalLp >= amount,
"emergency withdraw: pool total not enough"
);
user.amount = 0;
user.rewardDebt = 0;
user.rewardLockedUp = 0;
user.nextHarvestUntil = 0;
pool.totalLp -= amount;
for (
uint256 rewarderId = 0;
rewarderId < pool.rewarders.length;
++rewarderId
) {
pool.rewarders[rewarderId].onZyberReward(_pid, msg.sender, 0);
}
if (address(pool.lpToken) == address(zyber)) {
totalZyberInPools -= amount;
}
pool.lpToken.safeTransfer(msg.sender, amount);
emit EmergencyWithdraw(msg.sender, _pid, amount);
}
function payOrLockupPendingZyber(uint256 _pid) internal {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
if (user.nextHarvestUntil == 0 && block.timestamp >= startTimestamp) {
user.nextHarvestUntil = block.timestamp + pool.harvestInterval;
}
if (user.nextHarvestUntil != 0 && pool.harvestInterval == 0) {
user.nextHarvestUntil = 0;
}
uint256 pending = ((user.amount * pool.accZyberPerShare) /
ACC_TOKEN_PRECISION) - user.rewardDebt;
if (canHarvest(_pid, msg.sender)) {
if (pending > 0 || user.rewardLockedUp > 0) {
uint256 pendingRewards = pending + user.rewardLockedUp;
totalLockedUpRewards -= user.rewardLockedUp;
user.rewardLockedUp = 0;
user.nextHarvestUntil = block.timestamp + pool.harvestInterval;
safeZyberTransfer(msg.sender, pendingRewards);
}
} else if (pending > 0) {
totalLockedUpRewards += pending;
user.rewardLockedUp += pending;
emit RewardLockedUp(msg.sender, _pid, pending);
}
}
function safeZyberTransfer(address _to, uint256 _amount) internal {
if (zyber.balanceOf(address(this)) > totalZyberInPools) {
uint256 zyberBal = zyber.balanceOf(address(this)) -
totalZyberInPools;
if (_amount >= zyberBal) {
zyber.safeTransfer(_to, zyberBal);
} else if (_amount > 0) {
zyber.safeTransfer(_to, _amount);
}
}
}
function updateAllocPoint(
uint256 _pid,
uint256 _allocPoint
) public onlyOwner {
_massUpdatePools();
emit AllocPointsUpdated(
msg.sender,
poolInfo[_pid].allocPoint,
_allocPoint
);
totalAllocPoint =
totalAllocPoint -
poolInfo[_pid].allocPoint +
_allocPoint;
poolInfo[_pid].allocPoint = _allocPoint;
}
function updateEmissionRate(uint256 _zyberPerSec) public onlyOwner {
_massUpdatePools();
emit EmissionRateUpdated(msg.sender, zyberPerSec, _zyberPerSec);
zyberPerSec = _zyberPerSec;
}
function poolTotalLp(uint256 pid) external view returns (uint256) {
return poolInfo[pid].totalLp;
}
function harvestMany(uint256[] calldata _pids) public nonReentrant {
require(_pids.length <= 30, "harvest many: too many pool ids");
for (uint256 index = 0; index < _pids.length; ++index) {
_deposit(_pids[index], 0);
}
}
function setMarketingAddress(address _marketingAddress) public onlyOwner {
require(
_marketingAddress != address(0),
"invalid new marketing address"
);
marketingAddress = _marketingAddress;
emit SetmarketingAddress(_marketingAddress, marketingAddress);
}
function setTeamAddress(address _teamAddress) public onlyOwner {
require(_teamAddress != address(0), "invalid new team address");
teamAddress = _teamAddress;
emit SetTeamAddress(_teamAddress, teamAddress);
}
function setMarketingPercent(
uint256 _newmarketingPercent
) public onlyOwner {
require(_newmarketingPercent <= 2000, "invalid percent value");
emit SetmarketingPercent(marketingPercent, _newmarketingPercent);
marketingPercent = _newmarketingPercent;
}
function setTeamPercent(uint256 _newTeamPercent) public onlyOwner {
require(_newTeamPercent <= 2000, "invalid percent value");
emit SetTeamPercent(teamPercent, _newTeamPercent);
teamPercent = _newTeamPercent;
}
function setFeeAddress(address _feeAddress) public onlyOwner {
require(_feeAddress != address(0), "wrong address");
feeAddress = _feeAddress;
emit SetFeeAddress(msg.sender, _feeAddress);
}
function getZyberPerSec() public view returns (uint256) {
return zyberPerSec;
}
}
{
"compilationTarget": {
"contracts/farm/ZyberChef.sol": "ZyberChef"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 999999
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IBoringERC20","name":"_zyber","type":"address"},{"internalType":"uint256","name":"_zyberPerSec","type":"uint256"},{"internalType":"address","name":"_marketingAddress","type":"address"},{"internalType":"uint256","name":"_marketingPercent","type":"uint256"},{"internalType":"address","name":"_teamAddress","type":"address"},{"internalType":"uint256","name":"_teamPercent","type":"uint256"},{"internalType":"address","name":"_feeAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":true,"internalType":"contract IBoringERC20","name":"lpToken","type":"address"},{"indexed":false,"internalType":"uint16","name":"depositFeeBP","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"harvestInterval","type":"uint256"},{"indexed":true,"internalType":"contract IMultipleRewards[]","name":"rewarders","type":"address[]"}],"name":"Add","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"AllocPointsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"EmissionRateUpdated","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":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountLockedUp","type":"uint256"}],"name":"RewardLockedUp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"depositFeeBP","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"harvestInterval","type":"uint256"},{"indexed":true,"internalType":"contract IMultipleRewards[]","name":"rewarders","type":"address[]"}],"name":"Set","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"SetFeeAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"SetInvestorAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"SetTeamAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPercent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPercent","type":"uint256"}],"name":"SetTeamPercent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"SetmarketingAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPercent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPercent","type":"uint256"}],"name":"SetmarketingPercent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastRewardTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accZyberPerShare","type":"uint256"}],"name":"UpdatePool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"MAXIMUM_DEPOSIT_FEE_RATE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAXIMUM_HARVEST_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"contract IBoringERC20","name":"_lpToken","type":"address"},{"internalType":"uint16","name":"_depositFeeBP","type":"uint16"},{"internalType":"uint256","name":"_harvestInterval","type":"uint256"},{"internalType":"contract IMultipleRewards[]","name":"_rewarders","type":"address[]"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"canHarvest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"depositWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getZyberPerSec","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"}],"name":"harvestMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketingAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketingPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"massUpdatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingTokens","outputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"string[]","name":"symbols","type":"string[]"},{"internalType":"uint256[]","name":"decimals","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfo","outputs":[{"internalType":"contract IBoringERC20","name":"lpToken","type":"address"},{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"uint256","name":"lastRewardTimestamp","type":"uint256"},{"internalType":"uint256","name":"accZyberPerShare","type":"uint256"},{"internalType":"uint16","name":"depositFeeBP","type":"uint16"},{"internalType":"uint256","name":"harvestInterval","type":"uint256"},{"internalType":"uint256","name":"totalLp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"poolRewarders","outputs":[{"internalType":"address[]","name":"rewarders","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"poolRewardsPerSec","outputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"string[]","name":"symbols","type":"string[]"},{"internalType":"uint256[]","name":"decimals","type":"uint256[]"},{"internalType":"uint256[]","name":"rewardsPerSec","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"poolTotalLp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"uint16","name":"_depositFeeBP","type":"uint16"},{"internalType":"uint256","name":"_harvestInterval","type":"uint256"},{"internalType":"contract IMultipleRewards[]","name":"_rewarders","type":"address[]"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeAddress","type":"address"}],"name":"setFeeAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_marketingAddress","type":"address"}],"name":"setMarketingAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newmarketingPercent","type":"uint256"}],"name":"setMarketingPercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_teamAddress","type":"address"}],"name":"setTeamAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newTeamPercent","type":"uint256"}],"name":"setTeamPercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startFarming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"teamAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"teamPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAllocPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLockedUpRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalZyberInPools","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":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"}],"name":"updateAllocPoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_zyberPerSec","type":"uint256"}],"name":"updateEmissionRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"updatePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"rewardLockedUp","type":"uint256"},{"internalType":"uint256","name":"nextHarvestUntil","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"zyber","outputs":[{"internalType":"contract IBoringERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"zyberPerSec","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]