90 lines
3.0 KiB
Solidity
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;
|
|
}
|
|
}
|