ETH Price: $1,854.69 (-8.81%)

Transaction Decoder

Block:
4776293 at Dec-22-2017 10:34:56 AM +UTC
Transaction Fee:
0.00302524 ETH $5.61
Gas Used:
75,631 Gas / 40 Gwei

Emitted Events:

78 SirinSmartToken.Mint( to=[Sender] 0x24c5c997064d28bebd5ace87a275a533ea41edc3, amount=9777607573500000000000 )
79 SirinSmartToken.Transfer( from=0x0000000000000000000000000000000000000000, to=[Sender] 0x24c5c997064d28bebd5ace87a275a533ea41edc3, value=9777607573500000000000 )
80 SirinSmartToken.Issuance( _amount=9777607573500000000000 )
81 SirinCrowdsale.TokenPurchase( purchaser=[Sender] 0x24c5c997064d28bebd5ace87a275a533ea41edc3, beneficiary=[Sender] 0x24c5c997064d28bebd5ace87a275a533ea41edc3, value=15898548900000000000, amount=9777607573500000000000 )
82 MultiSigWallet.Deposit( sender=[Receiver] SirinCrowdsale, value=15898548900000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x24c5C997...3eA41edC3
15.9105489 Eth
Nonce: 0
0.00897476 Eth
Nonce: 1
15.90157414
0x29AfA344...4a2dc0F1e
(Sirin Labs: Token Sale)
0x5978c147...906eE52c5
(Sirin Labs: MultiSig)
84,998.933804278497753677 Eth85,014.832353178497753677 Eth15.8985489
0x68d57c9a...d70528D25
(Ethermine)
872.317003917319363331 Eth872.320029157319363331 Eth0.00302524

Execution Trace

ETH 15.8985489 SirinCrowdsale.CALL( )
  • SirinSmartToken.issue( _to=0x24c5C997064D28bEbD5aCE87a275A533eA41edC3, _amount=9777607573500000000000 )
  • ETH 15.8985489 MultiSigWallet.CALL( )
    File 1 of 3: SirinCrowdsale
    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);
        }
    }

    File 2 of 3: SirinSmartToken
    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);
        }
    }

    File 3 of 3: MultiSigWallet
    pragma solidity 0.4.18;
    
    
    /// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
    /// @author Stefan George - <stefan.george@consensys.net>
    contract MultiSigWallet {
    
        /*
         *  Events
         */
        event Confirmation(address indexed sender, uint indexed transactionId);
        event Revocation(address indexed sender, uint indexed transactionId);
        event Submission(uint indexed transactionId);
        event Execution(uint indexed transactionId);
        event ExecutionFailure(uint indexed transactionId);
        event Deposit(address indexed sender, uint value);
        event OwnerAddition(address indexed owner);
        event OwnerRemoval(address indexed owner);
        event RequirementChange(uint required);
    
        /*
         *  Constants
         */
        uint constant public MAX_OWNER_COUNT = 50;
    
        /*
         *  Storage
         */
        mapping (uint => Transaction) public transactions;
        mapping (uint => mapping (address => bool)) public confirmations;
        mapping (address => bool) public isOwner;
        address[] public owners;
        uint public required;
        uint public transactionCount;
    
        struct Transaction {
            address destination;
            uint value;
            bytes data;
            bool executed;
        }
    
        /*
         *  Modifiers
         */
        modifier onlyWallet() {
            if (msg.sender != address(this))
                throw;
            _;
        }
    
        modifier ownerDoesNotExist(address owner) {
            if (isOwner[owner])
                throw;
            _;
        }
    
        modifier ownerExists(address owner) {
            if (!isOwner[owner])
                throw;
            _;
        }
    
        modifier transactionExists(uint transactionId) {
            if (transactions[transactionId].destination == 0)
                throw;
            _;
        }
    
        modifier confirmed(uint transactionId, address owner) {
            if (!confirmations[transactionId][owner])
                throw;
            _;
        }
    
        modifier notConfirmed(uint transactionId, address owner) {
            if (confirmations[transactionId][owner])
                throw;
            _;
        }
    
        modifier notExecuted(uint transactionId) {
            if (transactions[transactionId].executed)
                throw;
            _;
        }
    
        modifier notNull(address _address) {
            if (_address == 0)
                throw;
            _;
        }
    
        modifier validRequirement(uint ownerCount, uint _required) {
            if (   ownerCount > MAX_OWNER_COUNT
                || _required > ownerCount
                || _required == 0
                || ownerCount == 0)
                throw;
            _;
        }
    
        /// @dev Fallback function allows to deposit ether.
        function()
            payable
        {
            if (msg.value > 0)
                Deposit(msg.sender, msg.value);
        }
    
        /*
         * Public functions
         */
        /// @dev Contract constructor sets initial owners and required number of confirmations.
        /// @param _owners List of initial owners.
        /// @param _required Number of required confirmations.
        function MultiSigWallet(address[] _owners, uint _required)
            public
            validRequirement(_owners.length, _required)
        {
            for (uint i=0; i<_owners.length; i++) {
                if (isOwner[_owners[i]] || _owners[i] == 0)
                    throw;
                isOwner[_owners[i]] = true;
            }
            owners = _owners;
            required = _required;
        }
    
        /// @dev Allows to add a new owner. Transaction has to be sent by wallet.
        /// @param owner Address of new owner.
        function addOwner(address owner)
            public
            onlyWallet
            ownerDoesNotExist(owner)
            notNull(owner)
            validRequirement(owners.length + 1, required)
        {
            isOwner[owner] = true;
            owners.push(owner);
            OwnerAddition(owner);
        }
    
        /// @dev Allows to remove an owner. Transaction has to be sent by wallet.
        /// @param owner Address of owner.
        function removeOwner(address owner)
            public
            onlyWallet
            ownerExists(owner)
        {
            isOwner[owner] = false;
            for (uint i=0; i<owners.length - 1; i++)
                if (owners[i] == owner) {
                    owners[i] = owners[owners.length - 1];
                    break;
                }
            owners.length -= 1;
            if (required > owners.length)
                changeRequirement(owners.length);
            OwnerRemoval(owner);
        }
    
        /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
        /// @param owner Address of owner to be replaced.
        /// @param newOwner Address of new owner.
        function replaceOwner(address owner, address newOwner)
            public
            onlyWallet
            ownerExists(owner)
            ownerDoesNotExist(newOwner)
        {
            for (uint i=0; i<owners.length; i++)
                if (owners[i] == owner) {
                    owners[i] = newOwner;
                    break;
                }
            isOwner[owner] = false;
            isOwner[newOwner] = true;
            OwnerRemoval(owner);
            OwnerAddition(newOwner);
        }
    
        /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
        /// @param _required Number of required confirmations.
        function changeRequirement(uint _required)
            public
            onlyWallet
            validRequirement(owners.length, _required)
        {
            required = _required;
            RequirementChange(_required);
        }
    
        /// @dev Allows an owner to submit and confirm a transaction.
        /// @param destination Transaction target address.
        /// @param value Transaction ether value.
        /// @param data Transaction data payload.
        /// @return Returns transaction ID.
        function submitTransaction(address destination, uint value, bytes data)
            public
            returns (uint transactionId)
        {
            transactionId = addTransaction(destination, value, data);
            confirmTransaction(transactionId);
        }
    
        /// @dev Allows an owner to confirm a transaction.
        /// @param transactionId Transaction ID.
        function confirmTransaction(uint transactionId)
            public
            ownerExists(msg.sender)
            transactionExists(transactionId)
            notConfirmed(transactionId, msg.sender)
        {
            confirmations[transactionId][msg.sender] = true;
            Confirmation(msg.sender, transactionId);
            executeTransaction(transactionId);
        }
    
        /// @dev Allows an owner to revoke a confirmation for a transaction.
        /// @param transactionId Transaction ID.
        function revokeConfirmation(uint transactionId)
            public
            ownerExists(msg.sender)
            confirmed(transactionId, msg.sender)
            notExecuted(transactionId)
        {
            confirmations[transactionId][msg.sender] = false;
            Revocation(msg.sender, transactionId);
        }
    
        /// @dev Allows anyone to execute a confirmed transaction.
        /// @param transactionId Transaction ID.
        function executeTransaction(uint transactionId)
            public
            ownerExists(msg.sender)
            confirmed(transactionId, msg.sender)
            notExecuted(transactionId)
        {
            if (isConfirmed(transactionId)) {
                Transaction tx = transactions[transactionId];
                tx.executed = true;
                if (tx.destination.call.value(tx.value)(tx.data))
                    Execution(transactionId);
                else {
                    ExecutionFailure(transactionId);
                    tx.executed = false;
                }
            }
        }
    
        /// @dev Returns the confirmation status of a transaction.
        /// @param transactionId Transaction ID.
        /// @return Confirmation status.
        function isConfirmed(uint transactionId)
            public
            constant
            returns (bool)
        {
            uint count = 0;
            for (uint i=0; i<owners.length; i++) {
                if (confirmations[transactionId][owners[i]])
                    count += 1;
                if (count == required)
                    return true;
            }
        }
    
        /*
         * Internal functions
         */
        /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
        /// @param destination Transaction target address.
        /// @param value Transaction ether value.
        /// @param data Transaction data payload.
        /// @return Returns transaction ID.
        function addTransaction(address destination, uint value, bytes data)
            internal
            notNull(destination)
            returns (uint transactionId)
        {
            transactionId = transactionCount;
            transactions[transactionId] = Transaction({
                destination: destination,
                value: value,
                data: data,
                executed: false
            });
            transactionCount += 1;
            Submission(transactionId);
        }
    
        /*
         * Web3 call functions
         */
        /// @dev Returns number of confirmations of a transaction.
        /// @param transactionId Transaction ID.
        /// @return Number of confirmations.
        function getConfirmationCount(uint transactionId)
            public
            constant
            returns (uint count)
        {
            for (uint i=0; i<owners.length; i++)
                if (confirmations[transactionId][owners[i]])
                    count += 1;
        }
    
        /// @dev Returns total number of transactions after filers are applied.
        /// @param pending Include pending transactions.
        /// @param executed Include executed transactions.
        /// @return Total number of transactions after filters are applied.
        function getTransactionCount(bool pending, bool executed)
            public
            constant
            returns (uint count)
        {
            for (uint i=0; i<transactionCount; i++)
                if (   pending && !transactions[i].executed
                    || executed && transactions[i].executed)
                    count += 1;
        }
    
        /// @dev Returns list of owners.
        /// @return List of owner addresses.
        function getOwners()
            public
            constant
            returns (address[])
        {
            return owners;
        }
    
        /// @dev Returns array with owner addresses, which confirmed transaction.
        /// @param transactionId Transaction ID.
        /// @return Returns array of owner addresses.
        function getConfirmations(uint transactionId)
            public
            constant
            returns (address[] _confirmations)
        {
            address[] memory confirmationsTemp = new address[](owners.length);
            uint count = 0;
            uint i;
            for (i=0; i<owners.length; i++)
                if (confirmations[transactionId][owners[i]]) {
                    confirmationsTemp[count] = owners[i];
                    count += 1;
                }
            _confirmations = new address[](count);
            for (i=0; i<count; i++)
                _confirmations[i] = confirmationsTemp[i];
        }
    
        /// @dev Returns list of transaction IDs in defined range.
        /// @param from Index start position of transaction array.
        /// @param to Index end position of transaction array.
        /// @param pending Include pending transactions.
        /// @param executed Include executed transactions.
        /// @return Returns array of transaction IDs.
        function getTransactionIds(uint from, uint to, bool pending, bool executed)
            public
            constant
            returns (uint[] _transactionIds)
        {
            uint[] memory transactionIdsTemp = new uint[](transactionCount);
            uint count = 0;
            uint i;
            for (i=0; i<transactionCount; i++)
                if (   pending && !transactions[i].executed
                    || executed && transactions[i].executed)
                {
                    transactionIdsTemp[count] = i;
                    count += 1;
                }
            _transactionIds = new uint[](to - from);
            for (i=from; i<to; i++)
                _transactionIds[i - from] = transactionIdsTemp[i];
        }
    }