Contract Source Code:
File 1 of 1 : TokenFarm
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
library SafeMathInt {
int256 private constant MIN_INT256 = int256(1) << 255;
int256 private constant MAX_INT256 = ~(int256(1) << 255);
function mul(int256 a, int256 b) internal pure returns (int256) {
int256 c = a * b;
require(c != MIN_INT256 || (a & MIN_INT256) != (b & MIN_INT256));
require((b == 0) || (c / b == a), 'mul overflow');
return c;
}
function div(int256 a, int256 b) internal pure returns (int256) {
require(b != -1 || a != MIN_INT256);
return a / b;
}
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a),
'sub overflow');
return c;
}
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a),
'add overflow');
return c;
}
function abs(int256 a) internal pure returns (int256) {
require(a != MIN_INT256,
'abs overflow');
return a < 0 ? -a : a;
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, 'SafeMath: addition overflow');
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, 'SafeMath: subtraction overflow');
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, 'SafeMath: multiplication overflow');
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, 'SafeMath: division by zero');
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0,
'parameter 2 can not be 0');
return a % b;
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
interface IBEP20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address who) external view returns (uint256);
function allowance(address owner, address spender)
external
view
returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
contract Ownable {
address private _owner;
event OwnershipRenounced(address indexed previousOwner);
event TransferOwnerShip(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
constructor() {
_owner = msg.sender;
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(msg.sender == _owner, 'Not owner');
_;
}
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(_owner);
_owner = address(0);
}
function transferOwnership(address newOwner) public onlyOwner {
emit TransferOwnerShip(newOwner);
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0),
'Owner can not be 0');
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
contract TokenFarm is Ownable {
using SafeMath for uint256;
using SafeMathInt for int256;
address public tokenWallet;
struct UserInfo {
uint256 amount; // How many tokens the user has provided.
uint256 stakingTime; // The time at which the user staked tokens.
uint256 rewardClaimed; // The amount of reward claimed by the user.
}
struct PoolInfo {
address tokenAddress;
address rewardTokenAddress;
uint256 maxPoolSize;
uint256 currentPoolSize;
uint256 maxContribution;
uint256 minContribution;
uint256 apy; // it is in 1000 times, so 1000 means 100%
uint256 emergencyFees; // it is the fees in percentage, final fees is emergencyFees/1000
uint256 minLockDays;
uint256 totalRewardsClaimed; // total rewards claimed by the users
bool poolType; // true for public staking, false for whitelist staking
bool poolActive;
}
// Info of each pool.
PoolInfo[] public poolInfo;
uint256 [] public rewardTimes;
bool lock_= false;
uint256 public totalRewardsClaimed = 0;
// Info of each user that stakes tokens.
mapping (uint256 => mapping (address => UserInfo)) public userInfo;
mapping (uint256 => mapping (address => bool)) public whitelistedAddress;
mapping (uint256 => uint256) public rewardAmount;
mapping (uint256 => uint256) public rewardCurrentPoolSize;
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);
constructor (address _wallet) {
require(_wallet != address(0), "Invalid wallet address");
tokenWallet = _wallet;
}
modifier lock {
require(!lock_, "Process is locked");
lock_ = true;
_;
lock_ = false;
}
function poolLength() public view returns (uint256) {
return poolInfo.length;
}
function addPool (address _tokenAddress, address _rewardTokenAddress, uint256 _maxPoolSize, uint256 _maxContribution,uint256 _emergencyFee, uint256 _minContribution, uint256 _apy, uint256 _minLockDays, bool _poolType, bool _poolActive) public onlyOwner {
poolInfo.push(PoolInfo({
tokenAddress: _tokenAddress,
rewardTokenAddress: _rewardTokenAddress,
maxPoolSize: _maxPoolSize,
currentPoolSize: 0,
minContribution: _minContribution,
maxContribution: _maxContribution,
apy: _apy,
emergencyFees: _emergencyFee,
minLockDays: _minLockDays,
poolType: _poolType,
poolActive: _poolActive,
totalRewardsClaimed: 0
}));
}
function updateMaxPoolSize (uint256 _pid, uint256 _maxPoolSize) public onlyOwner{
require (_pid < poolLength(), "Invalid pool ID");
require (_maxPoolSize >= poolInfo[_pid].currentPoolSize, "Cannot reduce the max size below the current pool size");
poolInfo[_pid].maxPoolSize = _maxPoolSize;
}
function updateMaxContribution (uint256 _pid, uint256 _maxContribution) public onlyOwner{
require (_pid < poolLength(), "Invalid pool ID");
poolInfo[_pid].maxContribution = _maxContribution;
}
function updateEmergencyFees (uint256 _pid, uint256 _emergencyFees) public onlyOwner {
require (_pid < poolLength(), "Invalid pool ID");
if (poolInfo[_pid].currentPoolSize > 0){
require (_emergencyFees <= poolInfo[_pid].emergencyFees, "You can't increase the emergency fees when people started staking");
}
poolInfo[_pid].emergencyFees = _emergencyFees;
}
function updateRewardToken(address _rewardTokenAddress, uint256 _pid) public onlyOwner {
require (_pid < poolLength(), "Invalid pool ID");
poolInfo[_pid].rewardTokenAddress = _rewardTokenAddress;
}
function updateToken(address _tokenAddress, uint256 _pid) public onlyOwner {
require (_pid < poolLength(), "Invalid pool ID");
poolInfo[_pid].tokenAddress = _tokenAddress;
}
function updateTokenWallet(address _wallet) public onlyOwner {
require (_wallet != address(0), "Invalid wallet address");
tokenWallet = _wallet;
}
function updateMinLockDays (uint256 _pid, uint256 _lockDays) public onlyOwner {
require (_pid < poolLength(), "Invalid pool ID");
require (poolInfo[_pid].currentPoolSize == 0, "Cannot change lock time after people started staking");
poolInfo[_pid].minLockDays = _lockDays;
}
function updateApy (uint256 _pid, uint256 _apy) public onlyOwner {
require (_pid < poolLength(), "Invalid pool ID");
poolInfo[_pid].apy = _apy;
}
function updatePoolType (uint256 _pid, bool _poolType) public onlyOwner {
require (_pid < poolLength(), "Invalid pool ID");
poolInfo[_pid].poolType = _poolType;
}
function updatePoolActive (uint256 _pid, bool _poolActive) public onlyOwner {
require (_pid < poolLength(), "Invalid pool ID");
poolInfo[_pid].poolActive = _poolActive;
}
function updateMinContribution (uint256 _pid, uint256 _minContribution) public onlyOwner {
require (_pid < poolLength(), "Invalid pool ID");
poolInfo[_pid].minContribution = _minContribution;
}
function addWhitelist (uint256 _pid, address [] memory _whitelistAddresses) public onlyOwner {
require (_pid < poolLength(), "Invalid pool ID");
uint256 length = _whitelistAddresses.length;
require (length<= 200, "Can add only 200 wl at a time");
for (uint256 i = 0; i < length; i++){
address _whitelistAddress = _whitelistAddresses[i];
whitelistedAddress[_pid][_whitelistAddress] = true;
}
}
function addReward (uint256 _pid, uint256 _amount) public onlyOwner {
rewardTimes.push(block.timestamp);
rewardAmount[block.timestamp] = _amount;
rewardCurrentPoolSize[block.timestamp] = poolInfo[_pid].currentPoolSize;
address _rewardTokenAddress = poolInfo[_pid].rewardTokenAddress;
IBEP20 rewardToken = IBEP20 (_rewardTokenAddress);
bool success = rewardToken.transferFrom(msg.sender, tokenWallet, _amount);
require(success, "Transfer failed");
}
function emergencyLock (bool _lock) public onlyOwner {
lock_ = _lock;
}
function stakeTokens (uint256 _pid, uint256 _amount) public lock {
require (_pid < poolLength(), "Invalid pool ID");
require (poolInfo[_pid].poolActive, "Pool is not active");
require (_amount >= (userInfo[_pid][msg.sender].amount).add(poolInfo[_pid].minContribution), "Amount is less than min contribution");
require (poolInfo[_pid].currentPoolSize.add(_amount) <= poolInfo[_pid].maxPoolSize, "Staking exceeds max pool size");
require ((userInfo[_pid][msg.sender].amount).add(_amount) <= poolInfo[_pid].maxContribution , "Max Contribution exceeds");
if (poolInfo[_pid].poolType == false){
require (whitelistedAddress[_pid][msg.sender], "You are not whitelisted for this pool");
}
// Sending the claimable tokens to the user
if (claimableRewards(_pid, msg.sender) > 0){
claimRewards(_pid);
}
address _tokenAddress = poolInfo[_pid].tokenAddress;
IBEP20 token = IBEP20 (_tokenAddress);
bool success = token.transferFrom(msg.sender, tokenWallet, _amount);
require (success, "Transfer From failed. Please approve the token");
poolInfo[_pid].currentPoolSize = (poolInfo[_pid].currentPoolSize).add(_amount);
uint256 _stakingTime = block.timestamp;
_amount = _amount.add(userInfo[_pid][msg.sender].amount);
uint256 _rewardClaimed = 0;
userInfo[_pid][msg.sender] = UserInfo ({
amount: _amount,
stakingTime: _stakingTime,
rewardClaimed: _rewardClaimed
});
}
function claimableRewards (uint256 _pid, address _user) public view returns (uint256) {
require (_pid < poolLength(), "Invalid pool ID");
uint256 _stakingTime = userInfo[_pid][_user].stakingTime;
uint256 lockDays = (block.timestamp - _stakingTime) / 1 days;
if(lockDays < poolInfo[_pid].minLockDays) return 0;
if (userInfo[_pid][_user].amount == 0) return 0;
uint256 _claimableReward = 0;
for (uint256 i = 0; i < rewardTimes.length; i++){
uint256 _rewardTime = rewardTimes[i];
uint256 _rewardAmount = rewardAmount[_rewardTime];
uint256 _rewardCurrentPoolSize = rewardCurrentPoolSize[_rewardTime];
if (_rewardTime > _stakingTime){
uint256 _refundValue = ((userInfo[_pid][_user].amount * _rewardAmount) / (_rewardCurrentPoolSize));
_claimableReward = _claimableReward.add(_refundValue);
}
}
if (userInfo[_pid][_user].rewardClaimed >= _claimableReward) return 0;
return _claimableReward - userInfo[_pid][_user].rewardClaimed;
}
function claimableNativeRewards (uint256 _pid, address _user) public view returns (uint256) {
require (_pid < poolLength(), "Invalid pool ID");
uint256 lockDays = (block.timestamp - userInfo[_pid][_user].stakingTime) / 1 days;
uint256 _refundValue = ((userInfo[_pid][_user].amount * poolInfo[_pid].apy * lockDays) / (1000 * 365));
return _refundValue;
}
function unstakeTokens (uint256 _pid) public lock {
require (_pid < poolLength(), "Invalid pool ID");
require (userInfo[_pid][msg.sender].amount > 0 , "You don't have any staked tokens");
require (userInfo[_pid][msg.sender].stakingTime > 0 , "You don't have any staked tokens");
// check the min lock days is passed or not
uint256 lockDays = (block.timestamp - userInfo[_pid][msg.sender].stakingTime) / 1 days;
require (lockDays >= poolInfo[_pid].minLockDays, "You can't unstake before min lock days");
address _tokenAddress = poolInfo[_pid].tokenAddress;
IBEP20 token = IBEP20 (_tokenAddress);
address _rewardTokenAddress = poolInfo[_pid].rewardTokenAddress;
IBEP20 rewardToken = IBEP20 (_rewardTokenAddress);
uint256 _amount = userInfo[_pid][msg.sender].amount;
uint256 _refundValue = claimableRewards(_pid, msg.sender);
uint256 _nativeReward = claimableNativeRewards(_pid, msg.sender);
userInfo[_pid][msg.sender].rewardClaimed += _refundValue;
poolInfo[_pid].currentPoolSize = (poolInfo[_pid].currentPoolSize).sub(userInfo[_pid][msg.sender].amount);
poolInfo[_pid].totalRewardsClaimed += _refundValue;
userInfo[_pid][msg.sender].amount = 0;
userInfo[_pid][msg.sender].rewardClaimed = 0;
bool success1 = token.transferFrom(tokenWallet,msg.sender, _amount);
bool success2 = token.transferFrom(tokenWallet,msg.sender, _nativeReward);
bool success3 = rewardToken.transferFrom(tokenWallet,msg.sender, _refundValue);
require(success1 && success2 && success3, "Transfer failed");
}
function claimRewards (uint256 _pid) public lock {
require (_pid < poolLength(), "Invalid pool ID");
require (userInfo[_pid][msg.sender].amount > 0 , "You don't have any staked tokens");
require (userInfo[_pid][msg.sender].stakingTime > 0 , "You don't have any staked tokens");
address _rewardTokenAddress = poolInfo[_pid].rewardTokenAddress;
IBEP20 rewardToken = IBEP20 (_rewardTokenAddress);
uint256 _refundValue = claimableRewards(_pid, msg.sender);
require(_refundValue > 0, "No rewards to claim"); // check if there is any reward to claim
userInfo[_pid][msg.sender].rewardClaimed += _refundValue;
poolInfo[_pid].totalRewardsClaimed += _refundValue;
bool success = rewardToken.transferFrom(tokenWallet,msg.sender, _refundValue);
require(success, "Transfer failed");
}
// emergency withdraw function
function emergencyWithdraw (uint256 _pid) public lock {
require (_pid < poolLength(), "Invalid pool ID");
require (userInfo[_pid][msg.sender].amount > 0 , "You don't have any staked tokens");
require (userInfo[_pid][msg.sender].stakingTime > 0 , "You don't have any staked tokens");
address _tokenAddress = poolInfo[_pid].tokenAddress;
IBEP20 token = IBEP20 (_tokenAddress);
uint256 _amount = userInfo[_pid][msg.sender].amount;
userInfo[_pid][msg.sender].amount = 0;
userInfo[_pid][msg.sender].rewardClaimed = 0;
poolInfo[_pid].currentPoolSize = (poolInfo[_pid].currentPoolSize).sub(_amount);
uint256 afterDeductAmount = _amount.sub((_amount * poolInfo[_pid].emergencyFees) / 1000);
bool success = token.transferFrom(tokenWallet,msg.sender, afterDeductAmount);
require(success, "Transfer failed");
}
// this function is to withdraw BNB sent to this address by mistake
function withdrawEth () external onlyOwner returns (bool) {
uint256 balance = address(this).balance;
(bool success, ) = payable(msg.sender).call{
value: balance
}("");
return success;
}
// this function is to withdraw BEP20 tokens sent to this address by mistake
function withdrawBEP20 (address _tokenAddress) external onlyOwner returns (bool) {
IBEP20 token = IBEP20(_tokenAddress);
uint256 balance = token.balanceOf(address(this));
bool success = token.transfer(msg.sender, balance);
return success;
}
}