-
Notifications
You must be signed in to change notification settings - Fork 1
/
StrategyManager.sol
150 lines (139 loc) · 5.08 KB
/
StrategyManager.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
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
pragma abicoder v2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./IPositionManager.sol";
import "./BebraCoin.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "hardhat/console.sol";
contract StrategyManager is Ownable, Bebra {
IPositionManager[] strategies;
mapping(address => uint256) private strategiesBalances;
uint[] strategiesWeights;
uint8 strategiesCount;
address private constant USDC = 0x7F5c764cBc14f9669B88837ca1490cCa17c31607;
event StrategiesChanged(
address[] newStrategiesAddresses,
uint[] newStrategiesWeights
);
event Deposit(address depositor, uint amount);
event Withdraw(address withdrawer, uint amount);
event TokenRebased(
uint256 indexed reportTimestamp,
uint256 preTotalShares,
uint256 preTotalPooledAmount,
uint256 postTotalShares,
uint256 postTotalPooledAmount
);
constructor() Ownable(msg.sender) {}
function changeStrategies(
address[] memory _strategiesBatch,
uint[] memory _strategiesWeight
) external onlyOwner {
require(
_strategiesBatch.length == _strategiesWeight.length,
"wrong input length"
);
delete strategies;
delete strategiesWeights;
uint8 _strategiesCount = uint8(_strategiesBatch.length);
uint fullWeght;
for (uint i = 0; i < _strategiesCount; i++) {
fullWeght += _strategiesWeight[i];
}
require(fullWeght == 1e18, "wrong strategies weights");
strategiesCount = _strategiesCount;
for (uint i = 0; i < _strategiesCount; i++) {
strategies.push(IPositionManager(_strategiesBatch[i]));
strategiesWeights.push(_strategiesWeight[i]);
IERC20(USDC).approve(_strategiesBatch[i], 2 ** 256 - 1);
}
emit StrategiesChanged(_strategiesBatch, _strategiesWeight);
}
function _getTotalPooledAmount() internal view override returns (uint256) {
return (getTotalPooledAmount());
}
function getTotalPooledAmount() public view returns (uint amount) {
for (uint i = 0; i < strategiesCount; i++) {
amount += strategiesBalances[address(strategies[i])];
}
return amount;
}
function deposit(uint amount) external {
require(
IERC20(USDC).balanceOf(msg.sender) > amount,
"your balance not enough"
);
require(strategiesCount > 0, "no strategies to deposit");
SafeERC20.safeTransferFrom(
IERC20(USDC),
msg.sender,
address(this),
amount
);
(uint pooledAmount1, uint totalShares1) = _getDataForRebase();
for (uint i = 0; i < strategiesCount; i++) {
strategies[i].openPosition((amount * strategiesWeights[i]) / 1e18);
strategiesBalances[address(strategies[i])] = strategies[i]
.getTotalAmount();
}
_mintShares(msg.sender, amount);
(uint pooledAmount2, uint totalShares2) = _getDataForRebase();
emit TokenRebased(
block.timestamp,
totalShares1,
pooledAmount1,
totalShares2,
pooledAmount2
);
emit Deposit(msg.sender, amount);
}
function _getDataForRebase()
internal
view
returns (uint pooledAmount, uint totalShares)
{
return (getTotalPooledAmount(), _getTotalShares());
}
function closePosition(uint amount) external {
_burnShares(msg.sender, amount);
uint[] memory withdrawSharesPercentage = new uint[](strategiesCount);
(uint pooledAmount1, uint totalShares1) = _getDataForRebase();
for (uint i = 0; i < strategiesCount; i++) {
withdrawSharesPercentage[i] =
(amount * strategiesWeights[i]) /
strategies[i].getTotalAmount();
strategies[i].closePosition(
(withdrawSharesPercentage[i] * strategiesWeights[i]) / 1e18
);
strategiesBalances[address(strategies[i])] = strategies[i]
.getTotalAmount();
}
(uint pooledAmount2, uint totalShares2) = _getDataForRebase();
emit TokenRebased(
block.timestamp,
totalShares1,
pooledAmount1,
totalShares2,
pooledAmount2
);
emit Withdraw(msg.sender, amount);
}
function harvest() external {
(uint pooledAmount1, uint totalShares1) = _getDataForRebase();
for (uint i = 0; i < strategiesCount; i++) {
strategies[i].claimAndReinvest();
strategiesBalances[address(strategies[i])] = strategies[i]
.getTotalAmount();
}
(uint pooledAmount2, uint totalShares2) = _getDataForRebase();
emit TokenRebased(
block.timestamp,
totalShares1,
pooledAmount1,
totalShares2,
pooledAmount2
);
}
}