pragma solidity ^0.4.18;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
/**
* @title Claimable
* @dev Extension for the Ownable contract, where the ownership needs to be claimed.
* This allows the new owner to accept the transfer.
*/
contract Claimable is Ownable {
address public pendingOwner;
/**
* @dev Modifier throws if called by any account other than the pendingOwner.
*/
modifier onlyPendingOwner() {
require(msg.sender == pendingOwner);
_;
}
/**
* @dev Allows the current owner to set the pendingOwner address.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) onlyOwner public {
pendingOwner = newOwner;
}
/**
* @dev Allows the pendingOwner address to finalize the transfer.
*/
function claimOwnership() onlyPendingOwner public {
OwnershipTransferred(owner, pendingOwner);
owner = pendingOwner;
pendingOwner = address(0);
}
}
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
uint256 public totalSupply;
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}
/**
* @title LimitedTransferToken
* @dev LimitedTransferToken defines the generic interface and the implementation to limit token
* transferability for different events. It is intended to be used as a base class for other token
* contracts.
* LimitedTransferToken has been designed to allow for different limiting factors,
* this can be achieved by recursively calling super.transferableTokens() until the base class is
* hit. For example:
* function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
* return min256(unlockedTokens, super.transferableTokens(holder, time));
* }
* A working example is VestedToken.sol:
* https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/VestedToken.sol
*/
contract LimitedTransferToken is ERC20 {
/**
* @dev Checks whether it can transfer or otherwise throws.
*/
modifier canTransfer(address _sender, uint256 _value) {
require(_value <= transferableTokens(_sender, uint64(now)));
_;
}
/**
* @dev Checks modifier and allows transfer if tokens are not locked.
* @param _to The address that will receive the tokens.
* @param _value The amount of tokens to be transferred.
*/
function transfer(address _to, uint256 _value) canTransfer(msg.sender, _value) public returns (bool) {
return super.transfer(_to, _value);
}
/**
* @dev Checks modifier and allows transfer if tokens are not locked.
* @param _from The address that will send the tokens.
* @param _to The address that will receive the tokens.
* @param _value The amount of tokens to be transferred.
*/
function transferFrom(address _from, address _to, uint256 _value) canTransfer(_from, _value) public returns (bool) {
return super.transferFrom(_from, _to, _value);
}
/**
* @dev Default transferable tokens function returns all tokens for a holder (no limit).
* @dev Overwriting transferableTokens(address holder, uint64 time) is the way to provide the
* specific logic for limiting token transferability for a holder over time.
*/
function transferableTokens(address holder, uint64 time) public view returns (uint256) {
return balanceOf(holder);
}
}
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
Transfer(_from, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
*
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return allowed[_owner][_spender];
}
/**
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
*/
function increaseApproval (address _spender, uint _addedValue) public returns (bool success) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function decreaseApproval (address _spender, uint _subtractedValue) public returns (bool success) {
uint oldValue = allowed[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
/**
* @title Mintable token
* @dev Simple ERC20 Token example, with mintable token creation
* @dev Issue: * https://github.com/OpenZeppelin/zeppelin-solidity/issues/120
* Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
*/
contract MintableToken is StandardToken, Claimable {
event Mint(address indexed to, uint256 amount);
event MintFinished();
bool public mintingFinished = false;
modifier canMint() {
require(!mintingFinished);
_;
}
/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
totalSupply = totalSupply.add(_amount);
balances[_to] = balances[_to].add(_amount);
Mint(_to, _amount);
Transfer(address(0), _to, _amount);
return true;
}
/**
* @dev Function to stop minting new tokens.
* @return True if the operation was successful.
*/
function finishMinting() onlyOwner public returns (bool) {
mintingFinished = true;
MintFinished();
return true;
}
}
/*
Smart Token interface
*/
contract ISmartToken {
// =================================================================================================================
// Members
// =================================================================================================================
bool public transfersEnabled = false;
// =================================================================================================================
// Event
// =================================================================================================================
// triggered when a smart token is deployed - the _token address is defined for forward compatibility, in case we want to trigger the event from a factory
event NewSmartToken(address _token);
// triggered when the total supply is increased
event Issuance(uint256 _amount);
// triggered when the total supply is decreased
event Destruction(uint256 _amount);
// =================================================================================================================
// Functions
// =================================================================================================================
function disableTransfers(bool _disable) public;
function issue(address _to, uint256 _amount) public;
function destroy(address _from, uint256 _amount) public;
}
/**
BancorSmartToken
*/
contract LimitedTransferBancorSmartToken is MintableToken, ISmartToken, LimitedTransferToken {
// =================================================================================================================
// Modifiers
// =================================================================================================================
/**
* @dev Throws if destroy flag is not enabled.
*/
modifier canDestroy() {
require(destroyEnabled);
_;
}
// =================================================================================================================
// Members
// =================================================================================================================
// We add this flag to avoid users and owner from destroy tokens during crowdsale,
// This flag is set to false by default and blocks destroy function,
// We enable destroy option on finalize, so destroy will be possible after the crowdsale.
bool public destroyEnabled = false;
// =================================================================================================================
// Public Functions
// =================================================================================================================
function setDestroyEnabled(bool _enable) onlyOwner public {
destroyEnabled = _enable;
}
// =================================================================================================================
// Impl ISmartToken
// =================================================================================================================
//@Override
function disableTransfers(bool _disable) onlyOwner public {
transfersEnabled = !_disable;
}
//@Override
function issue(address _to, uint256 _amount) onlyOwner public {
require(super.mint(_to, _amount));
Issuance(_amount);
}
//@Override
function destroy(address _from, uint256 _amount) canDestroy public {
require(msg.sender == _from || msg.sender == owner); // validate input
balances[_from] = balances[_from].sub(_amount);
totalSupply = totalSupply.sub(_amount);
Destruction(_amount);
Transfer(_from, 0x0, _amount);
}
// =================================================================================================================
// Impl LimitedTransferToken
// =================================================================================================================
// Enable/Disable token transfer
// Tokens will be locked in their wallets until the end of the Crowdsale.
// @holder - token`s owner
// @time - not used (framework unneeded functionality)
//
// @Override
function transferableTokens(address holder, uint64 time) public constant returns (uint256) {
require(transfersEnabled);
return super.transferableTokens(holder, time);
}
}
/**
A Token which is 'Bancor' compatible and can mint new tokens and pause token-transfer functionality
*/
contract SirinSmartToken is LimitedTransferBancorSmartToken {
// =================================================================================================================
// Members
// =================================================================================================================
string public name = "SIRIN";
string public symbol = "SRN";
uint8 public decimals = 18;
// =================================================================================================================
// Constructor
// =================================================================================================================
function SirinSmartToken() public {
//Apart of 'Bancor' computability - triggered when a smart token is deployed
NewSmartToken(address(this));
}
}
/**
* @title RefundVault
* @dev This contract is used for storing TOKENS AND ETHER while a crowdsale is in progress for a period of 60 DAYS.
* Investor can ask for a full/part refund for his ether against token. Once tokens are Claimed by the investor, they cannot be refunded.
* After 60 days, all ether will be withdrawn from the vault`s wallet, leaving all tokens to be claimed by the their owners.
**/
contract RefundVault is Claimable {
using SafeMath for uint256;
// =================================================================================================================
// Enums
// =================================================================================================================
enum State { Active, Refunding, Closed }
// =================================================================================================================
// Members
// =================================================================================================================
// Refund time frame
uint256 public constant REFUND_TIME_FRAME = 60 days;
mapping (address => uint256) public depositedETH;
mapping (address => uint256) public depositedToken;
address public etherWallet;
SirinSmartToken public token;
State public state;
uint256 public refundStartTime;
// =================================================================================================================
// Events
// =================================================================================================================
event Active();
event Closed();
event Deposit(address indexed beneficiary, uint256 etherWeiAmount, uint256 tokenWeiAmount);
event RefundsEnabled();
event RefundedETH(address beneficiary, uint256 weiAmount);
event TokensClaimed(address indexed beneficiary, uint256 weiAmount);
// =================================================================================================================
// Modifiers
// =================================================================================================================
modifier isActiveState() {
require(state == State.Active);
_;
}
modifier isRefundingState() {
require(state == State.Refunding);
_;
}
modifier isCloseState() {
require(state == State.Closed);
_;
}
modifier isRefundingOrCloseState() {
require(state == State.Refunding || state == State.Closed);
_;
}
modifier isInRefundTimeFrame() {
require(refundStartTime <= now && refundStartTime + REFUND_TIME_FRAME > now);
_;
}
modifier isRefundTimeFrameExceeded() {
require(refundStartTime + REFUND_TIME_FRAME < now);
_;
}
// =================================================================================================================
// Ctors
// =================================================================================================================
function RefundVault(address _etherWallet, SirinSmartToken _token) public {
require(_etherWallet != address(0));
require(_token != address(0));
etherWallet = _etherWallet;
token = _token;
state = State.Active;
Active();
}
// =================================================================================================================
// Public Functions
// =================================================================================================================
function deposit(address investor, uint256 tokensAmount) isActiveState onlyOwner public payable {
depositedETH[investor] = depositedETH[investor].add(msg.value);
depositedToken[investor] = depositedToken[investor].add(tokensAmount);
Deposit(investor, msg.value, tokensAmount);
}
function close() isRefundingState onlyOwner isRefundTimeFrameExceeded public {
state = State.Closed;
Closed();
etherWallet.transfer(this.balance);
}
function enableRefunds() isActiveState onlyOwner public {
state = State.Refunding;
refundStartTime = now;
RefundsEnabled();
}
//@dev Refund ether back to the investor in returns of proportional amount of SRN
//back to the Sirin`s wallet
function refundETH(uint256 ETHToRefundAmountWei) isInRefundTimeFrame isRefundingState public {
require(ETHToRefundAmountWei != 0);
uint256 depositedTokenValue = depositedToken[msg.sender];
uint256 depositedETHValue = depositedETH[msg.sender];
require(ETHToRefundAmountWei <= depositedETHValue);
uint256 refundTokens = ETHToRefundAmountWei.mul(depositedTokenValue).div(depositedETHValue);
assert(refundTokens > 0);
depositedETH[msg.sender] = depositedETHValue.sub(ETHToRefundAmountWei);
depositedToken[msg.sender] = depositedTokenValue.sub(refundTokens);
token.destroy(address(this),refundTokens);
msg.sender.transfer(ETHToRefundAmountWei);
RefundedETH(msg.sender, ETHToRefundAmountWei);
}
//@dev Transfer tokens from the vault to the investor while releasing proportional amount of ether
//to Sirin`s wallet.
//Can be triggerd by the investor only
function claimTokens(uint256 tokensToClaim) isRefundingOrCloseState public {
require(tokensToClaim != 0);
address investor = msg.sender;
require(depositedToken[investor] > 0);
uint256 depositedTokenValue = depositedToken[investor];
uint256 depositedETHValue = depositedETH[investor];
require(tokensToClaim <= depositedTokenValue);
uint256 claimedETH = tokensToClaim.mul(depositedETHValue).div(depositedTokenValue);
assert(claimedETH > 0);
depositedETH[investor] = depositedETHValue.sub(claimedETH);
depositedToken[investor] = depositedTokenValue.sub(tokensToClaim);
token.transfer(investor, tokensToClaim);
if(state != State.Closed) {
etherWallet.transfer(claimedETH);
}
TokensClaimed(investor, tokensToClaim);
}
// @dev investors can claim tokens by calling the function
// @param tokenToClaimAmount - amount of the token to claim
function claimAllTokens() isRefundingOrCloseState public {
uint256 depositedTokenValue = depositedToken[msg.sender];
claimTokens(depositedTokenValue);
}
}
/**
* @title Crowdsale
* @dev Crowdsale is a base contract for managing a token crowdsale.
* Crowdsales have a start and end timestamps, where investors can make
* token purchases and the crowdsale will assign them tokens based
* on a token per ETH rate. Funds collected are forwarded to a wallet
* as they arrive.
*/
contract Crowdsale {
using SafeMath for uint256;
// The token being sold
SirinSmartToken public token;
// start and end timestamps where investments are allowed (both inclusive)
uint256 public startTime;
uint256 public endTime;
// address where funds are collected
address public wallet;
// how many token units a buyer gets per wei
uint256 public rate;
// amount of raised money in wei
uint256 public weiRaised;
/**
* event for token purchase logging
* @param purchaser who paid for the tokens
* @param beneficiary who got the tokens
* @param value weis paid for purchase
* @param amount amount of tokens purchased
*/
event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
function Crowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, address _wallet, SirinSmartToken _token) public {
require(_startTime >= now);
require(_endTime >= _startTime);
require(_rate > 0);
require(_wallet != address(0));
require(_token != address(0));
startTime = _startTime;
endTime = _endTime;
rate = _rate;
wallet = _wallet;
token = _token;
}
// fallback function can be used to buy tokens
function() external payable {
buyTokens(msg.sender);
}
// low level token purchase function
function buyTokens(address beneficiary) public payable {
require(beneficiary != address(0));
require(validPurchase());
uint256 weiAmount = msg.value;
// calculate token amount to be created
uint256 tokens = weiAmount.mul(getRate());
// update state
weiRaised = weiRaised.add(weiAmount);
token.issue(beneficiary, tokens);
TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
forwardFunds();
}
// send ether to the fund collection wallet
// override to create custom fund forwarding mechanisms
function forwardFunds() internal {
wallet.transfer(msg.value);
}
// @return true if the transaction can buy tokens
function validPurchase() internal view returns (bool) {
bool withinPeriod = now >= startTime && now <= endTime;
bool nonZeroPurchase = msg.value != 0;
return withinPeriod && nonZeroPurchase;
}
// @return true if crowdsale event has ended
function hasEnded() public view returns (bool) {
return now > endTime;
}
// @return the crowdsale rate
function getRate() public view returns (uint256) {
return rate;
}
}
/**
* @title FinalizableCrowdsale
* @dev Extension of Crowdsale where an owner can do extra work
* after finishing.
*/
contract FinalizableCrowdsale is Crowdsale, Claimable {
using SafeMath for uint256;
bool public isFinalized = false;
event Finalized();
/**
* @dev Must be called after crowdsale ends, to do some extra finalization
* work. Calls the contract's finalization function.
*/
function finalize() onlyOwner public {
require(!isFinalized);
require(hasEnded());
finalization();
Finalized();
isFinalized = true;
}
/**
* @dev Can be overridden to add finalization logic. The overriding function
* should call super.finalization() to ensure the chain of finalization is
* executed entirely.
*/
function finalization() internal {
}
}
contract SirinCrowdsale is FinalizableCrowdsale {
// =================================================================================================================
// Constants
// =================================================================================================================
// Max amount of known addresses of which will get SRN by 'Grant' method.
//
// grantees addresses will be SirinLabs wallets addresses.
// these wallets will contain SRN tokens that will be used for 2 purposes only -
// 1. SRN tokens against raised fiat money
// 2. SRN tokens for presale bonus.
// we set the value to 10 (and not to 2) because we want to allow some flexibility for cases like fiat money that is raised close to the crowdsale.
// we limit the value to 10 (and not larger) to limit the run time of the function that process the grantees array.
uint8 public constant MAX_TOKEN_GRANTEES = 10;
// SRN to ETH base rate
uint256 public constant EXCHANGE_RATE = 500;
// Refund division rate
uint256 public constant REFUND_DIVISION_RATE = 2;
// =================================================================================================================
// Modifiers
// =================================================================================================================
/**
* @dev Throws if called not during the crowdsale time frame
*/
modifier onlyWhileSale() {
require(isActive());
_;
}
// =================================================================================================================
// Members
// =================================================================================================================
// wallets address for 60% of SRN allocation
address public walletTeam; //10% of the total number of SRN tokens will be allocated to the team
address public walletOEM; //10% of the total number of SRN tokens will be allocated to OEM’s, Operating System implementation, SDK developers and rebate to device and Shield OS™ users
address public walletBounties; //5% of the total number of SRN tokens will be allocated to professional fees and Bounties
address public walletReserve; //35% of the total number of SRN tokens will be allocated to SIRIN LABS and as a reserve for the company to be used for future strategic plans for the created ecosystem
// Funds collected outside the crowdsale in wei
uint256 public fiatRaisedConvertedToWei;
//Grantees - used for non-ether and presale bonus token generation
address[] public presaleGranteesMapKeys;
mapping (address => uint256) public presaleGranteesMap; //address=>wei token amount
// The refund vault
RefundVault public refundVault;
// =================================================================================================================
// Events
// =================================================================================================================
event GrantAdded(address indexed _grantee, uint256 _amount);
event GrantUpdated(address indexed _grantee, uint256 _oldAmount, uint256 _newAmount);
event GrantDeleted(address indexed _grantee, uint256 _hadAmount);
event FiatRaisedUpdated(address indexed _address, uint256 _fiatRaised);
event TokenPurchaseWithGuarantee(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
// =================================================================================================================
// Constructors
// =================================================================================================================
function SirinCrowdsale(uint256 _startTime,
uint256 _endTime,
address _wallet,
address _walletTeam,
address _walletOEM,
address _walletBounties,
address _walletReserve,
SirinSmartToken _sirinSmartToken,
RefundVault _refundVault)
public
Crowdsale(_startTime, _endTime, EXCHANGE_RATE, _wallet, _sirinSmartToken) {
require(_walletTeam != address(0));
require(_walletOEM != address(0));
require(_walletBounties != address(0));
require(_walletReserve != address(0));
require(_sirinSmartToken != address(0));
require(_refundVault != address(0));
walletTeam = _walletTeam;
walletOEM = _walletOEM;
walletBounties = _walletBounties;
walletReserve = _walletReserve;
token = _sirinSmartToken;
refundVault = _refundVault;
}
// =================================================================================================================
// Impl Crowdsale
// =================================================================================================================
// @return the rate in SRN per 1 ETH according to the time of the tx and the SRN pricing program.
// @Override
function getRate() public view returns (uint256) {
if (now < (startTime.add(24 hours))) {return 1000;}
if (now < (startTime.add(2 days))) {return 950;}
if (now < (startTime.add(3 days))) {return 900;}
if (now < (startTime.add(4 days))) {return 855;}
if (now < (startTime.add(5 days))) {return 810;}
if (now < (startTime.add(6 days))) {return 770;}
if (now < (startTime.add(7 days))) {return 730;}
if (now < (startTime.add(8 days))) {return 690;}
if (now < (startTime.add(9 days))) {return 650;}
if (now < (startTime.add(10 days))) {return 615;}
if (now < (startTime.add(11 days))) {return 580;}
if (now < (startTime.add(12 days))) {return 550;}
if (now < (startTime.add(13 days))) {return 525;}
return rate;
}
// =================================================================================================================
// Impl FinalizableCrowdsale
// =================================================================================================================
//@Override
function finalization() internal onlyOwner {
super.finalization();
// granting bonuses for the pre crowdsale grantees:
for (uint256 i = 0; i < presaleGranteesMapKeys.length; i++) {
token.issue(presaleGranteesMapKeys[i], presaleGranteesMap[presaleGranteesMapKeys[i]]);
}
// Adding 60% of the total token supply (40% were generated during the crowdsale)
// 40 * 2.5 = 100
uint256 newTotalSupply = token.totalSupply().mul(250).div(100);
// 10% of the total number of SRN tokens will be allocated to the team
token.issue(walletTeam, newTotalSupply.mul(10).div(100));
// 10% of the total number of SRN tokens will be allocated to OEM’s, Operating System implementation,
// SDK developers and rebate to device and Sirin OS™ users
token.issue(walletOEM, newTotalSupply.mul(10).div(100));
// 5% of the total number of SRN tokens will be allocated to professional fees and Bounties
token.issue(walletBounties, newTotalSupply.mul(5).div(100));
// 35% of the total number of SRN tokens will be allocated to SIRIN LABS,
// and as a reserve for the company to be used for future strategic plans for the created ecosystem
token.issue(walletReserve, newTotalSupply.mul(35).div(100));
// Re-enable transfers after the token sale.
token.disableTransfers(false);
// Re-enable destroy function after the token sale.
token.setDestroyEnabled(true);
// Enable ETH refunds and token claim.
refundVault.enableRefunds();
// transfer token ownership to crowdsale owner
token.transferOwnership(owner);
// transfer refundVault ownership to crowdsale owner
refundVault.transferOwnership(owner);
}
// =================================================================================================================
// Public Methods
// =================================================================================================================
// @return the total funds collected in wei(ETH and none ETH).
function getTotalFundsRaised() public view returns (uint256) {
return fiatRaisedConvertedToWei.add(weiRaised);
}
// @return true if the crowdsale is active, hence users can buy tokens
function isActive() public view returns (bool) {
return now >= startTime && now < endTime;
}
// =================================================================================================================
// External Methods
// =================================================================================================================
// @dev Adds/Updates address and token allocation for token grants.
// Granted tokens are allocated to non-ether, presale, buyers.
// @param _grantee address The address of the token grantee.
// @param _value uint256 The value of the grant in wei token.
function addUpdateGrantee(address _grantee, uint256 _value) external onlyOwner onlyWhileSale{
require(_grantee != address(0));
require(_value > 0);
// Adding new key if not present:
if (presaleGranteesMap[_grantee] == 0) {
require(presaleGranteesMapKeys.length < MAX_TOKEN_GRANTEES);
presaleGranteesMapKeys.push(_grantee);
GrantAdded(_grantee, _value);
}
else {
GrantUpdated(_grantee, presaleGranteesMap[_grantee], _value);
}
presaleGranteesMap[_grantee] = _value;
}
// @dev deletes entries from the grants list.
// @param _grantee address The address of the token grantee.
function deleteGrantee(address _grantee) external onlyOwner onlyWhileSale {
require(_grantee != address(0));
require(presaleGranteesMap[_grantee] != 0);
//delete from the map:
delete presaleGranteesMap[_grantee];
//delete from the array (keys):
uint256 index;
for (uint256 i = 0; i < presaleGranteesMapKeys.length; i++) {
if (presaleGranteesMapKeys[i] == _grantee) {
index = i;
break;
}
}
presaleGranteesMapKeys[index] = presaleGranteesMapKeys[presaleGranteesMapKeys.length - 1];
delete presaleGranteesMapKeys[presaleGranteesMapKeys.length - 1];
presaleGranteesMapKeys.length--;
GrantDeleted(_grantee, presaleGranteesMap[_grantee]);
}
// @dev Set funds collected outside the crowdsale in wei.
// note: we not to use accumulator to allow flexibility in case of humane mistakes.
// funds are converted to wei using the market conversion rate of USD\ETH on the day on the purchase.
// @param _fiatRaisedConvertedToWei number of none eth raised.
function setFiatRaisedConvertedToWei(uint256 _fiatRaisedConvertedToWei) external onlyOwner onlyWhileSale {
fiatRaisedConvertedToWei = _fiatRaisedConvertedToWei;
FiatRaisedUpdated(msg.sender, fiatRaisedConvertedToWei);
}
/// @dev Accepts new ownership on behalf of the SirinCrowdsale contract. This can be used, by the token sale
/// contract itself to claim back ownership of the SirinSmartToken contract.
function claimTokenOwnership() external onlyOwner {
token.claimOwnership();
}
/// @dev Accepts new ownership on behalf of the SirinCrowdsale contract. This can be used, by the token sale
/// contract itself to claim back ownership of the refundVault contract.
function claimRefundVaultOwnership() external onlyOwner {
refundVault.claimOwnership();
}
// @dev Buy tokes with guarantee
function buyTokensWithGuarantee() public payable {
require(validPurchase());
uint256 weiAmount = msg.value;
// calculate token amount to be created
uint256 tokens = weiAmount.mul(getRate());
tokens = tokens.div(REFUND_DIVISION_RATE);
// update state
weiRaised = weiRaised.add(weiAmount);
token.issue(address(refundVault), tokens);
refundVault.deposit.value(msg.value)(msg.sender, tokens);
TokenPurchaseWithGuarantee(msg.sender, address(refundVault), weiAmount, tokens);
}
}
{
"compilationTarget": {
"SirinCrowdsale.sol": "SirinCrowdsale"
},
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[],"name":"getTotalFundsRaised","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"claimTokenOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"refundVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"EXCHANGE_RATE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"rate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"presaleGranteesMap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"endTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"weiRaised","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"finalize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"claimOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"claimRefundVaultOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"wallet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_fiatRaisedConvertedToWei","type":"uint256"}],"name":"setFiatRaisedConvertedToWei","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"walletTeam","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"walletReserve","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"startTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"buyTokensWithGuarantee","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"isFinalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"fiatRaisedConvertedToWei","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_TOKEN_GRANTEES","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"walletBounties","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_grantee","type":"address"},{"name":"_value","type":"uint256"}],"name":"addUpdateGrantee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"presaleGranteesMapKeys","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_grantee","type":"address"}],"name":"deleteGrantee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"pendingOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"}],"name":"buyTokens","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"hasEnded","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"walletOEM","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"REFUND_DIVISION_RATE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_startTime","type":"uint256"},{"name":"_endTime","type":"uint256"},{"name":"_wallet","type":"address"},{"name":"_walletTeam","type":"address"},{"name":"_walletOEM","type":"address"},{"name":"_walletBounties","type":"address"},{"name":"_walletReserve","type":"address"},{"name":"_sirinSmartToken","type":"address"},{"name":"_refundVault","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_grantee","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"GrantAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_grantee","type":"address"},{"indexed":false,"name":"_oldAmount","type":"uint256"},{"indexed":false,"name":"_newAmount","type":"uint256"}],"name":"GrantUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_grantee","type":"address"},{"indexed":false,"name":"_hadAmount","type":"uint256"}],"name":"GrantDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_address","type":"address"},{"indexed":false,"name":"_fiatRaised","type":"uint256"}],"name":"FiatRaisedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"purchaser","type":"address"},{"indexed":true,"name":"beneficiary","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"TokenPurchaseWithGuarantee","type":"event"},{"anonymous":false,"inputs":[],"name":"Finalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"purchaser","type":"address"},{"indexed":true,"name":"beneficiary","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"TokenPurchase","type":"event"}]