-
Notifications
You must be signed in to change notification settings - Fork 0
/
DFDComptroller.sol
136 lines (113 loc) · 4.22 KB
/
DFDComptroller.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
pragma solidity 0.5.17;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20, SafeMath} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import {Math} from "@openzeppelin/contracts/math/Math.sol";
import {Ownable} from "@openzeppelin/contracts/ownership/Ownable.sol";
import {IComptroller, IDFDComptroller} from "../interfaces/IComptroller.sol";
import {Uni} from "../interfaces/Uni.sol";
contract RewardDistributionRecipient is Ownable {
address public rewardDistribution;
function notifyRewardAmount(uint256 reward) external;
modifier onlyRewardDistribution() {
require(_msgSender() == rewardDistribution, "Caller is not reward distribution");
_;
}
function setRewardDistribution(address _rewardDistribution)
external
onlyOwner
{
rewardDistribution = _rewardDistribution;
}
}
contract DFDComptroller is RewardDistributionRecipient, IDFDComptroller {
using SafeERC20 for IERC20;
using SafeMath for uint;
uint public constant DURATION = 7 days;
/*
Todo (before deployment)
1. Provide comptroller and beneficiary (ibDFD vault) address
2. Make the following constant
*/
address public uni = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
address public beneficiary; // ibDFD
IERC20 public dfd = IERC20(0x20c36f062a31865bED8a5B1e512D9a1A20AA333A);
IERC20 public dusd = IERC20(0x5BC25f649fc4e26069dDF4cF4010F9f706c23831);
IComptroller public comptroller;
uint public periodFinish;
uint public rewardRate;
uint public lastUpdateTime;
uint public rewardStored;
uint public rewardPaid;
event RewardAdded(uint reward);
event RewardPaid(address indexed user, uint256 reward);
event Harvested(uint indexed dusd, uint indexed dfd);
modifier updateReward() {
uint _lastTimeRewardApplicable = lastTimeRewardApplicable();
rewardStored = rewardStored.add(
_lastTimeRewardApplicable
.sub(lastUpdateTime)
.mul(rewardRate)
);
lastUpdateTime = _lastTimeRewardApplicable;
_;
}
function lastTimeRewardApplicable() public view returns (uint256) {
return Math.min(_timestamp(), periodFinish);
}
function getReward()
external
updateReward
{
require(msg.sender == beneficiary, "GET_REWARD_NO_AUTH");
uint reward = rewardStored.sub(rewardPaid);
rewardPaid = rewardStored;
dfd.safeTransfer(beneficiary, reward);
emit RewardPaid(beneficiary, reward);
}
function availableReward() public view returns(uint) {
return lastTimeRewardApplicable()
.sub(lastUpdateTime)
.mul(rewardRate)
.add(rewardStored)
.sub(rewardPaid);
}
function notifyRewardAmount(uint256 reward)
external
onlyRewardDistribution
updateReward
{
dfd.safeTransferFrom(msg.sender, address(this), reward);
if (block.timestamp >= periodFinish) {
rewardRate = reward.div(DURATION);
} else {
uint256 remaining = periodFinish.sub(block.timestamp);
uint256 leftover = remaining.mul(rewardRate);
rewardRate = reward.add(leftover).div(DURATION);
}
lastUpdateTime = block.timestamp;
periodFinish = block.timestamp.add(DURATION);
emit RewardAdded(reward);
}
function harvest()
onlyOwner
external
{
// This contract will receive dusd because it should be a registered beneficiary
comptroller.harvest();
uint256 _dusd = dusd.balanceOf(address(this));
if (_dusd > 0) {
dusd.approve(uni, _dusd);
address[] memory path = new address[](3);
path[0] = address(dusd);
path[1] = address(dfd);
uint[] memory amounts = Uni(uni).swapExactTokensForTokens(_dusd, uint256(0), path, address(this), now.add(1800));
if (amounts[1] > 0) {
dfd.safeTransfer(beneficiary, amounts[1]);
}
emit Harvested(_dusd, amounts[1]);
}
}
function _timestamp() internal view returns (uint) {
return block.timestamp;
}
}