/
LeverageService.sol
executable file
·239 lines (198 loc) · 8.52 KB
/
LeverageService.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
236
237
238
239
pragma solidity 0.4.25;
import "../../helpers/SafeMath.sol";
import "../../helpers/ISettings.sol";
import "../../helpers/IToken.sol";
import "../../helpers/ITBoxManager.sol";
/// @title LeverageService
contract LeverageService {
using SafeMath for uint256;
/// @notice The address of the admin account.
address public admin;
// The amount of Ether received from the commissions of the system.
uint256 public systemETH;
// Commission percentage of leverage
uint256 public feeLeverage;
// Commission percentage of exchange
uint256 public feeExchange;
// The percentage divider
uint256 public divider = 100000;
// The minimum deposit amount
uint256 public minEther;
// The percent of maximum collateral percent for emitting
uint256 public safeCollateralPercent;
ISettings public settings;
/// @dev An array containing the Order struct for all Orders in existence. The ID
/// of each Order is actually an index into this array.
Order[] public orders;
/// @dev The main Order struct. Every Order is represented by a copy
/// of this structure.
struct Order {
address owner;
uint256 pack;
// 0: exchange order
// > 0: leverage order
uint256 percent;
}
/// @dev The OrderCreated event is fired whenever a new Order comes into existence.
event OrderCreated(uint256 id, address owner, uint256 pack, uint256 percent);
/// @dev The OrderClosed event is fired whenever Order is closed.
event OrderClosed(uint256 id, address who);
/// @dev The OrderMatched event is fired whenever an Order is matched.
event OrderMatched(uint256 id, uint256 tBox, address who, address owner);
event FeeUpdated(uint256 leverage, uint256 exchange);
event MinEtherUpdated(uint256 value);
event Transferred(address from, address to, uint256 id);
event SafeCollateralPercentUpdated(uint256 _value);
/// @dev Defends against front-running attacks.
modifier validTx() {
require(tx.gasprice <= settings.gasPriceLimit(), "Gas price is greater than allowed");
_;
}
/// @dev Access modifier for admin-only functionality.
modifier onlyAdmin() {
require(admin == msg.sender, "You have no access");
_;
}
/// @dev Access modifier for Order owner-only functionality.
modifier onlyOwner(uint256 _id) {
require(orders[_id].owner == msg.sender, "Order isn't your");
_;
}
modifier ensureLeverageOrder(uint256 _id) {
require(orders[_id].owner != address(0), "Order doesn't exist");
require(orders[_id].percent > 0, "Not a leverage order");
_;
}
modifier ensureExchnageOrder(uint256 _id) {
require(orders[_id].owner != address(0), "Order doesn't exist");
require(orders[_id].percent == 0, "Not an exchange order");
_;
}
/// @notice ISettings address couldn't be changed later.
/// @dev The contract constructor sets the original `admin` of the contract to the sender
// account and sets the settings contract with provided address.
/// @param _settings The address of the settings contract.
constructor(ISettings _settings) public {
admin = msg.sender;
settings = ISettings(_settings);
feeLeverage = 500; // 0.5%
feeExchange = 500; // 0.5%
emit FeeUpdated(feeLeverage, feeExchange);
minEther = 1 ether;
emit MinEtherUpdated(minEther);
safeCollateralPercent = 500 * divider;
emit SafeCollateralPercentUpdated(safeCollateralPercent);
}
/// @dev Withdraws system fee.
function withdrawSystemETH(address _beneficiary)
external
onlyAdmin
{
require(_beneficiary != address(0), "Zero address, be careful");
require(systemETH > 0, "There is no available ETH");
uint256 _systemETH = systemETH;
systemETH = 0;
_beneficiary.transfer(_systemETH);
}
/// @dev Reclaims ERC20 tokens.
function reclaimERC20(address _token, address _beneficiary)
external
onlyAdmin
{
require(_beneficiary != address(0), "Zero address, be careful");
uint256 _amount = IToken(_token).balanceOf(address(this));
require(_amount > 0, "There are no tokens");
IToken(_token).transfer(_beneficiary, _amount);
}
/// @dev Sets commission.
function setCommission(uint256 _leverage, uint256 _exchange) external onlyAdmin {
require(_leverage <= 10000 && _exchange <= 10000, "Too much");
feeLeverage = _leverage;
feeExchange = _exchange;
emit FeeUpdated(_leverage, _exchange);
}
/// @dev Sets minimum deposit amount.
function setMinEther(uint256 _value) external onlyAdmin {
require(_value <= 100 ether, "Too much");
minEther = _value;
emit MinEtherUpdated(_value);
}
/// @dev Sets maximum collateral percent.
/// @param _value The maximum collateral percent.
function setSafeCollateralPercent(uint256 _value) external onlyAdmin {
require(_value >= 300 * divider && _value <= 800 * divider, "Safe collateral percent out of range");
safeCollateralPercent = _value;
emit SafeCollateralPercentUpdated(_value);
}
/// @dev Sets admin address.
function changeAdmin(address _newAdmin) external onlyAdmin {
require(_newAdmin != address(0), "Zero address, be careful");
admin = _newAdmin;
}
/// @dev Creates an Order.
function create(uint256 _percent) public payable returns (uint256) {
require(msg.value >= minEther, "Too small funds");
require(_percent == 0
|| (_percent >= ITBoxManager(settings.logicManager()).withdrawPercent(msg.value)
&& _percent <= safeCollateralPercent),
"Collateral percent out of range"
);
Order memory _order = Order(msg.sender, msg.value, _percent);
uint256 _id = orders.push(_order).sub(1);
emit OrderCreated(_id, msg.sender, msg.value, _percent);
return _id;
}
/// @dev Closes an Order.
function close(uint256 _id) external onlyOwner(_id) {
uint256 _eth = orders[_id].pack;
delete orders[_id];
msg.sender.transfer(_eth);
emit OrderClosed(_id, msg.sender);
}
/// @dev Uses to match a leverage Order.
function takeLeverageOrder(uint256 _id) external payable ensureLeverageOrder(_id) validTx {
address _owner = orders[_id].owner;
uint256 _eth = orders[_id].pack.mul(divider).div(orders[_id].percent);
require(msg.value == _eth, "Incorrect ETH value");
uint256 _sysEth = _eth.mul(feeLeverage).div(divider);
systemETH = systemETH.add(_sysEth);
uint256 _tmv = _eth.mul(ITBoxManager(settings.logicManager()).rate()).div(
ITBoxManager(settings.logicManager()).precision()
);
uint256 _box = ITBoxManager(settings.logicManager()).create.value(
orders[_id].pack
)(_tmv);
uint256 _sysTmv = _tmv.mul(feeLeverage).div(divider);
delete orders[_id];
_owner.transfer(_eth.sub(_sysEth));
ITBoxManager(settings.logicManager()).transferFrom(
address(this),
_owner,
_box
);
IToken(settings.tmvAddress()).transfer(msg.sender, _tmv.sub(_sysTmv));
emit OrderMatched(_id, _box, msg.sender, _owner);
}
/// @dev Uses to match an exchange Order.
function takeExchangeOrder(uint256 _id) external payable ensureExchnageOrder(_id) validTx returns(uint256) {
address _owner = orders[_id].owner;
uint256 _eth = orders[_id].pack;
uint256 _sysEth = _eth.mul(feeExchange).div(divider);
systemETH = systemETH.add(_sysEth);
uint256 _tmv = _eth.mul(ITBoxManager(settings.logicManager()).rate()).div(ITBoxManager(settings.logicManager()).precision());
uint256 _box = ITBoxManager(settings.logicManager()).create.value(msg.value)(_tmv);
uint256 _sysTmv = _tmv.mul(feeExchange).div(divider);
delete orders[_id];
msg.sender.transfer(_eth.sub(_sysEth));
ITBoxManager(settings.logicManager()).transferFrom(address(this), msg.sender, _box);
IToken(settings.tmvAddress()).transfer(_owner, _tmv.sub(_sysTmv));
emit OrderMatched(_id, _box, msg.sender, _owner);
return _tmv.sub(_sysTmv);
}
/// @dev Transfers ownership of an Order.
function transfer(address _to, uint256 _id) external onlyOwner(_id) {
require(_to != address(0), "Zero address, be careful");
orders[_id].owner = _to;
emit Transferred(msg.sender, _to, _id);
}
}