-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAggregator.sol
235 lines (186 loc) · 7.16 KB
/
Aggregator.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "hardhat/console.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
// Interface for ERC20 DAI contract
interface DAI {
event Approval(address, address, uint256);
event Transfer(address, address, uint256);
function allowance(address, address) external view returns (uint256);
function approve(address, uint256) external returns (bool);
function mint(address, uint256) external returns (uint256);
function balanceOf(address) external view returns (uint256);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function transfer(address, uint256) external returns (bool);
function transferFrom(address, address, uint256) external returns (bool);
function wards(address) external view returns (uint256);
}
// Interface for Compound's cDAI contract
interface cDAI {
function mint(uint256) external returns (uint256);
function redeem(uint256) external returns (uint256);
function balanceOf(address) external view returns (uint256);
function supplyRatePerBlock() external view returns (uint256);
}
interface aDAI {
function balanceOf(address) external view returns (uint256);
}
// Interface for Aave's lending pool contract
interface AaveLendingPool {
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
function withdraw(
address asset,
uint256 amount,
address to
) external;
function getReserveData(address asset)
external
view
returns (
uint256 configuration,
uint128 liquidityIndex,
uint128 variableBorrowIndex,
uint128 currentLiquidityRate,
uint128 currentVariableBorrowRate,
uint128 currentStableBorrowRate,
uint40 lastUpdateTimestamp,
address aTokenAddress,
address stableDebtTokenAddress,
address variableDebtTokenAddress,
address interestRateStrategyAddress,
uint8 id
);
}
contract Aggregator {
using SafeMath for uint256;
// Variables
string public name = "Yield Aggregator";
address public owner;
address public locationOfFunds; // Keep track of where the user balance is stored
uint256 public amountDeposited;
DAI dai = DAI(0x6B175474E89094C44Da98b954EedeAC495271d0F);
cDAI cDai = cDAI(0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643);
aDAI aDai = aDAI(0x028171bCA77440897B824Ca71D1c56caC55b68A3);
AaveLendingPool aaveLendingPool =
AaveLendingPool(0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9);
// Events
event Deposit(address owner, uint256 amount, address depositTo);
event Withdraw(address owner, uint256 amount, address withdrawFrom);
event Rebalance(address owner, uint256 amount, address depositTo);
modifier onlyOwner() {
require(msg.sender == owner, "Only owner allowed");
_;
}
// Constructor
constructor() {
owner = msg.sender;
}
// Functions
function deposit(
uint256 _amount,
uint256 _compAPY,
uint256 _aaveAPY
) public onlyOwner {
require(_amount > 0);
// Rebalance in the case of a protocol with the higher rate after their initial deposit,
// is no longer the higher interest rate during this deposit...
if (amountDeposited > 0) {
rebalance(_compAPY, _aaveAPY);
}
dai.transferFrom(msg.sender, address(this), _amount);
amountDeposited = amountDeposited.add(_amount);
// Compare interest rates
if (_compAPY > _aaveAPY) {
// Deposit into Compound
require(_depositToCompound(_amount) == 0);
// Update location
locationOfFunds = address(cDai);
} else {
// Deposit into Aave
_depositToAave(_amount);
// Update location
locationOfFunds = address(aaveLendingPool);
}
// Emit Deposit event
emit Deposit(msg.sender, _amount, locationOfFunds);
}
function withdraw() public onlyOwner {
require(amountDeposited > 0);
// Determine where the user funds are stored
if (locationOfFunds == address(cDai)) {
require(_withdrawFromCompound() == 0);
} else {
// Withdraw from Aave
_withdrawFromAave();
}
// Once we have the funds, transfer back to owner
uint256 balance = dai.balanceOf(address(this));
dai.transfer(msg.sender, balance);
emit Withdraw(msg.sender, amountDeposited, locationOfFunds);
// Reset user balance
amountDeposited = 0;
}
function rebalance(uint256 _compAPY, uint256 _aaveAPY) public onlyOwner {
// Make sure funds are already deposited...
require(amountDeposited > 0);
uint256 balance;
// Compare interest rates
if ((_compAPY > _aaveAPY) && (locationOfFunds != address(cDai))) {
// If compoundRate is greater than aaveRate, and the current
// location of user funds is not in compound, then we transfer funds.
_withdrawFromAave();
balance = dai.balanceOf(address(this));
_depositToCompound(balance);
// Update location
locationOfFunds = address(cDai);
emit Rebalance(msg.sender, amountDeposited, locationOfFunds);
} else if (
(_aaveAPY > _compAPY) &&
(locationOfFunds != address(aaveLendingPool))
) {
// If aaveRate is greater than compoundRate, and the current
// location of user funds is not in aave, then we transfer funds.
_withdrawFromCompound();
balance = dai.balanceOf(address(this));
_depositToAave(balance);
// Update location
locationOfFunds = address(aaveLendingPool);
emit Rebalance(msg.sender, amountDeposited, locationOfFunds);
}
}
function _depositToCompound(uint256 _amount) internal returns (uint256) {
require(dai.approve(address(cDai), _amount));
uint256 result = cDai.mint(_amount);
return result;
}
function _withdrawFromCompound() internal returns (uint256) {
uint256 balance = cDai.balanceOf(address(this));
uint256 result = cDai.redeem(balance);
return result;
}
function _depositToAave(uint256 _amount) internal {
require(dai.approve(address(aaveLendingPool), _amount));
aaveLendingPool.deposit(address(dai), _amount, address(this), 0);
}
function _withdrawFromAave() internal {
uint256 balance = aDai.balanceOf(address(this));
aaveLendingPool.withdraw(address(dai), balance, address(this));
}
// ---
function balanceOfContract() public view returns (uint256) {
if (locationOfFunds == address(cDai)) {
return cDai.balanceOf(address(this));
} else {
return aDai.balanceOf(address(this));
}
}
function balanceWhere() public view returns (address) {
return locationOfFunds;
}
}