-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStrategy.sol
More file actions
272 lines (207 loc) · 10.3 KB
/
Strategy.sol
File metadata and controls
272 lines (207 loc) · 10.3 KB
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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
pragma solidity >= 0.6.0 < 0.6.5;
pragma experimental ABIEncoderV2;
import "github.com/OpenZeppelin/zeppelin-solidity/contracts/math/SafeMath.sol";
//import "./CFT.sol";
// Given a client address, check if it exists in our clients, replace requires with this check --done
// Decision to be made on clients reinvesting in the same strategy --done
// Do we need any other confirmation before setting start_time and end_time?
// Set binanceStratAccount and fundAccount
// calculate fees and transfer to our address
// decide when we shall deduct 2% initial
// Run solidity static analysis
// Investment doesn't expire until the user says so
// Multiple investments can be made to the strategy, regardless of if a previous investment period has ended or not
// Implement accepting of usdt
// Sending
//check if amount os approved before calling transferFrom
// 1st - 500 month 1 ->
// 2nd - 500 month 2 ->
// Main => management
contract Strategy {
using SafeMath for uint;
CFT cftoken;//To instantiate the token
address public fund_manager;//
string strategyName;
uint min_amt;
int256 min_return;
bool status = true; //True => active
address payable binanceStratAccount;//change
address payable fundAccount = 0x058E4741d78B60185aaDa1129D19baB7b9949962;
// Should we remove an investment if end trade has been reached;
mapping (address => mapping(uint => Investment)) public investments;
mapping (address => uint) investmentLength;
address[] clientList;
event EndTrade(address, uint, Investment);
event TradingResult(address, uint, Investment);
struct Investment {
uint amt;
uint256 duration;
uint256 start_time;
uint256 end_time;
uint256 tradeResults;
uint fees;
bool trading;
uint8 flag;
}
modifier onlyManager(){
require(msg.sender == fund_manager);
_;
}
//constructor -- making it payable to add ETH to be used as Gas to cover Provable query costs
constructor(address payable _binanceAccount, string memory _strategyName, uint _min_amt, int256 _min_return) public payable{
fund_manager = msg.sender;
cftoken = CFT(tokenContract);
binanceStratAccount = _binanceAccount;
strategyName = _strategyName;
min_amt = _min_amt;
min_return = _min_return;
}
//function transfer(address _to, uint256 _value) onlyManager public payable{
// cftoken.transfer(_to, _value);
//To transfer tokens from THIS CONTRACT address
//}
//function transferFrom(address _from, address _to, uint256 _value) onlyManager public payable returns (bool success){
// cftoken.transferFrom(_from, _to, cftoken.allowance[_from][_to]);
//Works only after approve has been called from the _from address with _to adress being approved
//}
// function approve(uint256 _value) public{
// //This allows this CONTRACT to withdraw tokens from some other address
// cftoken.approve(address(this), _value);
// }
//function balanceof(address adr) public payable returns(uint){
//TO check balance.. What else do you want?
//return cftoken.balanceOf(adr);
//}
function getFundManager() external view returns(address){
return fund_manager;
}
function getContractBalance() external view returns(uint bal){
return address(this).balance;
}
function addGas() public payable returns(uint gas){
return msg.value;
}
function updateMinimumAmount(uint _min_amt) onlyManager external{
min_amt = _min_amt;
}
function updateMinimumReturn(int _min_return) onlyManager external{
min_return = _min_return;
}
function updateStatus(bool _status) onlyManager external{
status = _status;
}
function setClient(address _clientAdd, uint256 _duration) external payable {
// Check for usdt
require(status == true, "This Strategy is not currently active.");
require(cftoken.allowance[_clientAdd][address(this)] >= min_amt, "Can't do xxx");
require(cftoken.balanceof(_clientAdd) >= cftoken.allowance[_clientAdd][address(this)]);
uint approvedAmount = cftoken.allowance[_clientAdd][address(this)];
cftoken.transferFrom(_clientAdd, address(this), approvedAmount);
//it should revert if this transferFrom fails.
uint newIndex;
uint transferableAmount;
uint initialFees;
if((investmentLength[_clientAdd] == 0)) {
clientList.push(_clientAdd);
newIndex = 1;
investmentLength[_clientAdd] = 1;
}
else{
newIndex = investmentLength[_clientAdd] + 1;
investmentLength[_clientAdd] = newIndex;
}
transferableAmount =approvedAmount.sub((approvedAmount.mul(2)).div(100));
initialFees = (approvedAmount.mul(2)).div(100);
transferFunds( transferableAmount, initialFees );
investments[_clientAdd][newIndex].start_time = block.timestamp;
investments[_clientAdd][newIndex].duration = _duration;
investments[_clientAdd][newIndex].amt = transferableAmount;
investments[_clientAdd][newIndex].end_time = investments[_clientAdd][newIndex].start_time.add(investments[_clientAdd][newIndex].duration);
investments[_clientAdd][newIndex].trading = true;
investments[_clientAdd][newIndex].flag = 1;
}
// confirm if the address actually exists?
function transferFunds(uint transferableAmount, uint initialFees) private {
//binanceStratAccount.transfer(transferableAmount);
//fundAccount.transfer(initialFees);
cftoken.transfer(binanceStratAccount, transferableAmount);
cftoken.transfer(fundAccount, initialFees);
}
function getClients() onlyManager external view returns(address[] memory){
return clientList;
}
function getActiveInvestments(address _adrs) external view returns(Investment[] memory){
require(msg.sender == _adrs || msg.sender == fund_manager, "You do not have access");
Investment[] memory activeInvestments;
uint a=0;
for(uint i; i<investmentLength[_adrs]; i++){
if(investments[_adrs][i].trading == true){
activeInvestments[a]=investments[_adrs][i];
a++;
}
}
return activeInvestments;
}
// function getActiveInvestmentIds(address _adrs) external view returns(uint[] memory){
// require(msg.sender == _adrs || msg.sender == fund_manager, "You do not have access");
// uint[] memory ids;
// uint a=0;
// for(uint i; i<investmentLength[_adrs]; i++){
// if(investments[_adrs][i].trading == true){
// ids[a]=i;
// a++;
// }
// }
// }
// function getInvestmentPerId(address _adrs, uint id) external view returns(Investment memory){
// require(msg.sender == _adrs || msg.sender == fund_manager, "You do not have access");
// return investments[_adrs][id];
// }
// again, check if the address is valid and call from cron job
function end_trade(address _clientAdd, uint _index) public {
require(msg.sender == _clientAdd || msg.sender == fund_manager, "You do not have access");
require(investments[_clientAdd][_index].flag == 1, "This client does not exist");
require(investments[_clientAdd][_index].trading == true, "You do not have any active investments");
emit EndTrade(_clientAdd, _index, investments[_clientAdd][_index]);
}
function setResults(address _clientAdd, uint _index, int256 _results) onlyManager external {
if(investments[_clientAdd][_index].trading != false) { //is it necessary as we are already checking in end_trade
uint result = 0;
uint amount = investments[_clientAdd][_index].amt;
if(_results > min_return) //profit 5% to deduct fees, change it based on start_time and end_time
{
uint res = (amount.mul(uint(_results)).div(10000)); //fees set to 20% of profit
investments[_clientAdd][_index].fees = uint((res.mul(20)).div(100));
result = amount.add(uint((res.mul(80)).div(100)));
} else if(_results > 0 && _results <= min_return) {
result = amount.add((amount.mul(uint(_results))).div(10000));
} else {
result = amount.sub((amount.mul(uint(_results))).div(10000));
}
investments[_clientAdd][_index].tradeResults = result;
}
emitClientInvestments(_clientAdd, _index);
}
function emitClientInvestments(address _clientAdd, uint _index) private {
emit TradingResult(_clientAdd, _index, investments[_clientAdd][_index]);
}
function getTradingResult (address _clientAdd, uint _index) view public returns(uint) {
require(msg.sender == _clientAdd || msg.sender == fund_manager, "You do not have access");
return investments[_clientAdd][_index].tradeResults;
}
function withdraw(address _clientAdd, uint _index) onlyManager external {
uint payableAmount;
if(investments[_clientAdd][_index].trading != false) { //is it necessary as we are already checking in end_trade
require(investments[_clientAdd][_index].tradeResults > 0, "Trade Result is not set");
payableAmount = investments[_clientAdd][_index].tradeResults;
investments[_clientAdd][_index].trading = false;
}
//require(address(this).balance > (payableAmount.add(investments[_clientAdd][_index].fees)), "Sufficient funds not available");
require(cftoken.balanceof(address(this)) > (payableAmount.add(investments[_clientAdd][_index].fees)), "Sufficient funds not available");
address payable payableClientAddress = payable(_clientAdd);
//payableClientAddress.transfer(payableAmount);
//fundAccount.transfer(investments[_clientAdd][_index].fees);
transfer(payableClientAddress, payableAmount);
transfer(fundAccount, investments[_clientAdd][_index].fees);
}
}