contracts-imtbl/contracts/staking/RewardDistributor.sol
2024-08-27 15:24:09 +08:00

90 lines
3.0 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IRewardDistributor} from "./interfaces/IRewardDistributor.sol";
import {IRewardTracker} from "./interfaces/IRewardTracker.sol";
import {Governable} from "../core/Governable.sol";
contract RewardDistributor is IRewardDistributor, ReentrancyGuard, Governable {
using SafeERC20 for IERC20;
address public override rewardToken;
// 1个token, 在指定周期内, 每秒可获得的收益
// 比如收益是150%, 周期是1年, 那么 1.5 / (365 * 24 * 3600)
uint256 public override tokensPerInterval;
uint256 public lastDistributionTime;
// RewardTracker合约地址
address public rewardTracker;
address public admin;
event Distribute(uint256 amount);
event TokensPerIntervalChange(uint256 amount);
modifier onlyAdmin() {
require(msg.sender == admin, "RewardDistributor: forbidden");
_;
}
constructor(address _rewardToken, address _rewardTracker) {
rewardToken = _rewardToken;
rewardTracker = _rewardTracker;
admin = msg.sender;
}
function setAdmin(address _admin) external onlyGov {
admin = _admin;
}
// to help users who accidentally send their tokens to this contract
function withdrawToken(address _token, address _account, uint256 _amount) external onlyGov {
IERC20(_token).safeTransfer(_account, _amount);
}
function updateLastDistributionTime() external onlyAdmin {
lastDistributionTime = block.timestamp;
}
function setTokensPerInterval(uint256 _amount) external onlyAdmin {
require(lastDistributionTime != 0, "RewardDistributor: invalid lastDistributionTime");
IRewardTracker(rewardTracker).updateRewards();
tokensPerInterval = _amount;
emit TokensPerIntervalChange(_amount);
}
function pendingRewards() public view override returns (uint256) {
if (block.timestamp == lastDistributionTime) {
return 0;
}
uint256 timeDiff = block.timestamp - lastDistributionTime;
return tokensPerInterval * timeDiff;
}
// changed
// 从RewardTracker合约中调用
// 由于我们是每个用户单独计算收益, 所以这里需要传入具体数量, 用于计算需要transafer的数量
function distribute(uint256 _amount, uint256 _decimals) external override returns (uint256) {
require(msg.sender == rewardTracker, "RewardDistributor: invalid msg.sender");
uint256 amount = pendingRewards();
if (amount == 0) {
return 0;
}
lastDistributionTime = block.timestamp;
uint256 tokenAmount = amount * _amount / (10**_decimals);
uint256 balance = IERC20(rewardToken).balanceOf(address(this));
require(tokenAmount >= balance, "RewardDistributor: insufficient balance");
IERC20(rewardToken).safeTransfer(msg.sender, tokenAmount);
emit Distribute(tokenAmount);
return amount;
}
}