pragma solidity ^0.4.4;
// ERC20 token interface is implemented only partially
// (no SafeMath is used because contract code is very simple)
//
// Some functions left undefined:
// - transfer, transferFrom,
// - approve, allowance.
contract PresaleToken
{
/// Fields:
string public constant name = "IMMLA Presale Token";
string public constant symbol = "IML";
uint public constant decimals = 18;
uint public constant PRICE = 5200; // per 1 Ether
// price
// Cap is 2747 ETH
// 1 eth = 5200; presale IMMLA tokens
// 1 IML = 0,000192 ETH
// ETH price ~220$ - 10.07.2017
uint public constant TOKEN_SUPPLY_LIMIT = PRICE * 2747 * (1 ether / 1 wei);
enum State{
Init,
Running,
Paused,
Migrating,
Migrated
}
State public currentState = State.Running;
uint public totalSupply = 0; // amount of tokens already sold
// Gathered funds can be withdrawn only to escrow's address.
address public escrow = 0;
// Token manager has exclusive priveleges to call administrative
// functions on this contract.
address public tokenManager = 0;
// Crowdsale manager has exclusive priveleges to burn presale tokens.
address public crowdsaleManager = 0;
mapping (address => uint256) private balance;
/// Modifiers:
modifier onlyTokenManager() { if(msg.sender != tokenManager) throw; _; }
modifier onlyCrowdsaleManager() { if(msg.sender != crowdsaleManager) throw; _; }
modifier onlyInState(State state){ if(state != currentState) throw; _; }
/// Events:
event LogBuy(address indexed owner, uint value);
event LogBurn(address indexed owner, uint value);
event LogStateSwitch(State newState);
/// Functions:
/// @dev Constructor
/// @param _tokenManager Token manager address.
function PresaleToken(address _tokenManager, address _escrow)
{
if(_tokenManager==0) throw;
if(_escrow==0) throw;
tokenManager = _tokenManager;
escrow = _escrow;
}
function buyTokens(address _buyer) public payable onlyInState(State.Running)
{
if(msg.value == 0) throw;
uint newTokens = msg.value * PRICE;
if (totalSupply + newTokens > TOKEN_SUPPLY_LIMIT) throw;
balance[_buyer] += newTokens;
totalSupply += newTokens;
LogBuy(_buyer, newTokens);
}
/// @dev Returns number of tokens owned by given address.
/// @param _owner Address of token owner.
function burnTokens(address _owner) public onlyCrowdsaleManager onlyInState(State.Migrating)
{
uint tokens = balance[_owner];
if(tokens == 0) throw;
balance[_owner] = 0;
totalSupply -= tokens;
LogBurn(_owner, tokens);
// Automatically switch phase when migration is done.
if(totalSupply == 0)
{
currentState = State.Migrated;
LogStateSwitch(State.Migrated);
}
}
/// @dev Returns number of tokens owned by given address.
/// @param _owner Address of token owner.
function balanceOf(address _owner) constant returns (uint256)
{
return balance[_owner];
}
function setPresaleState(State _nextState) public onlyTokenManager
{
// Init -> Running
// Running -> Paused
// Running -> Migrating
// Paused -> Running
// Paused -> Migrating
// Migrating -> Migrated
bool canSwitchState
= (currentState == State.Init && _nextState == State.Running)
|| (currentState == State.Running && _nextState == State.Paused)
// switch to migration phase only if crowdsale manager is set
|| ((currentState == State.Running || currentState == State.Paused)
&& _nextState == State.Migrating
&& crowdsaleManager != 0x0)
|| (currentState == State.Paused && _nextState == State.Running)
// switch to migrated only if everyting is migrated
|| (currentState == State.Migrating && _nextState == State.Migrated
&& totalSupply == 0);
if(!canSwitchState) throw;
currentState = _nextState;
LogStateSwitch(_nextState);
}
function withdrawEther() public onlyTokenManager
{
if(this.balance > 0)
{
if(!escrow.send(this.balance)) throw;
}
}
/// Setters/getters
function setTokenManager(address _mgr) public onlyTokenManager
{
tokenManager = _mgr;
}
function setCrowdsaleManager(address _mgr) public onlyTokenManager
{
// You can't change crowdsale contract when migration is in progress.
if(currentState == State.Migrating) throw;
crowdsaleManager = _mgr;
}
function getTokenManager()constant returns(address)
{
return tokenManager;
}
function getCrowdsaleManager()constant returns(address)
{
return crowdsaleManager;
}
function getCurrentState()constant returns(State)
{
return currentState;
}
function getPrice()constant returns(uint)
{
return PRICE;
}
function getTotalSupply()constant returns(uint)
{
return totalSupply;
}
// Default fallback function
function() payable
{
buyTokens(msg.sender);
}
}
{
"compilationTarget": {
"PresaleToken.sol": "PresaleToken"
},
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"currentState","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"TOKEN_SUPPLY_LIMIT","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"tokenManager","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"crowdsaleManager","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getCurrentState","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_mgr","type":"address"}],"name":"setCrowdsaleManager","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getCrowdsaleManager","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"withdrawEther","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_mgr","type":"address"}],"name":"setTokenManager","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"PRICE","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_nextState","type":"uint8"}],"name":"setPresaleState","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getTokenManager","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"burnTokens","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getTotalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"escrow","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_buyer","type":"address"}],"name":"buyTokens","outputs":[],"payable":true,"type":"function"},{"inputs":[{"name":"_tokenManager","type":"address"},{"name":"_escrow","type":"address"}],"payable":false,"type":"constructor"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"LogBuy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"LogBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newState","type":"uint8"}],"name":"LogStateSwitch","type":"event"}]