-
Notifications
You must be signed in to change notification settings - Fork 98
/
Copy path0xb62132e35a6c13ee1ee0f84dc5d40bad8d815206-NEXO-Nexo.sol
475 lines (394 loc) · 15 KB
/
0xb62132e35a6c13ee1ee0f84dc5d40bad8d815206-NEXO-Nexo.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
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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
pragma solidity 0.4.23;
//
// This source file is part of the current-contracts open source project
// Copyright 2018 Zerion LLC
// Licensed under Apache License v2.0
//
// @title Abstract ERC20 token interface
contract AbstractToken {
function balanceOf(address owner) public view returns (uint256 balance);
function transfer(address to, uint256 value) public returns (bool success);
function transferFrom(address from, address to, uint256 value) public returns (bool success);
function approve(address spender, uint256 value) public returns (bool success);
function allowance(address owner, address spender) public view returns (uint256 remaining);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract Owned {
address public owner = msg.sender;
address public potentialOwner;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
modifier onlyPotentialOwner {
require(msg.sender == potentialOwner);
_;
}
event NewOwner(address old, address current);
event NewPotentialOwner(address old, address potential);
function setOwner(address _new)
public
onlyOwner
{
emit NewPotentialOwner(owner, _new);
potentialOwner = _new;
}
function confirmOwnership()
public
onlyPotentialOwner
{
emit NewOwner(owner, potentialOwner);
owner = potentialOwner;
potentialOwner = address(0);
}
}
// @title SafeMath contract - Math operations with safety checks.
// @author OpenZeppelin: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/math/SafeMath.sol
contract SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
/**
* @dev Raises `a` to the `b`th power, throws on overflow.
*/
function pow(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a ** b;
assert(c >= a);
return c;
}
}
/// Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/issues/20
contract StandardToken is AbstractToken, Owned, SafeMath {
/*
* Data structures
*/
mapping (address => uint256) internal balances;
mapping (address => mapping (address => uint256)) internal allowed;
uint256 public totalSupply;
/*
* Read and write storage functions
*/
/// @dev Transfers sender's tokens to a given address. Returns success.
/// @param _to Address of token receiver.
/// @param _value Number of tokens to transfer.
function transfer(address _to, uint256 _value) public returns (bool success) {
return _transfer(msg.sender, _to, _value);
}
/// @dev Allows allowed third party to transfer tokens from one address to another. Returns success.
/// @param _from Address from where tokens are withdrawn.
/// @param _to Address to where tokens are sent.
/// @param _value Number of tokens to transfer.
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(allowed[_from][msg.sender] >= _value);
allowed[_from][msg.sender] -= _value;
return _transfer(_from, _to, _value);
}
/// @dev Returns number of tokens owned by given address.
/// @param _owner Address of token owner.
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
/// @dev Sets approved amount of tokens for spender. Returns success.
/// @param _spender Address of allowed account.
/// @param _value Number of approved tokens.
function approve(address _spender, uint256 _value) public returns (bool success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/*
* Read storage functions
*/
/// @dev Returns number of allowed tokens for given address.
/// @param _owner Address of token owner.
/// @param _spender Address of token spender.
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return allowed[_owner][_spender];
}
/**
* @dev Private transfer, can only be called by this contract.
* @param _from The address of the sender.
* @param _to The address of the recipient.
* @param _value The amount to send.
* @return success True if the transfer was successful, or throws.
*/
function _transfer(address _from, address _to, uint256 _value) private returns (bool success) {
require(_to != address(0));
require(balances[_from] >= _value);
balances[_from] -= _value;
balances[_to] = add(balances[_to], _value);
emit Transfer(_from, _to, _value);
return true;
}
}
/// @title Token contract - Implements Standard ERC20 with additional features.
/// @author Zerion - <inbox@zerion.io>
contract Token is StandardToken {
// Time of the contract creation
uint256 public creationTime;
function Token() public {
/* solium-disable-next-line security/no-block-members */
creationTime = now;
}
/// @dev Owner can transfer out any accidentally sent ERC20 tokens
function transferERC20Token(AbstractToken _token, address _to, uint256 _value)
public
onlyOwner
returns (bool success)
{
require(_token.balanceOf(address(this)) >= _value);
uint256 receiverBalance = _token.balanceOf(_to);
require(_token.transfer(_to, _value));
uint256 receiverNewBalance = _token.balanceOf(_to);
assert(receiverNewBalance == add(receiverBalance, _value));
return true;
}
/// @dev Increases approved amount of tokens for spender. Returns success.
function increaseApproval(address _spender, uint256 _value) public returns (bool success) {
allowed[msg.sender][_spender] = add(allowed[msg.sender][_spender], _value);
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/// @dev Decreases approved amount of tokens for spender. Returns success.
function decreaseApproval(address _spender, uint256 _value) public returns (bool success) {
uint256 oldValue = allowed[msg.sender][_spender];
if (_value > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = sub(oldValue, _value);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
// @title Token contract - Implements Standard ERC20 Token for NEXO project.
/// @author Zerion - <inbox@zerion.io>
contract NexoToken is Token {
/// TOKEN META DATA
string constant public name = 'Nexo';
string constant public symbol = 'NEXO';
uint8 constant public decimals = 18;
/// ALOCATIONS
// To calculate vesting periods we assume that 1 month is always equal to 30 days
/*** Initial Investors' tokens ***/
// 525,000,000 (52.50%) tokens are distributed among initial investors
// These tokens will be distributed without vesting
address public investorsAllocation = address(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF);
uint256 public investorsTotal = 525000000e18;
/*** Overdraft Reserves ***/
// 250,000,000 (25%) tokens will be eventually available for overdraft
// These tokens will be distributed monthly with a 6 month cliff within a year
// 41,666,666 tokens will be unlocked every month after the cliff
// 4 tokens will be unlocked without vesting to ensure that total amount sums up to 250,000,000.
address public overdraftAllocation = address(0x1111111111111111111111111111111111111111);
uint256 public overdraftTotal = 250000000e18;
uint256 public overdraftPeriodAmount = 41666666e18;
uint256 public overdraftUnvested = 4e18;
uint256 public overdraftCliff = 5 * 30 days;
uint256 public overdraftPeriodLength = 30 days;
uint8 public overdraftPeriodsNumber = 6;
/*** Tokens reserved for Founders and Team ***/
// 112,500,000 (11.25%) tokens will be eventually available for the team
// These tokens will be distributed every 3 month without a cliff within 4 years
// 7,031,250 tokens will be unlocked every 3 month
address public teamAllocation = address(0x2222222222222222222222222222222222222222);
uint256 public teamTotal = 112500000e18;
uint256 public teamPeriodAmount = 7031250e18;
uint256 public teamUnvested = 0;
uint256 public teamCliff = 0;
uint256 public teamPeriodLength = 3 * 30 days;
uint8 public teamPeriodsNumber = 16;
/*** Tokens reserved for Community Building and Airdrop Campaigns ***/
// 60,000,000 (6%) tokens will be eventually available for the community
// 10,000,002 tokens will be available instantly without vesting
// 49,999,998 tokens will be distributed every 3 month without a cliff within 18 months
// 8,333,333 tokens will be unlocked every 3 month
address public communityAllocation = address(0x3333333333333333333333333333333333333333);
uint256 public communityTotal = 60000000e18;
uint256 public communityPeriodAmount = 8333333e18;
uint256 public communityUnvested = 10000002e18;
uint256 public communityCliff = 0;
uint256 public communityPeriodLength = 3 * 30 days;
uint8 public communityPeriodsNumber = 6;
/*** Tokens reserved for Advisors, Legal and PR ***/
// 52,500,000 (5.25%) tokens will be eventually available for advisers
// 25,000,008 tokens will be available instantly without vesting
// 27 499 992 tokens will be distributed monthly without a cliff within 12 months
// 2,291,666 tokens will be unlocked every month
address public advisersAllocation = address(0x4444444444444444444444444444444444444444);
uint256 public advisersTotal = 52500000e18;
uint256 public advisersPeriodAmount = 2291666e18;
uint256 public advisersUnvested = 25000008e18;
uint256 public advisersCliff = 0;
uint256 public advisersPeriodLength = 30 days;
uint8 public advisersPeriodsNumber = 12;
/// CONSTRUCTOR
function NexoToken() public {
// Overall, 1,000,000,000 tokens exist
totalSupply = 1000000000e18;
balances[investorsAllocation] = investorsTotal;
balances[overdraftAllocation] = overdraftTotal;
balances[teamAllocation] = teamTotal;
balances[communityAllocation] = communityTotal;
balances[advisersAllocation] = advisersTotal;
// Unlock some tokens without vesting
allowed[investorsAllocation][msg.sender] = investorsTotal;
allowed[overdraftAllocation][msg.sender] = overdraftUnvested;
allowed[communityAllocation][msg.sender] = communityUnvested;
allowed[advisersAllocation][msg.sender] = advisersUnvested;
}
/// DISTRIBUTION
function distributeInvestorsTokens(address _to, uint256 _amountWithDecimals)
public
onlyOwner
{
require(transferFrom(investorsAllocation, _to, _amountWithDecimals));
}
/// VESTING
function withdrawOverdraftTokens(address _to, uint256 _amountWithDecimals)
public
onlyOwner
{
allowed[overdraftAllocation][msg.sender] = allowance(overdraftAllocation, msg.sender);
require(transferFrom(overdraftAllocation, _to, _amountWithDecimals));
}
function withdrawTeamTokens(address _to, uint256 _amountWithDecimals)
public
onlyOwner
{
allowed[teamAllocation][msg.sender] = allowance(teamAllocation, msg.sender);
require(transferFrom(teamAllocation, _to, _amountWithDecimals));
}
function withdrawCommunityTokens(address _to, uint256 _amountWithDecimals)
public
onlyOwner
{
allowed[communityAllocation][msg.sender] = allowance(communityAllocation, msg.sender);
require(transferFrom(communityAllocation, _to, _amountWithDecimals));
}
function withdrawAdvisersTokens(address _to, uint256 _amountWithDecimals)
public
onlyOwner
{
allowed[advisersAllocation][msg.sender] = allowance(advisersAllocation, msg.sender);
require(transferFrom(advisersAllocation, _to, _amountWithDecimals));
}
/// @dev Overrides StandardToken.sol function
function allowance(address _owner, address _spender)
public
view
returns (uint256 remaining)
{
if (_spender != owner) {
return allowed[_owner][_spender];
}
uint256 unlockedTokens;
uint256 spentTokens;
if (_owner == overdraftAllocation) {
unlockedTokens = _calculateUnlockedTokens(
overdraftCliff,
overdraftPeriodLength,
overdraftPeriodAmount,
overdraftPeriodsNumber,
overdraftUnvested
);
spentTokens = sub(overdraftTotal, balanceOf(overdraftAllocation));
} else if (_owner == teamAllocation) {
unlockedTokens = _calculateUnlockedTokens(
teamCliff,
teamPeriodLength,
teamPeriodAmount,
teamPeriodsNumber,
teamUnvested
);
spentTokens = sub(teamTotal, balanceOf(teamAllocation));
} else if (_owner == communityAllocation) {
unlockedTokens = _calculateUnlockedTokens(
communityCliff,
communityPeriodLength,
communityPeriodAmount,
communityPeriodsNumber,
communityUnvested
);
spentTokens = sub(communityTotal, balanceOf(communityAllocation));
} else if (_owner == advisersAllocation) {
unlockedTokens = _calculateUnlockedTokens(
advisersCliff,
advisersPeriodLength,
advisersPeriodAmount,
advisersPeriodsNumber,
advisersUnvested
);
spentTokens = sub(advisersTotal, balanceOf(advisersAllocation));
} else {
return allowed[_owner][_spender];
}
return sub(unlockedTokens, spentTokens);
}
/// @dev Overrides Owned.sol function
function confirmOwnership()
public
onlyPotentialOwner
{
// Forbid the old owner to distribute investors' tokens
allowed[investorsAllocation][owner] = 0;
// Allow the new owner to distribute investors' tokens
allowed[investorsAllocation][msg.sender] = balanceOf(investorsAllocation);
// Forbid the old owner to withdraw any tokens from the reserves
allowed[overdraftAllocation][owner] = 0;
allowed[teamAllocation][owner] = 0;
allowed[communityAllocation][owner] = 0;
allowed[advisersAllocation][owner] = 0;
super.confirmOwnership();
}
function _calculateUnlockedTokens(
uint256 _cliff,
uint256 _periodLength,
uint256 _periodAmount,
uint8 _periodsNumber,
uint256 _unvestedAmount
)
private
view
returns (uint256)
{
/* solium-disable-next-line security/no-block-members */
if (now < add(creationTime, _cliff)) {
return _unvestedAmount;
}
/* solium-disable-next-line security/no-block-members */
uint256 periods = div(sub(now, add(creationTime, _cliff)), _periodLength);
periods = periods > _periodsNumber ? _periodsNumber : periods;
return add(_unvestedAmount, mul(periods, _periodAmount));
}
}