Melonport ICO is over after 13 minutes and 17 seconds as the funding goal of 227,000 ETH was reached.
Note that MLN tokens are ERC20-compliant but cannot be transferred before endTime = 1489575600 or Mar 15 2017 @ 11:00am (UTC), and will then be listed on the decentralised exchange contract market https://cryptoderivatives.market/.
The first crowdfunding transaction is 0x483d9e2f… at Feb-15-2017 11:00:06 AM +UTC.
The last successful non-zero crowdfunding transaction is 0xec2b4ab5… at Feb-15-2017 11:13:23 AM +UTC.
Last transaction >= 100 ETH 0x86c1859d… at Feb-15-2017 11:05:21 AM +UTC, or 5 minutes 15 seconds.
The crowdsale was over in 13 minutes and 17 seconds. And some transactions were lagging by 2 hours and 37 minutes. See the following screen.
The smart contract from 0x3bf541f87056d134e0109be1be92978b26cb09e0 follows:
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 |
pragma solidity ^0.4.8; /// @title Assertive contract /// @author Melonport AG <team@melonport.com> /// @notice Asserts function contract Assertive { function assert(bool assertion) internal { if (!assertion) throw; } } /// @title Overflow aware uint math functions. /// @author Melonport AG <team@melonport.com> /// @notice Inspired by https://github.com/MakerDAO/maker-otc/blob/master/contracts/simple_market.sol contract SafeMath is Assertive{ function safeMul(uint a, uint b) internal returns (uint) { uint c = a * b; assert(a == 0 || c / a == b); return c; } function safeSub(uint a, uint b) internal returns (uint) { assert(b <= a); return a - b; } function safeAdd(uint a, uint b) internal returns (uint) { uint c = a + b; assert(c>=a && c>=b); return c; } } /// @title ERC20 Token Protocol /// @author Melonport AG <team@melonport.com> /// @notice See https://github.com/ethereum/EIPs/issues/20 contract ERC20Protocol { function totalSupply() constant returns (uint256 totalSupply) {} function balanceOf(address _owner) constant returns (uint256 balance) {} function transfer(address _to, uint256 _value) returns (bool success) {} function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {} function approve(address _spender, uint256 _value) returns (bool success) {} function allowance(address _owner, address _spender) constant returns (uint256 remaining) {} event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); } /// @title ERC20 Token /// @author Melonport AG <team@melonport.com> /// @notice Original taken from https://github.com/ethereum/EIPs/issues/20 /// @notice Checked against integer overflow contract ERC20 is ERC20Protocol { function transfer(address _to, uint256 _value) returns (bool success) { if (balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]) { balances[msg.sender] -= _value; balances[_to] += _value; Transfer(msg.sender, _to, _value); return true; } else { return false; } } function transferFrom(address _from, address _to, uint256 _value) returns (bool success) { if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) { balances[_to] += _value; balances[_from] -= _value; allowed[_from][msg.sender] -= _value; Transfer(_from, _to, _value); return true; } else { return false; } } function balanceOf(address _owner) constant returns (uint256 balance) { return balances[_owner]; } function approve(address _spender, uint256 _value) returns (bool success) { allowed[msg.sender][_spender] = _value; Approval(msg.sender, _spender, _value); return true; } function allowance(address _owner, address _spender) constant returns (uint256 remaining) { return allowed[_owner][_spender]; } mapping (address => uint256) balances; mapping (address => mapping (address => uint256)) allowed; uint256 public totalSupply; } /// @title Melon Token Contract /// @author Melonport AG <team@melonport.com> contract MelonToken is ERC20, SafeMath { // FIELDS // Constant token specific fields string public constant name = "Melon Token"; string public constant symbol = "MLN"; uint public constant decimals = 18; uint public constant THAWING_DURATION = 2 years; // Time needed for iced tokens to thaw into liquid tokens uint public constant MAX_TOTAL_TOKEN_AMOUNT_OFFERED_TO_PUBLIC = 1000000 * 10 ** decimals; // Max amount of tokens offered to the public uint public constant MAX_TOTAL_TOKEN_AMOUNT = 1250000 * 10 ** decimals; // Max amount of total tokens raised during all contributions (includes stakes of patrons) // Fields that are only changed in constructor address public minter; // Contribution contract(s) address public melonport; // Can change to other minting contribution contracts but only until total amount of token minted uint public startTime; // Contribution start time in seconds uint public endTime; // Contribution end time in seconds // Fields that can be changed by functions mapping (address => uint) lockedBalances; // MODIFIERS modifier only_minter { assert(msg.sender == minter); _; } modifier only_melonport { assert(msg.sender == melonport); _; } modifier is_later_than(uint x) { assert(now > x); _; } modifier max_total_token_amount_not_reached(uint amount) { assert(safeAdd(totalSupply, amount) <= MAX_TOTAL_TOKEN_AMOUNT); _; } // CONSTANT METHODS function lockedBalanceOf(address _owner) constant returns (uint balance) { return lockedBalances[_owner]; } // METHODS /// Pre: All fields, except { minter, melonport, startTime, endTime } are valid /// Post: All fields, including { minter, melonport, startTime, endTime } are valid function MelonToken(address setMinter, address setMelonport, uint setStartTime, uint setEndTime) { minter = setMinter; melonport = setMelonport; startTime = setStartTime; endTime = setEndTime; } /// Pre: Address of contribution contract (minter) is set /// Post: Mints token into tradeable tranche function mintLiquidToken(address recipient, uint amount) external only_minter max_total_token_amount_not_reached(amount) { balances[recipient] = safeAdd(balances[recipient], amount); totalSupply = safeAdd(totalSupply, amount); } /// Pre: Address of contribution contract (minter) is set /// Post: Mints Token into iced tranche. Become liquid after completion of the melonproject or two years. function mintIcedToken(address recipient, uint amount) external only_minter max_total_token_amount_not_reached(amount) { lockedBalances[recipient] = safeAdd(lockedBalances[recipient], amount); totalSupply = safeAdd(totalSupply, amount); } /// Pre: Thawing period has passed - iced funds have turned into liquid ones /// Post: All funds available for trade function unlockBalance(address recipient) is_later_than(endTime + THAWING_DURATION) { balances[recipient] = safeAdd(balances[recipient], lockedBalances[recipient]); lockedBalances[recipient] = 0; } /// Pre: Prevent transfers until contribution period is over. /// Post: Transfer MLN from msg.sender /// Note: ERC20 interface function transfer(address recipient, uint amount) is_later_than(endTime) returns (bool success) { return super.transfer(recipient, amount); } /// Pre: Prevent transfers until contribution period is over. /// Post: Transfer MLN from arbitrary address /// Note: ERC20 interface function transferFrom(address sender, address recipient, uint amount) is_later_than(endTime) returns (bool success) { return super.transferFrom(sender, recipient, amount); } /// Pre: Melonport address is set. Restricted to melonport. /// Post: New minter can now create tokens up to MAX_TOTAL_TOKEN_AMOUNT. /// Note: This allows additional contribution periods at a later stage, while still using the same ERC20 compliant contract. function changeMintingAddress(address newAddress) only_melonport { minter = newAddress; } /// Pre: Melonport address is set. Restricted to melonport. /// Post: New address set. This address controls the setting of the minter address function changeMelonportAddress(address newAddress) only_melonport { melonport = newAddress; } } /// @title Contribution Contract /// @author Melonport AG <team@melonport.com> /// @notice This follows Condition-Orientated Programming as outlined here: /// @notice https://medium.com/@gavofyork/condition-orientated-programming-969f6ba0161a#.saav3bvva contract Contribution is SafeMath { // FIELDS // Constant fields uint public constant ETHER_CAP = 227000 ether; // Max amount raised during first contribution; targeted amount CHF 2.5MN uint public constant MAX_CONTRIBUTION_DURATION = 4 weeks; // Max amount in seconds of contribution period uint public constant BTCS_ETHER_CAP = ETHER_CAP * 25 / 100; // Max melon token allocation for btcs before contribution period starts // Price Rates uint public constant PRICE_RATE_FIRST = 2200; // Four price tiers, each valid for two weeks uint public constant PRICE_RATE_SECOND = 2150; uint public constant PRICE_RATE_THIRD = 2100; uint public constant PRICE_RATE_FOURTH = 2050; uint public constant DIVISOR_PRICE = 1000; // Price rates are divided by this number // Addresses of Patrons address public constant FOUNDER_ONE = 0x009beAE06B0c0C536ad1eA43D6f61DCCf0748B1f; address public constant FOUNDER_TWO = 0xB1EFca62C555b49E67363B48aE5b8Af3C7E3e656; address public constant EXT_COMPANY_ONE = 0x00779e0e4c6083cfd26dE77B4dbc107A7EbB99d2; address public constant EXT_COMPANY_TWO = 0x1F06B976136e94704D328D4d23aae7259AaC12a2; address public constant EXT_COMPANY_THREE = 0xDD91615Ea8De94bC48231c4ae9488891F1648dc5; address public constant ADVISOR_ONE = 0x0001126FC94AE0be2B685b8dE434a99B2552AAc3; address public constant ADVISOR_TWO = 0x4f2AF8d2614190Cc80c6E9772B0C367db8D9753C; address public constant ADVISOR_THREE = 0x715a70a7c7d76acc8d5874862e381c1940c19cce; address public constant ADVISOR_FOUR = 0x8615F13C12c24DFdca0ba32511E2861BE02b93b2; address public constant AMBASSADOR_ONE = 0xd3841FB80CE408ca7d0b41D72aA91CA74652AF47; address public constant AMBASSADOR_TWO = 0xDb775577538018a689E4Ad2e8eb5a7Ae7c34722B; address public constant AMBASSADOR_THREE = 0xaa967e0ce6A1Ff5F9c124D15AD0412F137C99767; address public constant AMBASSADOR_FOUR = 0x910B41a6568a645437bC286A5C733f3c501d8c88; address public constant AMBASSADOR_FIVE = 0xb1d16BFE840E66E3c81785551832aAACB4cf69f3; address public constant AMBASSADOR_SIX = 0x5F6ff16364BfEf546270325695B6e90cc89C497a; address public constant AMBASSADOR_SEVEN = 0x58656e8872B0d266c2acCD276cD23F4C0B5fEfb9; address public constant SPECIALIST_ONE = 0x8a815e818E617d1f93BE7477D179258aC2d25310; address public constant SPECIALIST_TWO = 0x1eba6702ba21cfc1f6c87c726364b60a5e444901; address public constant SPECIALIST_THREE = 0x82eae6c30ed9606e2b389ae65395648748c6a17f; // Stakes of Patrons uint public constant MELONPORT_COMPANY_STAKE = 1000; // 10% of all created melon token allocated to melonport company uint public constant FOUNDER_STAKE = 445; // 4.45% of all created melon token allocated to founder uint public constant EXT_COMPANY_STAKE_ONE = 150; // 1.5% of all created melon token allocated to external company uint public constant EXT_COMPANY_STAKE_TWO = 100; // 1% of all created melon token allocated to external company uint public constant EXT_COMPANY_STAKE_THREE = 50; // 0.5% of all created melon token allocated to external company uint public constant ADVISOR_STAKE_ONE = 150; // 1.5% of all created melon token allocated to advisor uint public constant ADVISOR_STAKE_TWO = 50; // 0.5% of all created melon token allocated to advisor uint public constant ADVISOR_STAKE_THREE = 25; // 0.25% of all created melon token allocated to advisor uint public constant ADVISOR_STAKE_FOUR = 10; // 0.1% of all created melon token allocated to advisor uint public constant AMBASSADOR_STAKE = 5; // 0.05% of all created melon token allocated to ambassadors uint public constant SPECIALIST_STAKE_ONE = 25; // 0.25% of all created melon token allocated to specialist uint public constant SPECIALIST_STAKE_TWO = 10; // 0.1% of all created melon token allocated to specialist uint public constant SPECIALIST_STAKE_THREE = 5; // 0.05% of all created melon token allocated to specialist uint public constant DIVISOR_STAKE = 10000; // Stakes are divided by this number; Results to one basis point // Fields that are only changed in constructor address public melonport; // All deposited ETH will be instantly forwarded to this address. address public btcs; // Bitcoin Suisse address for their allocation option address public signer; // Signer address as on https://contribution.melonport.com uint public startTime; // Contribution start time in seconds uint public endTime; // Contribution end time in seconds MelonToken public melonToken; // Contract of the ERC20 compliant melon token // Fields that can be changed by functions uint public etherRaised; // This will keep track of the Ether raised during the contribution bool public halted; // The melonport address can set this to true to halt the contribution due to an emergency // EVENTS event TokensBought(address indexed sender, uint eth, uint amount); // MODIFIERS modifier is_signer_signature(uint8 v, bytes32 r, bytes32 s) { bytes32 hash = sha256(msg.sender); assert(ecrecover(hash, v, r, s) == signer); _; } modifier only_melonport { assert(msg.sender == melonport); _; } modifier only_btcs { assert(msg.sender == btcs); _; } modifier is_not_halted { assert(!halted); _; } modifier ether_cap_not_reached { assert(safeAdd(etherRaised, msg.value) <= ETHER_CAP); _; } modifier btcs_ether_cap_not_reached { assert(safeAdd(etherRaised, msg.value) <= BTCS_ETHER_CAP); _; } modifier is_not_earlier_than(uint x) { assert(now >= x); _; } modifier is_earlier_than(uint x) { assert(now < x); _; } // CONSTANT METHODS /// Pre: startTime, endTime specified in constructor, /// Post: Price rate at given blockTime; One ether equals priceRate() / DIVISOR_PRICE of melon tokens function priceRate() constant returns (uint) { // Four price tiers if (startTime <= now && now < startTime + 1 weeks) return PRICE_RATE_FIRST; if (startTime + 1 weeks <= now && now < startTime + 2 weeks) return PRICE_RATE_SECOND; if (startTime + 2 weeks <= now && now < startTime + 3 weeks) return PRICE_RATE_THIRD; if (startTime + 3 weeks <= now && now < endTime) return PRICE_RATE_FOURTH; // Should not be called before or after contribution period assert(false); } // NON-CONSTANT METHODS /// Pre: All fields, except { melonport, btcs, signer, startTime } are valid /// Post: All fields, including { melonport, btcs, signer, startTime } are valid function Contribution(address setMelonport, address setBTCS, address setSigner, uint setStartTime) { melonport = setMelonport; btcs = setBTCS; signer = setSigner; startTime = setStartTime; endTime = startTime + MAX_CONTRIBUTION_DURATION; melonToken = new MelonToken(this, melonport, startTime, endTime); // Create Melon Token Contract var maxTotalTokenAmountOfferedToPublic = melonToken.MAX_TOTAL_TOKEN_AMOUNT_OFFERED_TO_PUBLIC(); uint stakeMultiplier = maxTotalTokenAmountOfferedToPublic / DIVISOR_STAKE; // Mint liquid tokens for melonport company, liquid means tradeale melonToken.mintLiquidToken(melonport, MELONPORT_COMPANY_STAKE * stakeMultiplier); // Mint iced tokens that are unable to trade for two years and allocate according to relevant stakes melonToken.mintIcedToken(FOUNDER_ONE, FOUNDER_STAKE * stakeMultiplier); melonToken.mintIcedToken(FOUNDER_TWO, FOUNDER_STAKE * stakeMultiplier); melonToken.mintIcedToken(EXT_COMPANY_ONE, EXT_COMPANY_STAKE_ONE * stakeMultiplier); melonToken.mintIcedToken(EXT_COMPANY_TWO, EXT_COMPANY_STAKE_TWO * stakeMultiplier); melonToken.mintIcedToken(EXT_COMPANY_THREE, EXT_COMPANY_STAKE_THREE * stakeMultiplier); melonToken.mintIcedToken(ADVISOR_ONE, ADVISOR_STAKE_ONE * stakeMultiplier); melonToken.mintIcedToken(ADVISOR_TWO, ADVISOR_STAKE_TWO * stakeMultiplier); melonToken.mintIcedToken(ADVISOR_THREE, ADVISOR_STAKE_THREE * stakeMultiplier); melonToken.mintIcedToken(ADVISOR_FOUR, ADVISOR_STAKE_FOUR * stakeMultiplier); melonToken.mintIcedToken(AMBASSADOR_ONE, AMBASSADOR_STAKE * stakeMultiplier); melonToken.mintIcedToken(AMBASSADOR_TWO, AMBASSADOR_STAKE * stakeMultiplier); melonToken.mintIcedToken(AMBASSADOR_THREE, AMBASSADOR_STAKE * stakeMultiplier); melonToken.mintIcedToken(AMBASSADOR_FOUR, AMBASSADOR_STAKE * stakeMultiplier); melonToken.mintIcedToken(AMBASSADOR_FIVE, AMBASSADOR_STAKE * stakeMultiplier); melonToken.mintIcedToken(AMBASSADOR_SIX, AMBASSADOR_STAKE * stakeMultiplier); melonToken.mintIcedToken(AMBASSADOR_SEVEN, AMBASSADOR_STAKE * stakeMultiplier); melonToken.mintIcedToken(SPECIALIST_ONE, SPECIALIST_STAKE_ONE * stakeMultiplier); melonToken.mintIcedToken(SPECIALIST_TWO, SPECIALIST_STAKE_TWO * stakeMultiplier); melonToken.mintIcedToken(SPECIALIST_THREE, SPECIALIST_STAKE_THREE * stakeMultiplier); } /// Pre: Valid signature received from https://contribution.melonport.com /// Post: Bought melon tokens according to priceRate() and msg.value function buy(uint8 v, bytes32 r, bytes32 s) payable { buyRecipient(msg.sender, v, r, s); } /// Pre: Valid signature received from https://contribution.melonport.com /// Post: Bought melon tokens according to priceRate() and msg.value on behalf of recipient function buyRecipient(address recipient, uint8 v, bytes32 r, bytes32 s) payable is_signer_signature(v, r, s) is_not_earlier_than(startTime) is_earlier_than(endTime) is_not_halted ether_cap_not_reached { uint amount = safeMul(msg.value, priceRate()) / DIVISOR_PRICE; melonToken.mintLiquidToken(recipient, amount); etherRaised = safeAdd(etherRaised, msg.value); assert(melonport.send(msg.value)); TokensBought(recipient, msg.value, amount); } /// Pre: BTCS before contribution period, BTCS has exclusive right to buy up to 25% of all melon tokens /// Post: Bought melon tokens according to PRICE_RATE_FIRST and msg.value on behalf of recipient function btcsBuyRecipient(address recipient) payable only_btcs is_earlier_than(startTime) is_not_halted btcs_ether_cap_not_reached { uint amount = safeMul(msg.value, PRICE_RATE_FIRST) / DIVISOR_PRICE; melonToken.mintLiquidToken(recipient, amount); etherRaised = safeAdd(etherRaised, msg.value); assert(melonport.send(msg.value)); TokensBought(recipient, msg.value, amount); } /// Pre: Emergency situation that requires contribution period to stop. /// Post: Contributing not possible anymore. function halt() only_melonport { halted = true; } /// Pre: Emergency situation resolved. /// Post: Contributing becomes possible again withing the outlined restrictions. function unhalt() only_melonport { halted = false; } /// Pre: Restricted to melonport. /// Post: New address set. To halt contribution and/or change minter in MelonToken contract. function changeMelonportAddress(address newAddress) only_melonport { melonport = newAddress; } } |