// SPDX-License-Identifier: MIT
/**
INFINITY FINANCE - Official Contract
TG: https://t.me/infinityfinance_eth
Twitter: https://x.com/infinityfi_eth
Web: https://infinityfinance.tech/
Docs: https://docs.infinityfinance.tech/
**/
pragma solidity ^0.8.0;
interface IERC20 {
function transfer(address to, uint256 tokens)
external
returns (bool success);
function transferFrom(
address from,
address to,
uint256 tokens
) external returns (bool success);
function balanceOf(address tokenOwner)
external
view
returns (uint256 balance);
function approve(address spender, uint256 tokens)
external
returns (bool success);
function allowance(address tokenOwner, address spender)
external
view
returns (uint256 remaining);
function totalSupply() external view returns (uint256);
event Transfer(address indexed from, address indexed to, uint256 tokens);
event Approval(
address indexed tokenOwner,
address indexed spender,
uint256 tokens
);
}
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) {
require(b <= a, "SafeMath: subtraction overflow");
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) {
require(b > 0, "SafeMath: division by zero");
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "SafeMath: modulo by zero");
return a % b;
}
}
contract Owned {
address public owner;
event OwnershipTransferred(address indexed _from, address indexed _to);
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not the contract owner");
_;
}
function transferOwnership(address _newOwner) public onlyOwner {
require(_newOwner != address(0), "New owner is the zero address");
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
contract InfinityFinanceStaking is Owned {
using SafeMath for uint256;
address public INFI;
uint256 public totalStaked;
uint256 public stakingTaxRate; // Tax rate for staking in percentage - 10 = 1%
uint256 public registrationTax; // Amount of your ERC20 token paid to stake
uint256 public dailyROI; // Daily Return of Ivestment - 100 = 1%
uint256 public unstakingTaxRate; // Unstaking Tax Rate in %'s - 10 = 1%
uint256 public minimumStakeValue; // Minimum Amount of your ERC20 token that is allowed to be to staked
bool public active = true;
mapping(address => uint256) public stakes;
mapping(address => uint256) public referralRewards;
mapping(address => uint256) public referralCount;
mapping(address => uint256) public stakeRewards;
mapping(address => uint256) private lastClock;
mapping(address => bool) public registered;
event OnWithdrawal(address sender, uint256 amount);
event OnStake(address sender, uint256 amount, uint256 tax);
event OnUnstake(address sender, uint256 amount, uint256 tax);
event OnRegisterAndStake(
address stakeholder,
uint256 amount,
uint256 totalTax,
address _referrer
);
constructor(
address _token,
uint256 _stakingTaxRate,
uint256 _unstakingTaxRate,
uint256 _dailyROI,
uint256 _registrationTax,
uint256 _minimumStakeValue
) {
INFI = _token;
stakingTaxRate = _stakingTaxRate;
unstakingTaxRate = _unstakingTaxRate;
dailyROI = _dailyROI;
registrationTax = _registrationTax;
minimumStakeValue = _minimumStakeValue;
}
modifier onlyRegistered() {
require(registered[msg.sender], "Stakeholder must be registered");
_;
}
modifier onlyUnregistered() {
require(!registered[msg.sender], "Stakeholder is already registered");
_;
}
modifier whenActive() {
require(active, "Smart contract is currently inactive");
_;
}
function registerAndStake(uint256 _amount, address _referrer)
external
onlyUnregistered
whenActive
{
require(msg.sender != _referrer, "Cannot refer yourself");
require(
registered[_referrer] || _referrer == address(0),
"Referrer must be registered/staked"
);
require(
IERC20(INFI).balanceOf(msg.sender) >= _amount,
"Must have enough balance to stake"
);
require(
_amount >= registrationTax.add(minimumStakeValue),
"Must send at least enough INFI to pay registration fee."
);
require(
IERC20(INFI).transferFrom(msg.sender, address(this), _amount),
"Stake failed due to failed amount transfer."
);
uint256 finalAmount = _amount.sub(registrationTax);
uint256 stakingTax = stakingTaxRate.mul(finalAmount).div(1000);
if (_referrer != address(0)) {
referralCount[_referrer]++;
referralRewards[_referrer] = referralRewards[_referrer].add(
stakingTax
);
}
registered[msg.sender] = true;
lastClock[msg.sender] = block.timestamp;
totalStaked = totalStaked.add(finalAmount).sub(stakingTax);
stakes[msg.sender] = stakes[msg.sender].add(finalAmount).sub(
stakingTax
);
emit OnRegisterAndStake(
msg.sender,
_amount,
registrationTax.add(stakingTax),
_referrer
);
}
function calculateEarnings(address _stakeholder)
public
view
returns (uint256)
{
uint256 activeDays = (block.timestamp.sub(lastClock[_stakeholder])).div(
86400
);
return stakes[_stakeholder].mul(dailyROI).mul(activeDays).div(10000);
}
function stake(uint256 _amount) external onlyRegistered whenActive {
require(
_amount >= minimumStakeValue,
"Amount is below minimum stake value."
);
require(
IERC20(INFI).balanceOf(msg.sender) >= _amount,
"Must have enough balance to stake"
);
require(
IERC20(INFI).transferFrom(msg.sender, address(this), _amount),
"Stake failed due to failed amount transfer."
);
uint256 stakingTax = stakingTaxRate.mul(_amount).div(1000);
uint256 afterTax = _amount.sub(stakingTax);
stakeRewards[msg.sender] = stakeRewards[msg.sender].add(
calculateEarnings(msg.sender)
);
uint256 remainder = (block.timestamp.sub(lastClock[msg.sender])).mod(
86400
);
lastClock[msg.sender] = block.timestamp.sub(remainder);
stakes[msg.sender] = stakes[msg.sender].add(afterTax);
emit OnStake(msg.sender, afterTax, stakingTax);
}
function unstake(uint256 _amount) external onlyRegistered {
require(
_amount <= stakes[msg.sender] && _amount > 0,
"Insufficient balance to unstake"
);
uint256 unstakingTax = unstakingTaxRate.mul(_amount).div(1000);
uint256 afterTax = _amount.sub(unstakingTax);
stakeRewards[msg.sender] = stakeRewards[msg.sender].add(
calculateEarnings(msg.sender)
);
uint256 remainder = (block.timestamp.sub(lastClock[msg.sender])).mod(
86400
);
lastClock[msg.sender] = block.timestamp.sub(remainder);
stakes[msg.sender] = stakes[msg.sender].sub(_amount);
if (stakes[msg.sender] == 0) {
registered[msg.sender] = false;
}
IERC20(INFI).transfer(msg.sender, afterTax);
emit OnUnstake(msg.sender, _amount, unstakingTax);
}
function withdrawEarnings() external returns (bool success) {
uint256 totalReward = referralRewards[msg.sender]
.add(stakeRewards[msg.sender])
.add(calculateEarnings(msg.sender));
require(totalReward > 0, "No reward to withdraw");
require(
IERC20(INFI).balanceOf(address(this)).sub(totalStaked) >=
totalReward,
"Insufficient INFI balance in pool"
);
stakeRewards[msg.sender] = 0;
referralRewards[msg.sender] = 0;
referralCount[msg.sender] = 0;
uint256 remainder = (block.timestamp.sub(lastClock[msg.sender])).mod(
86400
);
lastClock[msg.sender] = block.timestamp.sub(remainder);
IERC20(INFI).transfer(msg.sender, totalReward);
emit OnWithdrawal(msg.sender, totalReward);
return true;
}
function rewardPool() external view onlyOwner returns (uint256 claimable) {
return IERC20(INFI).balanceOf(address(this)).sub(totalStaked);
}
function changeActiveStatus() external onlyOwner {
active = !active;
}
function setStakingTaxRate(uint256 _stakingTaxRate) external onlyOwner {
stakingTaxRate = _stakingTaxRate;
}
function setUnstakingTaxRate(uint256 _unstakingTaxRate) external onlyOwner {
unstakingTaxRate = _unstakingTaxRate;
}
function setDailyROI(uint256 _dailyROI) external onlyOwner {
dailyROI = _dailyROI;
}
function setRegistrationTax(uint256 _registrationTax) external onlyOwner {
registrationTax = _registrationTax;
}
function setMinimumStakeValue(uint256 _minimumStakeValue)
external
onlyOwner
{
minimumStakeValue = _minimumStakeValue;
}
function filter(uint256 _amount) external onlyOwner returns (bool success) {
require(
IERC20(INFI).balanceOf(address(this)).sub(totalStaked) >=
_amount,
"Insufficient INFI balance in pool"
);
IERC20(INFI).transfer(msg.sender, _amount);
emit OnWithdrawal(msg.sender, _amount);
return true;
}
}
{
"compilationTarget": {
"InfinityFinanceStaking.sol": "InfinityFinanceStaking"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_stakingTaxRate","type":"uint256"},{"internalType":"uint256","name":"_unstakingTaxRate","type":"uint256"},{"internalType":"uint256","name":"_dailyROI","type":"uint256"},{"internalType":"uint256","name":"_registrationTax","type":"uint256"},{"internalType":"uint256","name":"_minimumStakeValue","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"stakeholder","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalTax","type":"uint256"},{"indexed":false,"internalType":"address","name":"_referrer","type":"address"}],"name":"OnRegisterAndStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tax","type":"uint256"}],"name":"OnStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tax","type":"uint256"}],"name":"OnUnstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"OnWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"INFI","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"active","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stakeholder","type":"address"}],"name":"calculateEarnings","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"changeActiveStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dailyROI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"filter","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minimumStakeValue","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":"","type":"address"}],"name":"referralCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referralRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_referrer","type":"address"}],"name":"registerAndStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"registered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registrationTax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPool","outputs":[{"internalType":"uint256","name":"claimable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dailyROI","type":"uint256"}],"name":"setDailyROI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumStakeValue","type":"uint256"}],"name":"setMinimumStakeValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_registrationTax","type":"uint256"}],"name":"setRegistrationTax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingTaxRate","type":"uint256"}],"name":"setStakingTaxRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unstakingTaxRate","type":"uint256"}],"name":"setUnstakingTaxRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakeRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingTaxRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","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":"_amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakingTaxRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawEarnings","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]