Description:
Decentralized Finance (DeFi) protocol contract providing Staking, Factory functionality.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"settings": {
"evmVersion": "cancun",
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": []
},
"sources": {
"project/contracts/TokenFarm.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
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;
IBEP20 public stakingToken;
IBEP20 public rewardToken;
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.
uint256 rewardETHClaimed; // The amount of reward claimed by the user.
}
struct Pool {
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 totalTokenRewards; // total rewards for the pool
uint256 totalETHRewards; // total rewards for the pool
uint256 totalRewardsClaimed; // total rewards claimed by the users
uint256 totalETHRewardsClaimed; // total rewards claimed by the users
bool poolType; // true for public staking, false for whitelist staking
bool poolActive;
}
// Info of each pool.
Pool public pool;
uint256[] public rewardETHTimes;
uint256[] public rewardTimes;
bool lock_= false;
uint256 public totalRewardsClaimed = 0;
// Info of each user that stakes tokens.
mapping(address => UserInfo) public userInfo;
mapping(uint256 => uint256) public rewardAmount;
mapping(address => bool) public whitelistedAddress;
mapping(uint256 => uint256) public rewardCurrentPoolSize;
// rewardETHAmount is the amount of reward in ETH
mapping(uint256 => uint256) public rewardETHAmount;
mapping(uint256 => uint256) public rewardETHCurrentPoolSize;
// rewards claimed by the user
mapping(address => uint256) public tokenRewardsClaimed;
mapping(address => uint256) public ethRewardsClaimed;
event Staked(address indexed user, uint256 amount, uint256 time);
event Unstaked(address indexed user, uint256 amount, uint256 time);
event EmergencyWithdraw(address indexed user, uint256 amount, uint256 time);
event Claimed(address indexed user, uint256 amount, uint256 ethAmount, uint256 time);
constructor (address _tokenAddress, address _rewardTokenAddress) {
stakingToken = IBEP20(_tokenAddress);
rewardToken = IBEP20(_rewardTokenAddress);
}
modifier lock {
require(!lock_, "Process is locked");
lock_ = true;
_;
lock_ = false;
}
function addPool (uint256 _maxPoolSize, uint256 _maxContribution,uint256 _emergencyFee, uint256 _minContribution, uint256 _apy, uint256 _minLockDays, bool _poolType, bool _poolActive) public onlyOwner {
pool = Pool({
maxPoolSize: _maxPoolSize,
currentPoolSize: 0,
minContribution: _minContribution,
maxContribution: _maxContribution,
apy: _apy,
emergencyFees: _emergencyFee,
minLockDays: _minLockDays,
poolType: _poolType,
poolActive: _poolActive,
totalRewardsClaimed: 0,
totalETHRewardsClaimed: 0,
totalTokenRewards: 0,
totalETHRewards: 0
});
}
function updateMaxPoolSize (uint256 _maxPoolSize) public onlyOwner{
require (_maxPoolSize >= pool.currentPoolSize, "Cannot reduce the max size below the current pool size");
pool.maxPoolSize = _maxPoolSize;
}
function updateMaxContribution (uint256 _maxContribution) public onlyOwner{
pool.maxContribution = _maxContribution;
}
function updateEmergencyFees ( uint256 _emergencyFees) public onlyOwner {
if (pool.currentPoolSize > 0){
require (_emergencyFees <= pool.emergencyFees, "You can't increase the emergency fees when people started staking");
}
pool.emergencyFees = _emergencyFees;
}
function updateMinLockDays (uint256 _lockDays) public onlyOwner {
require (pool.currentPoolSize == 0, "Cannot change lock time after people started staking");
pool.minLockDays = _lockDays;
}
function updateApy (uint256 _apy) public onlyOwner {
pool.apy = _apy;
}
function updatePoolType (bool _poolType) public onlyOwner {
pool.poolType = _poolType;
}
function updatePoolActive (bool _poolActive) public onlyOwner {
pool.poolActive = _poolActive;
}
function updateMinContribution (uint256 _minContribution) public onlyOwner {
pool.minContribution = _minContribution;
}
function addWhitelist (address [] memory _whitelistAddresses) public onlyOwner {
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[_whitelistAddress] = true;
}
}
function addReward (uint256 _amount) public onlyOwner {
rewardTimes.push(block.timestamp);
rewardAmount[block.timestamp] = _amount;
pool.totalTokenRewards = (pool.totalTokenRewards).add(_amount);
rewardCurrentPoolSize[block.timestamp] = pool.currentPoolSize;
bool success = rewardToken.transferFrom(msg.sender, address(this), _amount);
require(success, "Transfer failed");
}
function addETHReward () public payable onlyOwner {
uint256 _amount = msg.value;
rewardETHTimes.push(block.timestamp);
rewardETHAmount[block.timestamp] = _amount;
pool.totalETHRewards = (pool.totalETHRewards).add(_amount);
rewardETHCurrentPoolSize[block.timestamp] = pool.currentPoolSize;
_sendEther(address(this), _amount);
}
function emergencyLock (bool _lock) public onlyOwner {
lock_ = _lock;
}
function stakeTokens (uint256 _amount) public {
require (pool.poolActive, "Pool is not active");
require (_amount >= pool.minContribution, "Amount is less than min contribution");
require (pool.currentPoolSize.add(_amount) <= pool.maxPoolSize, "Staking exceeds max pool size");
require ((userInfo[msg.sender].amount).add(_amount) <= pool.maxContribution , "Max Contribution exceeds");
if (pool.poolType == false){
require (whitelistedAddress[msg.sender], "You are not whitelisted for this pool");
}
// Sending the claimable tokens to the user
if (claimableRewards(msg.sender) > 0){
_claimTokenRewards(msg.sender);
}
if(claimableETHReward(msg.sender) > 0){
_claimETHRewards(msg.sender);
}
bool success = stakingToken.transferFrom(msg.sender, address(this), _amount);
require (success, "Transfer From failed. Please approve the token");
pool.currentPoolSize = (pool.currentPoolSize).add(_amount);
uint256 _stakingTime = block.timestamp;
_amount = _amount.add(userInfo[msg.sender].amount);
userInfo[msg.sender] = UserInfo({
amount: _amount,
stakingTime: _stakingTime,
rewardClaimed: 0,
rewardETHClaimed: 0
});
emit Staked(msg.sender, _amount, _stakingTime);
}
function claimableRewards (address _user) public view returns (uint256) {
uint256 _stakingTime = userInfo[_user].stakingTime;
if (userInfo[_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[_user].amount * _rewardAmount) / (_rewardCurrentPoolSize));
_claimableReward = _claimableReward.add(_refundValue);
}
}
if (userInfo[_user].rewardClaimed >= _claimableReward) return 0;
return _claimableReward - userInfo[_user].rewardClaimed;
}
function claimableNativeRewards (address _user) public view returns (uint256) {
uint256 lockDays = (block.timestamp - userInfo[_user].stakingTime) / 1 days;
uint256 _refundValue = ((userInfo[_user].amount * pool.apy * lockDays) / (1000 * 365));
return _refundValue;
}
function claimableETHReward (address _user) public view returns (uint256) {
uint256 _stakingTime = userInfo[_user].stakingTime;
if (userInfo[_user].amount == 0) return 0;
uint256 _claimableReward = 0;
for (uint256 i = 0; i < rewardETHTimes.length; i++){
uint256 _rewardTime = rewardETHTimes[i];
uint256 _rewardAmount = rewardETHAmount[_rewardTime];
uint256 _rewardCurrentPoolSize = rewardETHCurrentPoolSize[_rewardTime];
if (_rewardTime > _stakingTime){
uint256 _refundValue = ((userInfo[_user].amount * _rewardAmount) / (_rewardCurrentPoolSize));
_claimableReward = _claimableReward.add(_refundValue);
}
}
if (userInfo[_user].rewardETHClaimed >= _claimableReward) return 0;
return _claimableReward - userInfo[_user].rewardETHClaimed;
}
function unstakeTokens () public lock {
require (userInfo[msg.sender].amount > 0 , "You don't have any staked tokens");
require (userInfo[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[msg.sender].stakingTime) / 1 days;
require (lockDays >= pool.minLockDays, "You can't unstake before min lock days");
uint256 _amount = userInfo[msg.sender].amount;
// claimethreward
if(claimableETHReward(msg.sender) > 0){
_claimETHRewards(msg.sender);
}
uint256 _refundValue = claimableRewards(msg.sender);
uint256 _nativeReward = claimableNativeRewards(msg.sender);
pool.currentPoolSize = (pool.currentPoolSize).sub(userInfo[msg.sender].amount);
pool.totalRewardsClaimed += _refundValue;
tokenRewardsClaimed[msg.sender] += _refundValue + _nativeReward;
_resetUser(); // reset the user data
bool success1 = stakingToken.transfer(msg.sender, _amount);
bool success2 = stakingToken.transfer(msg.sender, _nativeReward);
bool success3 = rewardToken.transfer(msg.sender, _refundValue);
require(success1 && success2 && success3, "Transfer failed");
emit Unstaked(msg.sender, _amount, block.timestamp);
}
function unlockAfter(address user) public view returns (uint256) {
return userInfo[user].stakingTime + (pool.minLockDays * 1 days);
}
function claimRewards() public lock {
_claimTokenRewards(msg.sender);
}
function claimETHReward() public lock {
_claimETHRewards(msg.sender);
}
// emergency withdraw function
function emergencyWithdraw () public lock {
require (userInfo[msg.sender].amount > 0 , "You don't have any staked tokens");
require (userInfo[msg.sender].stakingTime > 0 , "You don't have any staked tokens");
uint256 _amount = userInfo[msg.sender].amount;
pool.currentPoolSize = (pool.currentPoolSize).sub(_amount);
_resetUser(); // reset the user data
uint256 afterDeductAmount = _amount.sub((_amount * pool.emergencyFees) / 1000);
bool success = stakingToken.transfer(msg.sender, afterDeductAmount);
require(success, "Transfer failed");
emit EmergencyWithdraw(msg.sender, _amount, block.timestamp);
}
// send Ether
function _sendEther(address _to, uint256 _amount) internal {
(bool success,) = payable(_to).call{value: _amount}("");
require(success, "Transfer failed");
}
function _claimTokenRewards(address user) private {
require(userInfo[user].amount > 0, "You don't have any staked tokens");
require(userInfo[user].stakingTime > 0, "You don't have any staked tokens");
uint256 claimableAmount = claimableRewards(user);
require(claimableAmount > 0, "No rewards to claim");
// Update state
pool.totalRewardsClaimed += claimableAmount;
userInfo[user].rewardClaimed += claimableAmount;
tokenRewardsClaimed[user] += claimableAmount;
// Transfer rewards
require(rewardToken.transfer(user, claimableAmount), "Transfer failed");
emit Claimed(user, claimableAmount, 0, block.timestamp);
}
function _claimETHRewards(address user) private {
require(userInfo[user].amount > 0, "You don't have any staked tokens");
require(userInfo[user].stakingTime > 0, "You don't have any staked tokens");
uint256 claimableAmount = claimableETHReward(user);
require(claimableAmount > 0, "No rewards to claim");
// Update state
pool.totalETHRewardsClaimed += claimableAmount;
userInfo[user].rewardETHClaimed += claimableAmount;
ethRewardsClaimed[user] += claimableAmount;
// Transfer ETH rewards
_sendEther(user, claimableAmount);
emit Claimed(user, 0, claimableAmount, block.timestamp);
}
function _resetUser() private {
userInfo[msg.sender].amount = 0;
userInfo[msg.sender].rewardClaimed = 0;
userInfo[msg.sender].stakingTime = 0;
userInfo[msg.sender].rewardETHClaimed = 0;
}
// receive Ether
receive() external payable {}
// this function is to withdraw BNB sent to this address by mistake
function withdrawEth (uint256 amount) external onlyOwner returns (bool) {
(bool success, ) = payable(msg.sender).call{
value: amount
}("");
return success;
}
// this function is to withdraw BEP20 tokens sent to this address by mistake
function withdrawBEP20 (address _tokenAddress, uint256 amount) external onlyOwner returns (bool) {
IBEP20 token = IBEP20(_tokenAddress);
bool success = token.transfer(msg.sender, amount);
return success;
}
}"
}
}
}}
Submitted on: 2025-10-10 09:01:40
Comments
Log in to comment.
No comments yet.