-
Notifications
You must be signed in to change notification settings - Fork 0
/
SaleContract.sol
227 lines (196 loc) · 6.33 KB
/
SaleContract.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
pragma solidity 0.4.24;
import './Token.sol';
contract SaleContract{
using SafeMath for uint256;
uint256 constant internal TOKEN_DECIMALS = 10**5;
uint256 constant internal TOKEN_SUPPLY = 1000000000*TOKEN_DECIMALS; //1,000,000,000.00000, 1 billion 5 decimals
uint256 constant internal MIN_CONTRIBUTION = 0.01 ether; //$5 min
uint256 constant internal ETH_DECIMALS = 10**18;
uint16 constant internal TIERS = 10;
uint256 public totalTokensSold;
uint256 public weiEarned;
address public holdings;
address private owner;
uint16 private tier;
bool private paused;
bool private activeMemebershipSale;
//Token Smart Contract
Token public tokenAddress;
struct Participant{
uint256 tokensTransferable;
uint256 remainingWei;
}
mapping(address => Participant) public participants;
struct SaleTier {
uint256 tokensToBeSold; //amount of tokens to be sold in this SaleTier
uint256 tokensSold; //amount of tokens sold in each SaleTier
uint256 price; //how many wei per token
}
mapping(uint16 => SaleTier) public saleTier;
event LogTokensPurchased(address indexed buyer, uint256 indexed qtyOfTokens);
event LogOwnerWithdrawal(address ownerAddress, uint256 amountWithdrawn);
event LogRefundWei(address tokenBuyer, uint256 amount);
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
modifier isValidPayload() {
require(msg.data.length == 0 || msg.data.length == 4);
_;
}
modifier saleIsActive() {
require(activeMemebershipSale && totalTokensSold < TOKEN_SUPPLY);
_;
}
modifier saleHasEnded() {
require(totalTokensSold >= TOKEN_SUPPLY);
_;
}
modifier activeContract(){
require(paused == false);
_;
}
// @dev confirm price thresholds and amounts
// @param _holdings wallet address for holding ether
// @param _token address of the token contract
constructor(address _holdings, address _token)
public
{
require(_holdings != address(0));
require(_token != address(0));
holdings = _holdings;
paused = true;
tokenAddress = Token(_token);
owner = msg.sender;
for(uint16 i=0; i<TIERS; i++){
saleTier[i].tokensToBeSold = 100000000*TOKEN_DECIMALS;
saleTier[i].price = 20000000000000+(20000000000000*i);//how many wei to get one token
}// 20000000000000
}
/// @dev Fallback function.
/// @notice buyers send ETH to the saleContract address
function()
public
payable
{
if(msg.sender != owner){
buyTokens();
}
}
// @notice keeping owner private for the most part using a getter to see owner address
function getOwner()
view
public
returns(address _owner)
{
return owner;
}
// @dev owner needs to approve in token the transfer amount that the salecontract can transfer
// @notice token only able to be traded by saleContract
function startMembershipSale()
external
onlyOwner
{
tokenAddress.transferFrom(owner, address(this), 1000000000*TOKEN_DECIMALS);
activeMemebershipSale = true;
paused = false;
}
/// @notice called by fallback function
function buyTokens()
internal
saleIsActive
activeContract
isValidPayload
returns (bool success)
{
Participant storage participant = participants[msg.sender];
SaleTier storage currentPrice = saleTier[tier];
uint256 weiAmount = participant.remainingWei;
participant.remainingWei = 0;
uint256 remainingWei = msg.value.add(weiAmount);
require(remainingWei >= MIN_CONTRIBUTION);
uint256 price = currentPrice.price;
uint256 totalTokensRequested;
uint256 tierRemainingTokens;
uint256 tknsRequested;
while(remainingWei >= price && tier != TIERS) {
SaleTier storage currentTier = saleTier[tier];
price = currentTier.price;
tknsRequested = remainingWei.div(price).mul(TOKEN_DECIMALS);
tierRemainingTokens = currentTier.tokensToBeSold.sub(currentTier.tokensSold);
if(tknsRequested >= tierRemainingTokens){
tknsRequested -= tierRemainingTokens;
currentTier.tokensSold += tierRemainingTokens;
totalTokensRequested += tierRemainingTokens;
remainingWei -= (tierRemainingTokens.mul(price).div(TOKEN_DECIMALS));
tier++;
} else{
totalTokensRequested += tknsRequested;
currentTier.tokensSold += tknsRequested;
remainingWei -= (tknsRequested.mul(price).div(TOKEN_DECIMALS));
}
}
uint256 amount = msg.value.sub(remainingWei);
weiEarned += amount;
totalTokensSold += totalTokensRequested;
if(totalTokensSold == TOKEN_SUPPLY){activeMemebershipSale = false;}
participant.remainingWei += remainingWei;
emit LogTokensPurchased(msg.sender, totalTokensRequested);
tokenAddress.transfer(msg.sender, totalTokensRequested);
return true;
}
/// @notice to pause specific functions of the contract
function pauseContract()
public
onlyOwner
{
paused = true;
}
/// @notice used to unpause contract
function unpauseContract()
public
onlyOwner
{
paused = false;
}
// @notice owner withdraws ether periodically from the membership sale contract to holdings wallet
function ownerWithdrawal(uint256 _amount)
public
onlyOwner
returns(bool success)
{
emit LogOwnerWithdrawal(msg.sender, _amount);
holdings.transfer(_amount);
return true;
}
function contractBalance()
view
external
onlyOwner
returns (uint256)
{
return(address(this).balance);
}
// @notice no ethereum will be held in the membershipsale contract
// when refunds become available the amount of Ethererum needed will
// be manually transfered back to the membership sale to be refunded
// @notice only the last person that buys tokens if they deposited enought to buy more
// tokens than what is available will be able to use this function
function claimRemainingWei()
external
activeContract
saleHasEnded
returns (bool success)
{
Participant storage participant = participants[msg.sender];
require(participant.remainingWei != 0);
uint256 amount = participant.remainingWei;
participant.remainingWei = 0;
emit LogRefundWei(msg.sender, amount);
msg.sender.transfer(amount);
return true;
}
}