pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol";
contract StakingPool is Ownable { IERC20 public stakingToken; // Token used for staking IERC20 public rewardToken; // Token used for rewards
uint256 public rewardRate = 100; // Rewards per block (or unit of time)
uint256 public lastUpdateTime;
uint256 public rewardPerTokenStored;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;
uint256 private _totalSupply;
mapping(address => uint256) private _balances;
constructor(address _stakingToken, address _rewardToken) {
stakingToken = IERC20(_stakingToken);
rewardToken = IERC20(_rewardToken);
}
// Modifier to update rewards for the staker
modifier updateReward(address account) {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = block.timestamp;
if (account != address(0)) {
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
}
_;
}
// View function to return total staked tokens in the pool
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
// View function to return staked tokens for a user
function balanceOf(address account) external view returns (uint256) {
return _balances[account];
}
// Function to stake tokens into the pool
function stake(uint256 amount) external updateReward(msg.sender) {
require(amount > 0, "Cannot stake 0");
_totalSupply += amount;
_balances[msg.sender] += amount;
stakingToken.transferFrom(msg.sender, address(this), amount);
}
// Function to withdraw staked tokens from the pool
function withdraw(uint256 amount) external updateReward(msg.sender) {
require(amount > 0, "Cannot withdraw 0");
_totalSupply -= amount;
_balances[msg.sender] -= amount;
stakingToken.transfer(msg.sender, amount);
}
// Function to claim rewards
function getReward() external updateReward(msg.sender) {
uint256 reward = rewards[msg.sender];
require(reward > 0, "No rewards available");
rewards[msg.sender] = 0;
rewardToken.transfer(msg.sender, reward);
}
// Helper function to calculate rewards per token
function rewardPerToken() public view returns (uint256) {
if (_totalSupply == 0) {
return rewardPerTokenStored;
}
return rewardPerTokenStored + (
rewardRate * (block.timestamp - lastUpdateTime) * 1e18 / _totalSupply
);
}
// Helper function to calculate earned rewards for a user
function earned(address account) public view returns (uint256) {
return (_balances[account] * (rewardPerToken() - userRewardPerTokenPaid[account]) / 1e18) + rewards[account];
}
// Owner function to set the reward rate
function setRewardRate(uint256 _rewardRate) external onlyOwner {
rewardRate = _rewardRate;
}
}