This repository has been archived by the owner on May 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 25
/
KinTokenSale.sol
334 lines (268 loc) · 13.4 KB
/
KinTokenSale.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
pragma solidity ^0.4.15;
import './SafeMath.sol';
import './Ownable.sol';
import './TokenHolder.sol';
import './KinToken.sol';
import './VestingTrustee.sol';
/// @title Kin token sale contract.
contract KinTokenSale is Ownable, TokenHolder {
using SafeMath for uint256;
// External parties:
// KIN token contract.
KinToken public kin;
// Vesting contract for pre-sale participants.
VestingTrustee public trustee;
// Received funds are forwarded to this address.
address public fundingRecipient;
// Kin token unit.
// Using same decimal value as ETH (makes ETH-KIN conversion much easier).
// This is the same as in Kin token contract.
uint256 public constant TOKEN_UNIT = 10 ** 18;
// Maximum number of tokens in circulation: 10 trillion.
uint256 public constant MAX_TOKENS = 10 ** 13 * TOKEN_UNIT;
// Maximum tokens offered in the sale.
uint256 public constant MAX_TOKENS_SOLD = 512195121951 * TOKEN_UNIT;
// Wei to 1 USD ratio.
uint256 public constant WEI_PER_USD = uint256(1 ether) / 289;
// KIN to 1 USD ratio,
// such that MAX_TOKENS_SOLD / KIN_PER_USD is the $75M cap.
uint256 public constant KIN_PER_USD = 6829 * TOKEN_UNIT;
// KIN to 1 wei ratio.
uint256 public constant KIN_PER_WEI = KIN_PER_USD / WEI_PER_USD;
// Sale start and end timestamps.
uint256 public constant SALE_DURATION = 14 days;
uint256 public startTime;
uint256 public endTime;
// Amount of tokens sold until now in the sale.
uint256 public tokensSold = 0;
// Participation caps, according to KYC tiers.
uint256 public constant TIER_1_CAP = 100000 * WEI_PER_USD;
uint256 public constant TIER_2_CAP = uint256(-1); // Maximum uint256 value
// Accumulated amount each participant has contributed so far.
mapping (address => uint256) public participationHistory;
// Maximum amount that each participant is allowed to contribute (in WEI).
mapping (address => uint256) public participationCaps;
// Maximum amount ANYBODY is currently allowed to contribute.
uint256 public hardParticipationCap = 4393 * WEI_PER_USD;
// Vesting information for special addresses:
struct TokenGrant {
uint256 value;
uint256 startOffset;
uint256 cliffOffset;
uint256 endOffset;
uint256 installmentLength;
uint8 percentVested;
}
address[] public tokenGrantees;
mapping (address => TokenGrant) public tokenGrants;
uint256 public lastGrantedIndex = 0;
uint256 public constant MAX_TOKEN_GRANTEES = 100;
uint256 public constant GRANT_BATCH_SIZE = 10;
// Post-TDE multisig addresses.
address public constant KIN_FOUNDATION_ADDRESS = 0x56aE76573EC54754bC5B6A8cBF04bBd7Dc86b0A0;
address public constant KIK_ADDRESS = 0x3bf4BbE253153678E9E8E540395C22BFf7fCa87d;
event TokensIssued(address indexed _to, uint256 _tokens);
/// @dev Reverts if called when not during sale.
modifier onlyDuringSale() {
require(!saleEnded() && now >= startTime);
_;
}
/// @dev Reverts if called before sale ends.
modifier onlyAfterSale() {
require(saleEnded());
_;
}
/// @dev Constructor that initializes the sale conditions.
/// @param _fundingRecipient address The address of the funding recipient.
/// @param _startTime uint256 The start time of the token sale.
function KinTokenSale(address _fundingRecipient, uint256 _startTime) {
require(_fundingRecipient != address(0));
require(_startTime > now);
// Deploy new KinToken contract.
kin = new KinToken();
// Deploy new VestingTrustee contract.
trustee = new VestingTrustee(kin);
fundingRecipient = _fundingRecipient;
startTime = _startTime;
endTime = startTime + SALE_DURATION;
// Initialize special vesting grants.
initTokenGrants();
}
/// @dev Initialize token grants.
function initTokenGrants() private onlyOwner {
// Issue the remaining 60% to Kin Foundation's multisig wallet. In a few days, after the token sale is
// finalized, these tokens will be loaded into the KinVestingTrustee smart contract, according to the white
// paper. Please note, that this is implied by setting a 0% vesting percent.
tokenGrantees.push(KIN_FOUNDATION_ADDRESS);
tokenGrants[KIN_FOUNDATION_ADDRESS] = TokenGrant(MAX_TOKENS.mul(60).div(100), 0, 0, 3 years, 1 days, 0);
// Kik, 30%
tokenGrantees.push(KIK_ADDRESS);
tokenGrants[KIK_ADDRESS] = TokenGrant(MAX_TOKENS.mul(30).div(100), 0, 0, 120 weeks, 12 weeks, 100);
}
/// @dev Adds a Kin token vesting grant.
/// @param _grantee address The address of the token grantee. Can be granted only once.
/// @param _value uint256 The value of the grant.
function addTokenGrant(address _grantee, uint256 _value) external onlyOwner {
require(_grantee != address(0));
require(_value > 0);
require(tokenGrantees.length + 1 <= MAX_TOKEN_GRANTEES);
// Verify the grant doesn't already exist.
require(tokenGrants[_grantee].value == 0);
for (uint i = 0; i < tokenGrantees.length; i++) {
require(tokenGrantees[i] != _grantee);
}
// Add grant and add to grantee list.
tokenGrantees.push(_grantee);
tokenGrants[_grantee] = TokenGrant(_value, 0, 1 years, 1 years, 1 days, 50);
}
/// @dev Deletes a Kin token grant.
/// @param _grantee address The address of the token grantee.
function deleteTokenGrant(address _grantee) external onlyOwner {
require(_grantee != address(0));
// Delete the grant from the keys array.
for (uint i = 0; i < tokenGrantees.length; i++) {
if (tokenGrantees[i] == _grantee) {
delete tokenGrantees[i];
break;
}
}
// Delete the grant from the mapping.
delete tokenGrants[_grantee];
}
/// @dev Add a list of participants to a capped participation tier.
/// @param _participants address[] The list of participant addresses.
/// @param _cap uint256 The cap amount (in ETH).
function setParticipationCap(address[] _participants, uint256 _cap) private onlyOwner {
for (uint i = 0; i < _participants.length; i++) {
participationCaps[_participants[i]] = _cap;
}
}
/// @dev Add a list of participants to cap tier #1.
/// @param _participants address[] The list of participant addresses.
function setTier1Participants(address[] _participants) external onlyOwner {
setParticipationCap(_participants, TIER_1_CAP);
}
/// @dev Add a list of participants to tier #2.
/// @param _participants address[] The list of participant addresses.
function setTier2Participants(address[] _participants) external onlyOwner {
setParticipationCap(_participants, TIER_2_CAP);
}
/// @dev Set hard participation cap for all participants.
/// @param _cap uint256 The hard cap amount.
function setHardParticipationCap(uint256 _cap) external onlyOwner {
require(_cap > 0);
hardParticipationCap = _cap;
}
/// @dev Fallback function that will delegate the request to create().
function () external payable onlyDuringSale {
create(msg.sender);
}
/// @dev Create and sell tokens to the caller.
/// @param _recipient address The address of the recipient receiving the tokens.
function create(address _recipient) public payable onlyDuringSale {
require(_recipient != address(0));
// Enforce participation cap (in Wei received).
uint256 weiAlreadyParticipated = participationHistory[msg.sender];
uint256 participationCap = SafeMath.min256(participationCaps[msg.sender], hardParticipationCap);
uint256 cappedWeiReceived = SafeMath.min256(msg.value, participationCap.sub(weiAlreadyParticipated));
require(cappedWeiReceived > 0);
// Accept funds and transfer to funding recipient.
uint256 weiLeftInSale = MAX_TOKENS_SOLD.sub(tokensSold).div(KIN_PER_WEI);
uint256 weiToParticipate = SafeMath.min256(cappedWeiReceived, weiLeftInSale);
participationHistory[msg.sender] = weiAlreadyParticipated.add(weiToParticipate);
fundingRecipient.transfer(weiToParticipate);
// Issue tokens and transfer to recipient.
uint256 tokensLeftInSale = MAX_TOKENS_SOLD.sub(tokensSold);
uint256 tokensToIssue = weiToParticipate.mul(KIN_PER_WEI);
if (tokensLeftInSale.sub(tokensToIssue) < KIN_PER_WEI) {
// If purchase would cause less than KIN_PER_WEI tokens left then nobody could ever buy them.
// So, gift them to the last buyer.
tokensToIssue = tokensLeftInSale;
}
tokensSold = tokensSold.add(tokensToIssue);
issueTokens(_recipient, tokensToIssue);
// Partial refund if full participation not possible
// e.g. due to cap being reached.
uint256 refund = msg.value.sub(weiToParticipate);
if (refund > 0) {
msg.sender.transfer(refund);
}
}
/// @dev Finalizes the token sale event, by stopping token minting.
function finalize() external onlyAfterSale onlyOwner {
if (!kin.isMinting()) {
revert();
}
require(lastGrantedIndex == tokenGrantees.length);
// Finish minting.
kin.endMinting();
}
/// @dev Grants pre-configured token grants in batches. When the method is called, it'll resume from the last grant,
/// from its previous run, and will finish either after granting GRANT_BATCH_SIZE grants or finishing the whole list
/// of grants.
function grantTokens() external onlyAfterSale onlyOwner {
uint endIndex = SafeMath.min256(tokenGrantees.length, lastGrantedIndex + GRANT_BATCH_SIZE);
for (uint i = lastGrantedIndex; i < endIndex; i++) {
address grantee = tokenGrantees[i];
// Calculate how many tokens have been granted, vested, and issued such that: granted = vested + issued.
TokenGrant memory tokenGrant = tokenGrants[grantee];
uint256 tokensGranted = tokenGrant.value.mul(tokensSold).div(MAX_TOKENS_SOLD);
uint256 tokensVesting = tokensGranted.mul(tokenGrant.percentVested).div(100);
uint256 tokensIssued = tokensGranted.sub(tokensVesting);
// Transfer issued tokens that have yet to be transferred to grantee.
if (tokensIssued > 0) {
issueTokens(grantee, tokensIssued);
}
// Transfer vested tokens that have yet to be transferred to vesting trustee, and initialize grant.
if (tokensVesting > 0) {
issueTokens(trustee, tokensVesting);
trustee.grant(grantee, tokensVesting, now.add(tokenGrant.startOffset), now.add(tokenGrant.cliffOffset),
now.add(tokenGrant.endOffset), tokenGrant.installmentLength, true);
}
lastGrantedIndex++;
}
}
/// @dev Issues tokens for the recipient.
/// @param _recipient address The address of the recipient.
/// @param _tokens uint256 The amount of tokens to issue.
function issueTokens(address _recipient, uint256 _tokens) private {
// Request Kin token contract to mint the requested tokens for the buyer.
kin.mint(_recipient, _tokens);
TokensIssued(_recipient, _tokens);
}
/// @dev Returns whether the sale has ended.
/// @return bool Whether the sale has ended or not.
function saleEnded() private constant returns (bool) {
return tokensSold >= MAX_TOKENS_SOLD || now >= endTime;
}
/// @dev Requests to transfer control of the Kin token contract to a new owner.
/// @param _newOwnerCandidate address The address to transfer ownership to.
///
/// NOTE:
/// 1. The new owner will need to call Kin token contract's acceptOwnership directly in order to accept the ownership.
/// 2. Calling this method during the token sale will prevent the token sale to continue, since only the owner of
/// the Kin token contract can issue new tokens.
function requestKinTokenOwnershipTransfer(address _newOwnerCandidate) external onlyOwner {
kin.requestOwnershipTransfer(_newOwnerCandidate);
}
/// @dev Accepts new ownership on behalf of the Kin token contract.
// This can be used by the sale contract itself to claim back ownership of the Kin token contract.
function acceptKinTokenOwnership() external onlyOwner {
kin.acceptOwnership();
}
/// @dev Requests to transfer control of the VestingTrustee contract to a new owner.
/// @param _newOwnerCandidate address The address to transfer ownership to.
///
/// NOTE:
/// 1. The new owner will need to call VestingTrustee's acceptOwnership directly in order to accept the ownership.
/// 2. Calling this method during the token sale will prevent the token sale from finalizaing, since only the owner
/// of the VestingTrustee contract can issue new token grants.
function requestVestingTrusteeOwnershipTransfer(address _newOwnerCandidate) external onlyOwner {
trustee.requestOwnershipTransfer(_newOwnerCandidate);
}
/// @dev Accepts new ownership on behalf of the VestingTrustee contract.
/// This can be used by the token sale contract itself to claim back ownership of the VestingTrustee contract.
function acceptVestingTrusteeOwnership() external onlyOwner {
trustee.acceptOwnership();
}
}