generated from yearn/brownie-strategy-mix
-
Notifications
You must be signed in to change notification settings - Fork 70
/
AlphaHomoLender.sol
195 lines (152 loc) · 6.53 KB
/
AlphaHomoLender.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
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "../Interfaces/alpha-homora/Bank.sol";
import "../Interfaces/alpha-homora/BankConfig.sol";
import "../Interfaces/UniswapInterfaces/IWETH.sol";
import "./GenericLenderBase.sol";
/********************
* A lender plugin for LenderYieldOptimiser for any erc20 asset on Cream (not eth)
* Made by SamPriestley.com
* https://github.com/Grandthrax/yearnv2/blob/master/contracts/GenericLender/GenericCream.sol
*
********************* */
contract AlphaHomo is GenericLenderBase {
using SafeERC20 for IERC20;
using Address for address;
using SafeMath for uint256;
uint256 private constant secondsPerYear = 31556952;
address public constant weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
address public constant bank = address(0x67B66C99D3Eb37Fa76Aa3Ed1ff33E8e39F0b9c7A);
constructor(address _strategy, string memory name) public GenericLenderBase(_strategy, name) {
require(address(want) == weth, "NOT WETH");
dust = 1e12;
//want.approve(_cToken, uint256(-1));
}
receive() external payable {}
function nav() external view override returns (uint256) {
return _nav();
}
function _nav() internal view returns (uint256) {
return want.balanceOf(address(this)).add(underlyingBalanceStored());
}
function withdrawUnderlying(uint256 amount) internal returns (uint256) {
Bank b = Bank(bank);
uint256 shares = amount.mul(b.totalSupply()).div(_bankTotalEth());
//uint256 shares = amount.mul(b.glbDebtVal().add(b.pendingInterest(0))).div(b.glbDebtShare());
// uint256 shares = b.debtValToShare(amount);
uint256 balance = b.balanceOf(address(this));
if (shares > balance) {
b.withdraw(balance);
} else {
b.withdraw(shares);
}
uint256 withdrawn = address(this).balance;
IWETH(weth).deposit{value: withdrawn}();
return withdrawn;
}
function underlyingBalanceStored() public view returns (uint256 balance) {
Bank b = Bank(bank);
return b.balanceOf(address(this)).mul(_bankTotalEth()).div(b.totalSupply());
//return b.balanceOf(address(this)).mul(b.glbDebtVal().add(b.pendingInterest(0))).div(b.glbDebtShare());
}
function _bankTotalEth() internal view returns (uint256 _totalEth) {
Bank b = Bank(bank);
uint256 interest = b.pendingInterest(0);
BankConfig config = BankConfig(b.config());
uint256 toReserve = interest.mul(config.getReservePoolBps()).div(10000);
uint256 glbDebtVal = b.glbDebtVal().add(interest);
uint256 reservePool = b.reservePool().add(toReserve);
_totalEth = bank.balance.add(glbDebtVal).sub(reservePool);
}
function apr() external view override returns (uint256) {
return _apr(0);
}
function aprAfterDeposit(uint256 amount) external view override returns (uint256) {
return _apr(amount);
}
function _apr(uint256 amount) internal view returns (uint256) {
Bank b = Bank(bank);
BankConfig config = BankConfig(b.config());
uint256 balance = bank.balance.add(amount);
uint256 ratePerSec = config.getInterestRate(b.glbDebtVal(), balance);
return ratePerSec.mul(secondsPerYear);
}
function weightedApr() external view override returns (uint256) {
uint256 a = _apr(0);
return a.mul(_nav());
}
function withdraw(uint256 amount) external override management returns (uint256) {
return _withdraw(amount);
}
//emergency withdraw. sends balance plus amount to governance
function emergencyWithdraw(uint256 amount) external override management {
withdrawUnderlying(amount);
want.safeTransfer(vault.governance(), want.balanceOf(address(this)));
}
//withdraw an amount including any want balance
function _withdraw(uint256 amount) internal returns (uint256) {
uint256 balanceUnderlying = underlyingBalanceStored();
uint256 looseBalance = want.balanceOf(address(this));
uint256 total = balanceUnderlying.add(looseBalance);
if (amount > total) {
//cant withdraw more than we own
amount = total;
}
if (looseBalance >= amount) {
want.safeTransfer(address(strategy), amount);
return amount;
}
//not state changing but OK because of previous call
uint256 liquidity = bank.balance;
if (liquidity > 1) {
uint256 toWithdraw = amount.sub(looseBalance);
if (toWithdraw <= liquidity) {
//we can take all
withdrawUnderlying(toWithdraw);
} else {
//take all we can
withdrawUnderlying(liquidity);
}
}
looseBalance = want.balanceOf(address(this));
want.safeTransfer(address(strategy), looseBalance);
return looseBalance;
}
function deposit() external override management {
uint256 balance = want.balanceOf(address(this));
IWETH(weth).withdraw(balance);
Bank(bank).deposit{value: balance}();
}
function withdrawAll() external override management returns (bool) {
uint256 invested = _nav();
Bank b = Bank(bank);
uint256 balance = b.balanceOf(address(this));
b.withdraw(balance);
uint256 withdrawn = address(this).balance;
IWETH(weth).deposit{value: withdrawn}();
uint256 returned = want.balanceOf(address(this));
want.safeTransfer(address(strategy), returned);
return returned.add(dust) >= invested;
}
//think about this
function enabled() external view override returns (bool) {
return true;
}
function hasAssets() external view override returns (bool) {
uint256 bankBal = Bank(bank).balanceOf(address(this));
uint256 wantBal = want.balanceOf(address(this));
//adding apples to oranges but doesnt matter as we are just looking for rounding errors
return bankBal.add(wantBal) > dust;
}
function protectedTokens() internal view override returns (address[] memory) {
address[] memory protected = new address[](2);
protected[0] = address(want);
protected[1] = bank;
return protected;
}
}