-
Notifications
You must be signed in to change notification settings - Fork 1
/
Distribution.sol
198 lines (166 loc) · 5.21 KB
/
Distribution.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
pragma solidity ^0.4.18;
import "zeppelin-solidity/contracts/token/BurnableToken.sol";
import "zeppelin-solidity/contracts/math/SafeMath.sol";
import 'zeppelin-solidity/contracts/ownership/Ownable.sol';
/**
* @title Distribution contract
* @dev see https://send.sd/distribution
*/
contract Distribution is Ownable {
using SafeMath for uint256;
uint16 public stages;
uint256 public stageDuration;
uint256 public startTime;
uint256 public soldTokens;
uint256 public bonusClaimedTokens;
uint256 public raisedETH;
uint256 public raisedUSD;
uint256 public weiUsdRate;
BurnableToken public token;
bool public isActive;
uint256 public cap;
uint256 public stageCap;
mapping (address => mapping (uint16 => uint256)) public contributions;
mapping (uint16 => uint256) public sold;
mapping (uint16 => bool) public burned;
mapping (address => mapping (uint16 => bool)) public claimed;
event NewPurchase(
address indexed purchaser,
uint256 sdtAmount,
uint256 usdAmount,
uint256 ethAmount
);
event NewBonusClaim(
address indexed purchaser,
uint256 sdtAmount
);
function Distribution(
uint16 _stages,
uint256 _stageDuration,
address _token
) public {
stages = _stages;
stageDuration = _stageDuration;
isActive = false;
token = BurnableToken(_token);
}
/**
* @dev contribution function
*/
function () external payable {
require(isActive);
require(weiUsdRate > 0);
require(getStage() < stages);
uint256 usd = msg.value / weiUsdRate;
uint256 tokens = computeTokens(usd);
uint16 stage = getStage();
sold[stage] = sold[stage].add(tokens);
require(sold[stage] < stageCap);
contributions[msg.sender][stage] = contributions[msg.sender][stage].add(tokens);
soldTokens = soldTokens.add(tokens);
raisedETH = raisedETH.add(msg.value);
raisedUSD = raisedUSD.add(usd);
NewPurchase(msg.sender, tokens, usd, msg.value);
token.transfer(msg.sender, tokens);
}
/**
* @dev Initialize distribution
* @param _cap uint256 The amount of tokens for distribution
*/
function init(uint256 _cap, uint256 _startTime) public onlyOwner {
require(!isActive);
require(token.balanceOf(this) == _cap);
require(_startTime > block.timestamp);
startTime = _startTime;
cap = _cap;
stageCap = cap / stages;
isActive = true;
}
/**
* @dev retrieve bonus from specified stage
* @param _stage uint16 The stage
*/
function claimBonus(uint16 _stage) public {
require(!claimed[msg.sender][_stage]);
require(getStage() > _stage);
if (!burned[_stage]) {
token.burn(stageCap.sub(sold[_stage]).sub(sold[_stage].mul(computeBonus(_stage)).div(1 ether)));
burned[_stage] = true;
}
uint256 tokens = computeAddressBonus(_stage);
token.transfer(msg.sender, tokens);
bonusClaimedTokens = bonusClaimedTokens.add(tokens);
claimed[msg.sender][_stage] = true;
NewBonusClaim(msg.sender, tokens);
}
/**
* @dev set an exchange rate in wei
* @param _rate uint256 The new exchange rate
*/
function setWeiUsdRate(uint256 _rate) public onlyOwner {
require(_rate > 0);
weiUsdRate = _rate;
}
/**
* @dev retrieve ETH
* @param _amount uint256 The new exchange rate
* @param _address address The address to receive ETH
*/
function forwardFunds(uint256 _amount, address _address) public onlyOwner {
_address.transfer(_amount);
}
/**
* @dev compute tokens given a USD value
* @param _usd uint256 Value in USD
*/
function computeTokens(uint256 _usd) public view returns(uint256) {
return _usd.mul(1000000000000000000 ether).div(
soldTokens.mul(19800000000000000000).div(cap).add(200000000000000000)
);
}
/**
* @dev current stage
*/
function getStage() public view returns(uint16) {
require(block.timestamp >= startTime);
return uint16(uint256(block.timestamp).sub(startTime).div(stageDuration));
}
/**
* @dev compute bonus (%) for a specified stage
* @param _stage uint16 The stage
*/
function computeBonus(uint16 _stage) public view returns(uint256) {
return uint256(100000000000000000).sub(sold[_stage].mul(100000).div(441095890411));
}
/**
* @dev compute for a specified stage
* @param _stage uint16 The stage
*/
function computeAddressBonus(uint16 _stage) public view returns(uint256) {
return contributions[msg.sender][_stage].mul(computeBonus(_stage)).div(1 ether);
}
//////////
// Safety Methods
//////////
/// @notice This method can be used by the controller to extract mistakenly
/// sent tokens to this contract.
/// @param _token The address of the token contract that you want to recover
/// set to 0 in case you want to extract ether.
function claimTokens(address _token) public onlyOwner {
// owner can claim any token but SDT
require(_token != address(token));
if (_token == 0x0) {
owner.transfer(this.balance);
return;
}
ERC20Basic erc20token = ERC20Basic(_token);
uint256 balance = erc20token.balanceOf(this);
erc20token.transfer(owner, balance);
ClaimedTokens(_token, owner, balance);
}
event ClaimedTokens(
address indexed _token,
address indexed _controller,
uint256 _amount
);
}