Contract Name:
WolkExchange
Contract Source Code:
File 1 of 1 : WolkExchange
pragma solidity ^0.4.16;
// SafeMath Taken From FirstBlood
contract SafeMath {
function safeMul(uint a, uint b) internal returns (uint) {
uint c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeDiv(uint a, uint b) internal returns (uint) {
assert(b > 0);
uint c = a / b;
assert(a == b * 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;
}
}
// Ownership
contract Owned {
address public owner;
address public newOwner;
modifier onlyOwner { assert(msg.sender == owner); _; }
event OwnerUpdate(address _prevOwner, address _newOwner);
function Owned() {
owner = msg.sender;
}
function transferOwnership(address _newOwner) public onlyOwner {
require(_newOwner != owner);
newOwner = _newOwner;
}
function acceptOwnership() public {
require(msg.sender == newOwner);
OwnerUpdate(owner, newOwner);
owner = newOwner;
newOwner = 0x0;
}
}
// ERC20 Interface
contract ERC20 {
function totalSupply() constant returns (uint _totalSupply);
function balanceOf(address _owner) constant returns (uint balance);
function transfer(address _to, uint _value) returns (bool success);
function transferFrom(address _from, address _to, uint _value) returns (bool success);
function approve(address _spender, uint _value) returns (bool success);
function allowance(address _owner, address _spender) constant returns (uint remaining);
event Transfer(address indexed _from, address indexed _to, uint _value);
event Approval(address indexed _owner, address indexed _spender, uint _value);
}
// ERC20Token
contract ERC20Token is ERC20, SafeMath {
mapping(address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
uint256 public totalTokens;
function transfer(address _to, uint256 _value) returns (bool success) {
if (balances[msg.sender] >= _value && _value > 0) {
balances[msg.sender] = safeSub(balances[msg.sender], _value);
balances[_to] = safeAdd(balances[_to], _value);
Transfer(msg.sender, _to, _value);
return true;
} else {
return false;
}
}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
var _allowance = allowed[_from][msg.sender];
if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
balances[_to] = safeAdd(balances[_to], _value);
balances[_from] = safeSub(balances[_from], _value);
allowed[_from][msg.sender] = safeSub(_allowance, _value);
Transfer(_from, _to, _value);
return true;
} else {
return false;
}
}
function totalSupply() constant returns (uint256) {
return totalTokens;
}
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
function approve(address _spender, uint256 _value) returns (bool success) {
require((_value == 0) || (allowed[msg.sender][_spender] == 0));
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];
}
}
contract Wolk is ERC20Token, Owned {
// TOKEN INFO
string public constant name = "Wolk Protocol Token";
string public constant symbol = "WOLK";
uint256 public constant decimals = 18;
// RESERVE
uint256 public reserveBalance = 0;
uint8 public constant percentageETHReserve = 15;
// CONTRACT OWNER
address public multisigWallet;
// WOLK SETTLERS
mapping (address => bool) settlers;
modifier onlySettler { assert(settlers[msg.sender] == true); _; }
// TOKEN GENERATION CONTROL
address public wolkSale;
bool public allSaleCompleted = false;
bool public openSaleCompleted = false;
modifier isTransferable { require(allSaleCompleted); _; }
modifier onlyWolk { assert(msg.sender == wolkSale); _; }
// TOKEN GENERATION EVENTLOG
event WolkCreated(address indexed _to, uint256 _tokenCreated);
event WolkDestroyed(address indexed _from, uint256 _tokenDestroyed);
event LogRefund(address indexed _to, uint256 _value);
}
contract WolkTGE is Wolk {
// TOKEN GENERATION EVENT
mapping (address => uint256) contribution;
mapping (address => uint256) presaleLimit;
mapping (address => bool) presaleContributor;
uint256 public constant tokenGenerationMin = 50 * 10**6 * 10**decimals;
uint256 public constant tokenGenerationMax = 150 * 10**6 * 10**decimals;
uint256 public presale_start_block;
uint256 public start_block;
uint256 public end_block;
// @param _presaleStartBlock
// @param _startBlock
// @param _endBlock
// @param _wolkWallet
// @param _wolkSale
// @return success
// @dev Wolk Genesis Event [only accessible by Contract Owner]
function wolkGenesis(uint256 _presaleStartBlock, uint256 _startBlock, uint256 _endBlock, address _wolkWallet, address _wolkSale) onlyOwner returns (bool success){
require((totalTokens < 1) && (block.number <= _startBlock) && (_endBlock > _startBlock) && (_startBlock > _presaleStartBlock));
presale_start_block = _presaleStartBlock;
start_block = _startBlock;
end_block = _endBlock;
multisigWallet = _wolkWallet;
wolkSale = _wolkSale;
settlers[msg.sender] = true;
return true;
}
// @param _presaleParticipants
// @return success
// @dev Adds addresses that are allowed to take part in presale [only accessible by current Contract Owner]
function addParticipant(address[] _presaleParticipants, uint256[] _contributionLimits) onlyOwner returns (bool success) {
require(_presaleParticipants.length == _contributionLimits.length);
for (uint cnt = 0; cnt < _presaleParticipants.length; cnt++){
presaleContributor[_presaleParticipants[cnt]] = true;
presaleLimit[_presaleParticipants[cnt]] = safeMul(_contributionLimits[cnt], 10**decimals);
}
return true;
}
// @param _presaleParticipants
// @return success
// @dev Revoke designated presale contributors [only accessible by current Contract Owner]
function removeParticipant(address[] _presaleParticipants) onlyOwner returns (bool success){
for (uint cnt = 0; cnt < _presaleParticipants.length; cnt++){
presaleContributor[_presaleParticipants[cnt]] = false;
presaleLimit[_presaleParticipants[cnt]] = 0;
}
return true;
}
// @param _participant
// @return remainingAllocation
// @dev return PresaleLimit allocated to given address
function participantBalance(address _participant) constant returns (uint256 remainingAllocation) {
return presaleLimit[_participant];
}
// @param _participant
// @dev use tokenGenerationEvent to handle Pre-sale and Open-sale
function tokenGenerationEvent(address _participant) payable external {
require( presaleContributor[_participant] && !openSaleCompleted && !allSaleCompleted && (block.number <= end_block) && msg.value > 0);
/* Early Participation Discount (rounded to the nearest integer)
---------------------------------
| Token Issued | Rate | Discount|
---------------------------------
| 0 - 50MM | 1177 | 15.0% |
| 50MM - 60MM | 1143 | 12.5% |
| 60MM - 70MM | 1111 | 10.0% |
| 70MM - 80MM | 1081 | 7.5% |
| 80MM - 90MM | 1053 | 5.0% |
| 90MM - 100MM | 1026 | 2.5% |
| 100MM+ | 1000 | 0.0% |
---------------------------------
*/
uint256 rate = 1000; // Default Rate
if ( totalTokens < (50 * 10**6 * 10**decimals) ) {
rate = 1177;
} else if ( totalTokens < (60 * 10**6 * 10**decimals) ) {
rate = 1143;
} else if ( totalTokens < (70 * 10**6 * 10**decimals) ) {
rate = 1111;
} else if ( totalTokens < (80 * 10**6 * 10**decimals) ) {
rate = 1081;
} else if ( totalTokens < (90 * 10**6 * 10**decimals) ) {
rate = 1053;
} else if ( totalTokens < (100 * 10**6 * 10**decimals) ) {
rate = 1026;
}else{
rate = 1000;
}
if ((block.number < start_block) && (block.number >= presale_start_block)) {
require(presaleLimit[_participant] >= msg.value);
presaleLimit[_participant] = safeSub(presaleLimit[_participant], msg.value);
} else {
require(block.number >= start_block) ;
}
uint256 tokens = safeMul(msg.value, rate);
uint256 checkedSupply = safeAdd(totalTokens, tokens);
require(checkedSupply <= tokenGenerationMax);
totalTokens = checkedSupply;
Transfer(address(this), _participant, tokens);
balances[_participant] = safeAdd(balances[_participant], tokens);
contribution[_participant] = safeAdd(contribution[_participant], msg.value);
WolkCreated(_participant, tokens); // logs token creation
}
// @dev If Token Generation Minimum is Not Met, TGE Participants can call this func and request for refund
function refund() external {
require((contribution[msg.sender] > 0) && (!allSaleCompleted) && (totalTokens < tokenGenerationMin) && (block.number > end_block));
uint256 tokenBalance = balances[msg.sender];
uint256 refundBalance = contribution[msg.sender];
balances[msg.sender] = 0;
contribution[msg.sender] = 0;
totalTokens = safeSub(totalTokens, tokenBalance);
WolkDestroyed(msg.sender, tokenBalance);
LogRefund(msg.sender, refundBalance);
msg.sender.transfer(refundBalance);
}
// @dev Finalizing the Open-Sale for Token Generation Event. 15% of Eth will be kept in contract to provide liquidity
function finalizeOpenSale() onlyOwner {
require((!openSaleCompleted) && (totalTokens >= tokenGenerationMin));
openSaleCompleted = true;
end_block = block.number;
reserveBalance = safeDiv(safeMul(totalTokens, percentageETHReserve), 100000);
var withdrawalBalance = safeSub(this.balance, reserveBalance);
msg.sender.transfer(withdrawalBalance);
}
// @dev Finalizing the Private-Sale. Entire Eth will be kept in contract to provide liquidity. This func will conclude the entire sale.
function finalize() onlyWolk payable external {
require((openSaleCompleted) && (!allSaleCompleted));
uint256 privateSaleTokens = safeDiv(safeMul(msg.value, 100000), percentageETHReserve);
uint256 checkedSupply = safeAdd(totalTokens, privateSaleTokens);
totalTokens = checkedSupply;
reserveBalance = safeAdd(reserveBalance, msg.value);
Transfer(address(this), wolkSale, privateSaleTokens);
balances[wolkSale] = safeAdd(balances[wolkSale], privateSaleTokens);
WolkCreated(wolkSale, privateSaleTokens); // logs token creation for Presale events
allSaleCompleted = true;
}
}
contract IBurnFormula {
function calculateWolkToBurn(uint256 _value) public constant returns (uint256);
}
contract IFeeFormula {
function calculateProviderFee(uint256 _value) public constant returns (uint256);
}
contract WolkProtocol is Wolk {
// WOLK NETWORK PROTOCOL
address public burnFormula;
bool public settlementIsRunning = true;
uint256 public burnBasisPoints = 500; // Burn rate (in BP) when Service Provider withdraws from data buyers' accounts
mapping (address => mapping (address => bool)) authorized; // holds which accounts have approved which Service Providers
mapping (address => uint256) feeBasisPoints; // Fee (in BP) earned by Service Provider when depositing to data seller
mapping (address => address) feeFormulas; // Provider's customizable Fee mormula
modifier isSettleable { require(settlementIsRunning); _; }
// WOLK PROTOCOL Events:
event AuthorizeServiceProvider(address indexed _owner, address _serviceProvider);
event DeauthorizeServiceProvider(address indexed _owner, address _serviceProvider);
event SetServiceProviderFee(address indexed _serviceProvider, uint256 _feeBasisPoints);
event BurnTokens(address indexed _from, address indexed _serviceProvider, uint256 _value);
// @param _burnBasisPoints
// @return success
// @dev Set BurnRate on Wolk Protocol -- only Wolk can set this, affects Service Provider settleBuyer
function setBurnRate(uint256 _burnBasisPoints) onlyOwner returns (bool success) {
require((_burnBasisPoints > 0) && (_burnBasisPoints <= 1000));
burnBasisPoints = _burnBasisPoints;
return true;
}
// @param _newBurnFormula
// @return success
// @dev Set the formula to use for burning -- only Wolk can set this
function setBurnFormula(address _newBurnFormula) onlyOwner returns (bool success){
uint256 testBurning = estWolkToBurn(_newBurnFormula, 10 ** 18);
require(testBurning > (5 * 10 ** 13));
burnFormula = _newBurnFormula;
return true;
}
// @param _newFeeFormula
// @return success
// @dev Set the formula to use for settlement -- settler can customize its fee
function setFeeFormula(address _newFeeFormula) onlySettler returns (bool success){
uint256 testSettling = estProviderFee(_newFeeFormula, 10 ** 18);
require(testSettling > (5 * 10 ** 13));
feeFormulas[msg.sender] = _newFeeFormula;
return true;
}
// @param _isRunning
// @return success
// @dev upating settlement status -- only Wolk can set this
function updateSettlementStatus(bool _isRunning) onlyOwner returns (bool success){
settlementIsRunning = _isRunning;
return true;
}
// @param _serviceProvider
// @param _feeBasisPoints
// @return success
// @dev Set Service Provider fee -- only Contract Owner can do this, affects Service Provider settleSeller
function setServiceFee(address _serviceProvider, uint256 _feeBasisPoints) onlyOwner returns (bool success) {
if (_feeBasisPoints <= 0 || _feeBasisPoints > 4000){
// revoke Settler privilege
settlers[_serviceProvider] = false;
feeBasisPoints[_serviceProvider] = 0;
return false;
}else{
feeBasisPoints[_serviceProvider] = _feeBasisPoints;
settlers[_serviceProvider] = true;
SetServiceProviderFee(_serviceProvider, _feeBasisPoints);
return true;
}
}
// @param _serviceProvider
// @return _feeBasisPoints
// @dev Check service Fee (in BP) for a given provider
function checkServiceFee(address _serviceProvider) constant returns (uint256 _feeBasisPoints) {
return feeBasisPoints[_serviceProvider];
}
// @param _serviceProvider
// @return _formulaAddress
// @dev Returns the contract address of the Service Provider's fee formula
function checkFeeSchedule(address _serviceProvider) constant returns (address _formulaAddress) {
return feeFormulas[_serviceProvider];
}
// @param _value
// @return wolkBurnt
// @dev Returns estimate of Wolk to burn
function estWolkToBurn(address _burnFormula, uint256 _value) constant internal returns (uint256){
if(_burnFormula != 0x0){
uint256 wolkBurnt = IBurnFormula(_burnFormula).calculateWolkToBurn(_value);
return wolkBurnt;
}else{
return 0;
}
}
// @param _value
// @param _serviceProvider
// @return estFee
// @dev Returns estimate of Service Provider's fee
function estProviderFee(address _serviceProvider, uint256 _value) constant internal returns (uint256){
address ProviderFeeFormula = feeFormulas[_serviceProvider];
if (ProviderFeeFormula != 0x0){
uint256 estFee = IFeeFormula(ProviderFeeFormula).calculateProviderFee(_value);
return estFee;
}else{
return 0;
}
}
// @param _buyer
// @param _value
// @return success
// @dev Service Provider Settlement with Buyer: a small percent is burnt (set in setBurnRate, stored in burnBasisPoints) when funds are transferred from buyer to Service Provider [only accessible by settlers]
function settleBuyer(address _buyer, uint256 _value) onlySettler isSettleable returns (bool success) {
require((burnBasisPoints > 0) && (burnBasisPoints <= 1000) && authorized[_buyer][msg.sender]); // Buyer must authorize Service Provider
require(balances[_buyer] >= _value && _value > 0);
var WolkToBurn = estWolkToBurn(burnFormula, _value);
var burnCap = safeDiv(safeMul(_value, burnBasisPoints), 10000); //can not burn more than this
// If burn formula not found, use default burn rate. If Est to burn exceeds BurnCap, cut back to the cap
if (WolkToBurn < 1) WolkToBurn = burnCap;
if (WolkToBurn > burnCap) WolkToBurn = burnCap;
var transferredToServiceProvider = safeSub(_value, WolkToBurn);
balances[_buyer] = safeSub(balances[_buyer], _value);
balances[msg.sender] = safeAdd(balances[msg.sender], transferredToServiceProvider);
totalTokens = safeSub(totalTokens, WolkToBurn);
Transfer(_buyer, msg.sender, transferredToServiceProvider);
Transfer(_buyer, 0x00000000000000000000, WolkToBurn);
BurnTokens(_buyer, msg.sender, WolkToBurn);
return true;
}
// @param _seller
// @param _value
// @return success
// @dev Service Provider Settlement with Seller: a small percent is kept by Service Provider (set in setServiceFee, stored in feeBasisPoints) when funds are transferred from Service Provider to seller [only accessible by settlers]
function settleSeller(address _seller, uint256 _value) onlySettler isSettleable returns (bool success) {
// Service Providers have a % max fee (e.g. 20%)
var serviceProviderBP = feeBasisPoints[msg.sender];
require((serviceProviderBP > 0) && (serviceProviderBP <= 4000) && (_value > 0));
var seviceFee = estProviderFee(msg.sender, _value);
var Maximumfee = safeDiv(safeMul(_value, serviceProviderBP), 10000);
// If provider's fee formula not set, use default burn rate. If Est fee exceeds Maximumfee, cut back to the fee
if (seviceFee < 1) seviceFee = Maximumfee;
if (seviceFee > Maximumfee) seviceFee = Maximumfee;
var transferredToSeller = safeSub(_value, seviceFee);
require(balances[msg.sender] >= transferredToSeller );
balances[_seller] = safeAdd(balances[_seller], transferredToSeller);
Transfer(msg.sender, _seller, transferredToSeller);
return true;
}
// @param _providerToAdd
// @return success
// @dev Buyer authorizes the Service Provider (to call settleBuyer). For security reason, _providerToAdd needs to be whitelisted by Wolk Inc first
function authorizeProvider(address _providerToAdd) returns (bool success) {
require(settlers[_providerToAdd]);
authorized[msg.sender][_providerToAdd] = true;
AuthorizeServiceProvider(msg.sender, _providerToAdd);
return true;
}
// @param _providerToRemove
// @return success
// @dev Buyer deauthorizes the Service Provider (from calling settleBuyer)
function deauthorizeProvider(address _providerToRemove) returns (bool success) {
authorized[msg.sender][_providerToRemove] = false;
DeauthorizeServiceProvider(msg.sender, _providerToRemove);
return true;
}
// @param _owner
// @param _serviceProvider
// @return authorizationStatus
// @dev Check authorization between account and Service Provider
function checkAuthorization(address _owner, address _serviceProvider) constant returns (bool authorizationStatus) {
return authorized[_owner][_serviceProvider];
}
// @param _owner
// @param _providerToAdd
// @return authorizationStatus
// @dev Grant authorization between account and Service Provider on buyers' behalf [only accessible by Contract Owner]
// @note Explicit permission from balance owner MUST be obtained beforehand
function grantService(address _owner, address _providerToAdd) onlyOwner returns (bool authorizationStatus) {
var isPreauthorized = authorized[_owner][msg.sender];
if (isPreauthorized && settlers[_providerToAdd]) {
authorized[_owner][_providerToAdd] = true;
AuthorizeServiceProvider(msg.sender, _providerToAdd);
return true;
}else{
return false;
}
}
// @param _owner
// @param _providerToRemove
// @return authorization_status
// @dev Revoke authorization between account and Service Provider on buyers' behalf [only accessible by Contract Owner]
// @note Explicit permission from balance owner are NOT required for disabling ill-intent Service Provider
function removeService(address _owner, address _providerToRemove) onlyOwner returns (bool authorizationStatus) {
authorized[_owner][_providerToRemove] = false;
DeauthorizeServiceProvider(_owner, _providerToRemove);
return true;
}
}
// Taken from https://github.com/bancorprotocol/contracts/blob/master/solidity/contracts/BancorFormula.sol
contract IBancorFormula {
function calculatePurchaseReturn(uint256 _supply, uint256 _reserveBalance, uint8 _reserveRatio, uint256 _depositAmount) public constant returns (uint256);
function calculateSaleReturn(uint256 _supply, uint256 _reserveBalance, uint8 _reserveRatio, uint256 _sellAmount) public constant returns (uint256);
}
contract WolkExchange is WolkProtocol, WolkTGE {
uint256 public maxPerExchangeBP = 50;
address public exchangeFormula;
bool public exchangeIsRunning = false;
modifier isExchangable { require(exchangeIsRunning && allSaleCompleted); _; }
// @param _newExchangeformula
// @return success
// @dev Set the bancor formula to use -- only Wolk Inc can set this
function setExchangeFormula(address _newExchangeformula) onlyOwner returns (bool success){
require(sellWolkEstimate(10**decimals, _newExchangeformula) > 0);
require(purchaseWolkEstimate(10**decimals, _newExchangeformula) > 0);
exchangeIsRunning = false;
exchangeFormula = _newExchangeformula;
return true;
}
// @param _isRunning
// @return success
// @dev upating exchange status -- only Wolk Inc can set this
function updateExchangeStatus(bool _isRunning) onlyOwner returns (bool success){
if (_isRunning){
require(sellWolkEstimate(10**decimals, exchangeFormula) > 0);
require(purchaseWolkEstimate(10**decimals, exchangeFormula) > 0);
}
exchangeIsRunning = _isRunning;
return true;
}
// @param _maxPerExchange
// @return success
// @dev Set max sell token amount per transaction -- only Wolk Inc can set this
function setMaxPerExchange(uint256 _maxPerExchange) onlyOwner returns (bool success) {
require((_maxPerExchange >= 10) && (_maxPerExchange <= 100));
maxPerExchangeBP = _maxPerExchange;
return true;
}
// @return Estimated Liquidation Cap
// @dev Liquidation Cap per transaction is used to ensure proper price discovery for Wolk Exchange
function estLiquidationCap() public constant returns (uint256) {
if (openSaleCompleted){
var liquidationMax = safeDiv(safeMul(totalTokens, maxPerExchangeBP), 10000);
if (liquidationMax < 100 * 10**decimals){
liquidationMax = 100 * 10**decimals;
}
return liquidationMax;
}else{
return 0;
}
}
function sellWolkEstimate(uint256 _wolkAmountest, address _formula) internal returns(uint256) {
uint256 ethReceivable = IBancorFormula(_formula).calculateSaleReturn(totalTokens, reserveBalance, percentageETHReserve, _wolkAmountest);
return ethReceivable;
}
function purchaseWolkEstimate(uint256 _ethAmountest, address _formula) internal returns(uint256) {
uint256 wolkReceivable = IBancorFormula(_formula).calculatePurchaseReturn(totalTokens, reserveBalance, percentageETHReserve, _ethAmountest);
return wolkReceivable;
}
// @param _wolkAmount
// @return ethReceivable
// @dev send Wolk into contract in exchange for eth, at an exchange rate based on the Bancor Protocol derivation and decrease totalSupply accordingly
function sellWolk(uint256 _wolkAmount) isExchangable() returns(uint256) {
uint256 sellCap = estLiquidationCap();
require((balances[msg.sender] >= _wolkAmount));
require(sellCap >= _wolkAmount);
uint256 ethReceivable = sellWolkEstimate(_wolkAmount,exchangeFormula);
require(this.balance > ethReceivable);
balances[msg.sender] = safeSub(balances[msg.sender], _wolkAmount);
totalTokens = safeSub(totalTokens, _wolkAmount);
reserveBalance = safeSub(this.balance, ethReceivable);
WolkDestroyed(msg.sender, _wolkAmount);
Transfer(msg.sender, 0x00000000000000000000, _wolkAmount);
msg.sender.transfer(ethReceivable);
return ethReceivable;
}
// @return wolkReceivable
// @dev send eth into contract in exchange for Wolk tokens, at an exchange rate based on the Bancor Protocol derivation and increase totalSupply accordingly
function purchaseWolk(address _buyer) isExchangable() payable returns(uint256){
require(msg.value > 0);
uint256 wolkReceivable = purchaseWolkEstimate(msg.value, exchangeFormula);
require(wolkReceivable > 0);
totalTokens = safeAdd(totalTokens, wolkReceivable);
balances[_buyer] = safeAdd(balances[_buyer], wolkReceivable);
reserveBalance = safeAdd(reserveBalance, msg.value);
WolkCreated(_buyer, wolkReceivable);
Transfer(address(this),_buyer,wolkReceivable);
return wolkReceivable;
}
// @dev fallback function for purchase
// @note Automatically fallback to tokenGenerationEvent before sale is completed. After the token generation event, fallback to purchaseWolk. Liquidity exchange will be enabled through updateExchangeStatus
function () payable {
require(msg.value > 0);
if(!openSaleCompleted){
this.tokenGenerationEvent.value(msg.value)(msg.sender);
}else if (block.number >= end_block){
this.purchaseWolk.value(msg.value)(msg.sender);
}else{
revert();
}
}
}