ETH Price: $1,862.24 (-0.57%)

Transaction Decoder

Block:
6018132 at Jul-23-2018 09:58:00 PM +UTC
Transaction Fee:
0.0005159704 ETH $0.96
Gas Used:
234,532 Gas / 2.2 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x4F2d119b...88758BDEF
0x59De2a5C...0FC5fF7b5
0xbc7de2B7...57dCABd7b
0.349036402634259261 Eth
Nonce: 1068
0.348520432234259261 Eth
Nonce: 1069
0.0005159704
(Ethermine)
465.868755640899094079 Eth465.869271611299094079 Eth0.0005159704

Execution Trace

MEAManager.launchShipOnMEA( _assetId=3268, starId=38 ) => ( 1532467186 )
  • CSCPreSaleManager.getCollectibleDetails( _tokenId=3268 ) => ( assetId=3268, sequenceId=32, collectibleType=0, collectibleClass=1, collectibleName=Prometheus Voucher, isRedeemed=False, owner=0xbc7de2B767fA97Ea9D5Ebc05A8d0C8557dCABd7b )
  • 0x4f2d119b1063f75bd2088b80ce288a588758bdef.8ede1817( )
  • 0x4f2d119b1063f75bd2088b80ce288a588758bdef.7f9c8974( )
  • 0x4f2d119b1063f75bd2088b80ce288a588758bdef.51cfa44b( )
  • 0x4f2d119b1063f75bd2088b80ce288a588758bdef.85dc6721( )
  • 0x4f2d119b1063f75bd2088b80ce288a588758bdef.4d15642a( )
    launchShipOnMEA[MEAManager (ln:530)]
    File 1 of 2: MEAManager
    pragma solidity ^0.4.19;
    
    
    
    /// @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens
    /// @author Dieter Shirley <[email protected]> (https://github.com/dete)
    contract CSCERC721 {
      // Required methods
      function balanceOf(address _owner) public view returns (uint256 balance) { 
          return 0;
          
      }
      function ownerOf(uint256 _tokenId) public view returns (address owner) { return;}
    
      function getCollectibleDetails(uint256 _assetId) external view returns(uint256 assetId, uint256 sequenceId, uint256 collectibleType, uint256 collectibleClass, bool isRedeemed, address owner) {
            assetId = 0;
            sequenceId = 0;
            collectibleType = 0;
            collectibleClass = 0;
            owner = 0;
            isRedeemed = false;
      }
    
       function tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) {
            return;
       }
    
    }
    
    contract CSCFactoryERC721 {
        
        function ownerOf(uint256 _tokenId) public view returns (address owner) { return;}
    
        function getCollectibleDetails(uint256 _tokenId) external view returns(uint256 assetId, uint256 sequenceId, uint256 collectibleType, uint256 collectibleClass, bytes32 collectibleName, bool isRedeemed, address owner) {
    
            assetId = 0;
            sequenceId = 0;
            collectibleType = 0;
            collectibleClass = 0;
            owner = 0;
            collectibleName = 0x0;
            isRedeemed = false;
        }
    
        function tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) {
            return;
       }
    }
    
    contract ERC20 {
      function balanceOf(address who) public view returns (uint256);
      function transfer(address to, uint256 value) public returns (bool);
    }
    
    contract CSCResourceFactory {
        mapping(uint16 => address) public resourceIdToAddress; 
    }
    
    
    contract MEAHiddenLogic {
    
    
        function getTotalTonsClaimed() external view returns(uint32) {
            return;
        }
    
        function getTotalSupply() external view returns(uint32) {
            return;
        }
    
         function getStarTotalSupply(uint8 _starId) external view returns(uint32) {
            return;
        }
    
        function getReturnTime(uint256 _assetId) external view returns(uint256 time) {
            return;
        }
    
        //uint256 iron, uint256 quartz, uint256 nickel, uint256 cobalt, uint256 silver, uint256 titanium, uint256 lucinite, uint256 gold, uint256 cosmethyst, uint256 allurum,  uint256 platinum,  uint256 trilite 
        function setResourceForStar(uint8[5] _resourceTypes, uint16[5] _resourcePer, uint32[5] _resourceAmounts) public returns(uint8 starId) {
        }
    
        
        /// @dev Method to fetch collected ore details
        function getAssetCollectedOreBallances(uint256 _assetID) external view returns(uint256 iron, uint256 quartz, uint256 nickel, uint256 cobalt, uint256 silver, uint256 titanium, uint256 lucinite, uint256 gold, uint256 cosmethyst, uint256 allurum,  uint256 platinum,  uint256 trilite);
    
        function getAssetCollectedOreBallancesArray(uint256 _assetID) external view returns(uint256[12] ores);
    
        function emptyShipCargo(uint32 _assetId) external;
    
         /// @dev For creating CSC Collectible
        function startMEAMission(uint256 _assetId, uint256 oreMax, uint8 starId, uint256 _travelTime) public returns(uint256);
    
        
    }
    
    /* Controls state and access rights for contract functions
     * @title Operational Control
     * @author Fazri Zubair & Farhan Khwaja (Lucid Sight, Inc.)
     * Inspired and adapted from contract created by OpenZeppelin
     * Ref: https://github.com/OpenZeppelin/zeppelin-solidity/
     */
    contract OperationalControl {
        // Facilitates access & control for the game.
        // Roles:
        //  -The Managers (Primary/Secondary): Has universal control of all elements (No ability to withdraw)
        //  -The Banker: The Bank can withdraw funds and adjust fees / prices.
        //  -otherManagers: Contracts that need access to functions for gameplay
    
        /// @dev Emited when contract is upgraded
        event ContractUpgrade(address newContract);
    
        /// @dev Emited when other manager is set
        event OtherManagerUpdated(address otherManager, uint256 state);
    
        // The addresses of the accounts (or contracts) that can execute actions within each roles.
        address public managerPrimary;
        address public managerSecondary;
        address public bankManager;
    
        // Contracts that require access for gameplay
        mapping(address => uint8) public otherManagers;
    
        // @dev Keeps track whether the contract is paused. When that is true, most actions are blocked
        bool public paused = false;
    
        // @dev Keeps track whether the contract erroredOut. When that is true, most actions are blocked & refund can be claimed
        bool public error = false;
    
        /// @dev Operation modifiers for limiting access
        modifier onlyManager() {
            require(msg.sender == managerPrimary || msg.sender == managerSecondary);
            _;
        }
    
        modifier onlyBanker() {
            require(msg.sender == bankManager);
            _;
        }
    
        modifier onlyOtherManagers() {
            require(otherManagers[msg.sender] == 1);
            _;
        }
    
    
        modifier anyOperator() {
            require(
                msg.sender == managerPrimary ||
                msg.sender == managerSecondary ||
                msg.sender == bankManager ||
                otherManagers[msg.sender] == 1
            );
            _;
        }
    
        /// @dev Assigns a new address to act as the Other Manager. (State = 1 is active, 0 is disabled)
        function setOtherManager(address _newOp, uint8 _state) external onlyManager {
            require(_newOp != address(0));
    
            otherManagers[_newOp] = _state;
    
            OtherManagerUpdated(_newOp,_state);
        }
    
        /// @dev Assigns a new address to act as the Primary Manager.
        function setPrimaryManager(address _newGM) external onlyManager {
            require(_newGM != address(0));
    
            managerPrimary = _newGM;
        }
    
        /// @dev Assigns a new address to act as the Secondary Manager.
        function setSecondaryManager(address _newGM) external onlyManager {
            require(_newGM != address(0));
    
            managerSecondary = _newGM;
        }
    
        /// @dev Assigns a new address to act as the Banker.
        function setBanker(address _newBK) external onlyManager {
            require(_newBK != address(0));
    
            bankManager = _newBK;
        }
    
        /*** Pausable functionality adapted from OpenZeppelin ***/
    
        /// @dev Modifier to allow actions only when the contract IS NOT paused
        modifier whenNotPaused() {
            require(!paused);
            _;
        }
    
        /// @dev Modifier to allow actions only when the contract IS paused
        modifier whenPaused {
            require(paused);
            _;
        }
    
        /// @dev Modifier to allow actions only when the contract has Error
        modifier whenError {
            require(error);
            _;
        }
    
        /// @dev Called by any Operator role to pause the contract.
        /// Used only if a bug or exploit is discovered (Here to limit losses / damage)
        function pause() external onlyManager whenNotPaused {
            paused = true;
        }
    
        /// @dev Unpauses the smart contract. Can only be called by the Game Master
        /// @notice This is public rather than external so it can be called by derived contracts. 
        function unpause() public onlyManager whenPaused {
            // can't unpause if contract was upgraded
            paused = false;
        }
    
        /// @dev Unpauses the smart contract. Can only be called by the Game Master
        /// @notice This is public rather than external so it can be called by derived contracts. 
        function hasError() public onlyManager whenPaused {
            error = true;
        }
    
        /// @dev Unpauses the smart contract. Can only be called by the Game Master
        /// @notice This is public rather than external so it can be called by derived contracts. 
        function noError() public onlyManager whenPaused {
            error = false;
        }
    }
    
    contract MEAManager is OperationalControl {
    
        /*** EVENTS ***/
    
        /*** CONSTANTS ***/
        uint256 public constant REAPER_INTREPID = 3; 
        uint256 public constant REAPER_INTREPID_EXTRACTION_BASE = 10; // tons per hour of mining
        uint256 public constant REAPER_INTREPID_FTL_SPEED = 900; // Seconds to travel 1 light year
        uint256 public constant REAPER_INTREPID_MAX_CARGO = 320;
    
        uint256 public constant PHOENIX_CORSAIR = 2;
        uint256 public constant PHOENIX_CORSAIR_EXTRACTION_BASE = 40; // tons per hour of mining
        uint256 public constant PHOENIX_CORSAIR_FTL_SPEED = 1440; // Seconds to travel 1 light year
        uint256 public constant PHOENIX_CORSAIR_MAX_CARGO = 1500;
    
        uint256 public constant VULCAN_PROMETHEUS = 1;
        uint256 public constant VULCAN_PROMETHEUS_EXTRACTION_BASE = 300; // tons per hour of mining
        uint256 public constant VULCAN_PROMETHEUS_FTL_SPEED = 2057; // Seconds to travel 1 light year
        uint256 public constant VULCAN_PROMETHEUS_MAX_CARGO = 6000; 
    
        uint256 public constant SIGMA = 4;
        uint256 public constant SIGMA_EXTRACTION_BASE = 150; // tons per hour of mining
        uint256 public constant SIGMA_FTL_SPEED = 4235; // Seconds to travel 1 light year
        uint256 public constant SIGMA_MAX_CARGO = 15000; 
    
        uint256 public constant HAYATO = 5;
        uint256 public constant HAYATO_EXTRACTION_BASE = 150; // tons per hour of mining
        uint256 public constant HAYATO_FTL_SPEED = 360; // Seconds to travel 1 light year
        uint256 public constant HAYATO_MAX_CARGO = 1500; 
    
        uint256 public constant CPGPEREGRINE = 6;
        uint256 public constant CPGPEREGRINE_EXTRACTION_BASE = 150; // tons per hour of mining
        uint256 public constant CPGPEREGRINE_FTL_SPEED = 720; // Seconds to travel 1 light year
        uint256 public constant CPGPEREGRINE_MAX_CARGO = 4000; 
    
        uint256 public constant TACTICALCRUISER = 7;
        uint256 public constant TACTICALCRUISER_EXTRACTION_BASE = 150; // tons per hour of mining
        uint256 public constant TACTICALCRUISER_FTL_SPEED = 720; // Seconds to travel 1 light year
        uint256 public constant TACTICALCRUISER_MAX_CARGO = 1000;
    
        uint256 public constant OTHERCRUISER = 8;
        uint256 public constant OTHERCRUISER_EXTRACTION_BASE = 100; // tons per hour of mining
        uint256 public constant OTHERCRUISER_FTL_SPEED = 720; // Seconds to travel 1 light year
        uint256 public constant OTHERCRUISER_MAX_CARGO = 1500;  
    
        uint256 public constant VULCAN_POD = 9;
        uint256 public constant VULCAN_POD_EXTRACTION_BASE = 1; // tons per hour of mining
        uint256 public constant VULCAN_POD_FTL_SPEED = 2000; // Seconds to travel 1 light year
        uint256 public constant VULCAN_POD_MAX_CARGO = 75;  
    
        //For Devs to Travel Around
        uint256 public constant DEVCLASS = 99;
        uint256 public constant DEVCLASS_EXTRACTION_BASE = 50; // tons per hour of mining
        uint256 public constant DEVCLASS_FTL_SPEED = 10; // Seconds to travel 1 light year
        uint256 public constant DEVCLASS_MAX_CARGO = 500; 
        
        /// @notice Name and symbol of the non fungible token, as defined in ERC721.
        string public constant NAME = "MEAGameManager";
    
        /*** Mappings ***/
    
         /// @dev assetID to ore type to qty collected
        mapping(uint32 => mapping(uint8 => uint32)) public collectedOreAssetMapping;
    
        /// @dev owner address to ore type to qty collected
        mapping(address => mapping(uint8 => uint32)) public collectedOreBalanceMapping;
    
        /// @dev owner address to ore type to qty collected
        mapping(address => mapping(uint8 => uint32)) public distributedOreBalanceMapping;
    
        /// @dev assetID to number of MEA trips it has completed
        mapping(uint32 => uint32) public assetIdNumberOfTripsMapping;
    
        /// @dev assetID to ore type to qty collected
        mapping(uint8 => uint16) public starLightyearDistanceMapping;
    
        /// @dev assetID to last star visited
        mapping(uint32 => uint8) public assetIdToStarVisitedMapping;
    
        /// @dev assetID to last star visited
        mapping(uint16 => address) public resourceERC20Address;
    
        /// @dev assetID to Start Time of Current Trip
        mapping(uint32 => uint32) public assetIdCurrentTripStartTimeMapping;
    
    
        /*** Variables ***/
        uint256 public miningTimePerTrip = 3600; // 3600 for 1 hour 10
        uint256 public aimeIncreasePerTrip = 2500; // 25.00
    
        address cscERC721Address;
        address cscFactoryERC721Address;
        address hiddenLogicAddress;
     
    
        function MEAManager() public {
            require(msg.sender != address(0));
            paused = true; 
            managerPrimary = msg.sender;
            managerSecondary = msg.sender;
            bankManager = msg.sender;
            cscERC721Address = address(0xe4f5e0d5c033f517a943602df942e794a06bc123);
            cscFactoryERC721Address = address(0xcc9a66acf8574141b0e025202dd57649765a4be7);
        }
    
        /*** Management Functions ***/
    
        /// @dev Set HiddenLogic
        function setHiddenLogic(address _hiddenLogicAddress) public onlyManager {
            hiddenLogicAddress = _hiddenLogicAddress;
        }
    
        /// @dev Set HiddenLogic
        function setResourceERC20Address(uint16 _resId, address _reourceAddress) public onlyManager {
            resourceERC20Address[_resId] = _reourceAddress;
        }
    
        /// @dev Set HiddenLogic
        function setAllResourceERC20Addresses(address _master) public onlyManager {
            CSCResourceFactory factory = CSCResourceFactory(_master);
            for(uint8 i = 0; i < 12; i++) {
                resourceERC20Address[i] = factory.resourceIdToAddress(i);
            }
        }
    
        /// @dev Set CSCErc721 Contract
        function setCSCERC721(address _cscERC721Address) public onlyManager {
            cscERC721Address = _cscERC721Address;
        }
    
         /// @dev Set CSCFactoryErc721 Contract
        function setCSCFactoryERC721(address _cscFactoryERC721Address) public onlyManager {
            cscFactoryERC721Address = _cscFactoryERC721Address;
        }
    
        /// @dev Set / Modify Lightyear Distance 3.456 ly = 3456
        function setStarDistance(uint8 _starId, uint16 _lightyearsInThousands) public anyOperator {
            starLightyearDistanceMapping[_starId] = _lightyearsInThousands;
        }
    
        /// @dev Set / Modify MEA Game Attributes
        function setMEAAttributes(uint256 _aime, uint256 _miningTime) public onlyManager {
            aimeIncreasePerTrip = _aime;
            miningTimePerTrip = _miningTime;
        }
    
        /// @dev Withdraw Remaining Resource Tokens
        function reclaimResourceDeposits(address _withdrawAddress) public onlyManager {
            require(_withdrawAddress != address(0));
            for(uint8 ii = 0; ii < 12; ii++) {
                if(resourceERC20Address[ii] != 0) {
                    ERC20 resCont = ERC20(resourceERC20Address[ii]);
                    uint256 bal = resCont.balanceOf(this);
                    resCont.transfer(_withdrawAddress, bal);
                }
            }
        }
    
        /*** Public Functions ***/
    
         /// @dev Get Current Cargo Hold of AssetId (item names)
        function getAssetIdCargo(uint32 _assetId) public view returns(uint256 iron, uint256 quartz, uint256 nickel, uint256 cobalt, uint256 silver, uint256 titanium, uint256 lucinite, uint256 gold, uint256 cosmethyst, uint256 allurum,  uint256 platinum,  uint256 trilite) {
            uint256[12] memory _ores = getAssetIdCargoArray(_assetId);
            iron = _ores[0];
            quartz = _ores[1];
            nickel = _ores[2];
            cobalt = _ores[3];
            silver = _ores[4];
            titanium = _ores[5];
            lucinite = _ores[6];
            gold = _ores[7];
            cosmethyst = _ores[8];
            allurum = _ores[9];
            platinum = _ores[10];
            trilite = _ores[11];
        }
    
        // function getAllShipStats(uint32[] _shipIds) public view returns(uint32[] results) {
        //     //loop all results
        //     for(uint i = 0; i < _shipIds.length; i++) {
        //         results[]];
        //     }
    
        // }
    
        /// @dev Get Current Cargo Hold of AssetId (array)
        function getAssetIdCargoArray (uint32 _assetId) public view returns(uint256[12])  {
            MEAHiddenLogic logic = MEAHiddenLogic(hiddenLogicAddress);
            return logic.getAssetCollectedOreBallancesArray(_assetId);
        }
    
        /// @dev Get AssetId Trip Completed Time
        function getAssetIdTripCompletedTime(uint256 _assetId) external view returns(uint256 time) {
            MEAHiddenLogic logic = MEAHiddenLogic(hiddenLogicAddress);
            return logic.getReturnTime(uint32(_assetId));
        }
    
        /// @dev Get AssetId Trip Completed Time
        function getAssetIdTripStartTime(uint256 _assetId) external view returns(uint256 time) {
    
            return assetIdCurrentTripStartTimeMapping[uint32(_assetId)];
        }
    
        function getLastStarOfAssetId(uint32 _assetId) public view returns(uint8 starId){
            return assetIdToStarVisitedMapping[_assetId];
        }
    
        /// @dev Get Resource Address
        function getResourceERC20Address(uint16 _resId) public view returns(address resourceContract) {
            return resourceERC20Address[_resId];
        }
    
        /// @dev Get Time
        function getMEATime() external view returns(uint256 time) {
            return now;
        }
    
        /// @dev Method to fetch processed ore details
        function getCollectedOreBalances(address _owner) external view returns(uint256 iron, uint256 quartz, uint256 nickel, uint256 cobalt, uint256 silver, uint256 titanium, uint256 lucinite, uint256 gold, uint256 cosmethyst, uint256 allurum,  uint256 platinum,  uint256 trilite) {
    
            iron = collectedOreBalanceMapping[_owner][0];
            quartz = collectedOreBalanceMapping[_owner][1];
            nickel = collectedOreBalanceMapping[_owner][2];
            cobalt = collectedOreBalanceMapping[_owner][3];
            silver = collectedOreBalanceMapping[_owner][4];
            titanium = collectedOreBalanceMapping[_owner][5];
            lucinite = collectedOreBalanceMapping[_owner][6];
            gold = collectedOreBalanceMapping[_owner][7];
            cosmethyst = collectedOreBalanceMapping[_owner][8];
            allurum = collectedOreBalanceMapping[_owner][9];
            platinum = collectedOreBalanceMapping[_owner][10];
            trilite = collectedOreBalanceMapping[_owner][11];
        }
    
        /// @dev Method to fetch processed ore details
        function getDistributedOreBalances(address _owner) external view returns(uint256 iron, uint256 quartz, uint256 nickel, uint256 cobalt, uint256 silver, uint256 titanium, uint256 lucinite, uint256 gold, uint256 cosmethyst, uint256 allurum,  uint256 platinum,  uint256 trilite) {
    
            iron = distributedOreBalanceMapping[_owner][0];
            quartz = distributedOreBalanceMapping[_owner][1];
            nickel = distributedOreBalanceMapping[_owner][2];
            cobalt = distributedOreBalanceMapping[_owner][3];
            silver = distributedOreBalanceMapping[_owner][4];
            titanium = distributedOreBalanceMapping[_owner][5];
            lucinite = distributedOreBalanceMapping[_owner][6];
            gold = distributedOreBalanceMapping[_owner][7];
            cosmethyst = distributedOreBalanceMapping[_owner][8];
            allurum = distributedOreBalanceMapping[_owner][9];
            platinum = distributedOreBalanceMapping[_owner][10];
            trilite = distributedOreBalanceMapping[_owner][11];
        }
    
        function withdrawCollectedResources() public {
    
            for(uint8 ii = 0; ii < 12; ii++) {
                require(resourceERC20Address[ii] != address(0));
                uint32 oreOutstanding = collectedOreBalanceMapping[msg.sender][ii] - distributedOreBalanceMapping[msg.sender][ii];
                if(oreOutstanding > 0) {
                    ERC20 resCont = ERC20(resourceERC20Address[ii]);
                    distributedOreBalanceMapping[msg.sender][ii] += oreOutstanding;
                    resCont.transfer(msg.sender, oreOutstanding);
                }
            }
    
        }
    
        //Gets star distance in thousandths of ly
        function getStarDistanceInLyThousandths(uint8 _starId) public view returns (uint32 total) {
            return starLightyearDistanceMapping[_starId];
        }
        
        //Gets total resources already claimed by commanders
        function totalMEATonsClaimed() public view returns (uint32 total) {
            MEAHiddenLogic logic = MEAHiddenLogic(hiddenLogicAddress);
            return logic.getTotalTonsClaimed();
        }
    
        //Gets total seeded supply commanders
        function totalMEATonsSupply() public view returns (uint32 total) {
            MEAHiddenLogic logic = MEAHiddenLogic(hiddenLogicAddress);
            return logic.getTotalSupply();
        }
    
         function totalStarSupplyRemaining(uint8 _starId) external view returns(uint32) {
            MEAHiddenLogic logic = MEAHiddenLogic(hiddenLogicAddress);
            return logic.getStarTotalSupply(_starId);
        }
    
        function claimOreOnlyFromAssetId(uint256 _assetId) {
            uint256 collectibleClass = 0;
            address shipOwner;
            (collectibleClass, shipOwner) = _getShipInfo(_assetId);
    
             require(shipOwner == msg.sender);
    
            _claimOreAndClear(uint32(_assetId), 0);
        }
        /// @dev For creating CSC Collectible
        function launchShipOnMEA(uint256 _assetId, uint8 starId) public whenNotPaused returns(uint256) {
            
            MEAHiddenLogic logic = MEAHiddenLogic(hiddenLogicAddress);
    
            uint256 collectibleClass = 0;
            address shipOwner;
    
            (collectibleClass, shipOwner) = _getShipInfo(_assetId);
    
            //Check if the ship owner is sender
            require(shipOwner == msg.sender);
    
            //Check if ship is back at earth
            require(now > logic.getReturnTime(_assetId));
            
            //Claims ore and clears
            _claimOreAndClear(uint32(_assetId), starId);
    
            //Get Asset Stats
            uint tripCount = assetIdNumberOfTripsMapping[uint32(_assetId)];
            uint starTripDist = starLightyearDistanceMapping[starId];
            uint256 oreMax = 5;
            uint256 tripSeconds = 10;
    
            if(collectibleClass == REAPER_INTREPID) {
                oreMax = REAPER_INTREPID_EXTRACTION_BASE + (REAPER_INTREPID_EXTRACTION_BASE * tripCount * aimeIncreasePerTrip / 10000);
                tripSeconds = REAPER_INTREPID_FTL_SPEED * starTripDist / 1000; // 4LPH - 900 seconds per light year
                if(oreMax > REAPER_INTREPID_MAX_CARGO)
                    oreMax = REAPER_INTREPID_MAX_CARGO;
            }
            else if(collectibleClass == PHOENIX_CORSAIR) {
                oreMax = PHOENIX_CORSAIR_EXTRACTION_BASE + (PHOENIX_CORSAIR_EXTRACTION_BASE * tripCount * aimeIncreasePerTrip / 10000);
                tripSeconds = PHOENIX_CORSAIR_FTL_SPEED * starTripDist / 1000; // 2.5LPH - 1440 seconds per light year
                if(oreMax > PHOENIX_CORSAIR_MAX_CARGO)
                    oreMax = PHOENIX_CORSAIR_MAX_CARGO;
            }
            else if(collectibleClass == VULCAN_PROMETHEUS) {
                oreMax = VULCAN_PROMETHEUS_EXTRACTION_BASE + (VULCAN_PROMETHEUS_EXTRACTION_BASE * tripCount * aimeIncreasePerTrip / 10000);
                tripSeconds = VULCAN_PROMETHEUS_FTL_SPEED * starTripDist / 1000; // 1.75LPH - 2057 seconds per light year
                if(oreMax > VULCAN_PROMETHEUS_MAX_CARGO)
                    oreMax = VULCAN_PROMETHEUS_MAX_CARGO;
            }
            else if(collectibleClass == SIGMA) {
                oreMax = SIGMA_EXTRACTION_BASE + (SIGMA_EXTRACTION_BASE * tripCount * aimeIncreasePerTrip / 10000);
                tripSeconds = SIGMA_FTL_SPEED * starTripDist / 1000; // 0.85LPH - 4235 seconds per light year
                if(oreMax > SIGMA_MAX_CARGO)
                    oreMax = SIGMA_MAX_CARGO;
            }
            else if(collectibleClass == HAYATO) { //Hayato
                oreMax = HAYATO_EXTRACTION_BASE + (HAYATO_EXTRACTION_BASE * tripCount * aimeIncreasePerTrip / 10000);
                tripSeconds = HAYATO_FTL_SPEED * starTripDist / 1000; // 10LPH - 360 seconds per light year
                if(oreMax > HAYATO_MAX_CARGO)
                    oreMax = HAYATO_MAX_CARGO;
            }
            else if(collectibleClass == CPGPEREGRINE) { //CPG Peregrine
                oreMax = CPGPEREGRINE_EXTRACTION_BASE + (CPGPEREGRINE_EXTRACTION_BASE * tripCount * aimeIncreasePerTrip / 10000);
                tripSeconds = CPGPEREGRINE_FTL_SPEED * starTripDist / 1000; // 5LPH -720 seconds per light year
                if(oreMax > CPGPEREGRINE_MAX_CARGO)
                    oreMax = CPGPEREGRINE_MAX_CARGO;
            }
            else if(collectibleClass == TACTICALCRUISER) { //TACTICA CRUISER Ships
                oreMax = TACTICALCRUISER_EXTRACTION_BASE + (TACTICALCRUISER_EXTRACTION_BASE * tripCount * aimeIncreasePerTrip / 10000);
                tripSeconds = TACTICALCRUISER_FTL_SPEED * starTripDist / 1000; 
                if(oreMax > TACTICALCRUISER_MAX_CARGO)
                    oreMax = TACTICALCRUISER_MAX_CARGO;
            }
            else if(collectibleClass == VULCAN_POD) { //TACTICA CRUISER Ships
                oreMax = VULCAN_POD_EXTRACTION_BASE + (VULCAN_POD_EXTRACTION_BASE * tripCount * aimeIncreasePerTrip / 10000);
                tripSeconds = VULCAN_POD_FTL_SPEED * starTripDist / 1000; 
                if(oreMax > VULCAN_POD_MAX_CARGO)
                    oreMax = VULCAN_POD_MAX_CARGO;
            }
            else if(collectibleClass >= DEVCLASS) { //Dev Ships
                oreMax = DEVCLASS_EXTRACTION_BASE + (DEVCLASS_EXTRACTION_BASE * tripCount * aimeIncreasePerTrip / 10000);
                tripSeconds = DEVCLASS_FTL_SPEED * starTripDist / 1000;
                if(oreMax > DEVCLASS_MAX_CARGO)
                    oreMax = DEVCLASS_MAX_CARGO;
            } else {
                if(collectibleClass >= OTHERCRUISER) { //Support Other Promo Ships
                    oreMax = OTHERCRUISER_EXTRACTION_BASE + (OTHERCRUISER_EXTRACTION_BASE * tripCount * aimeIncreasePerTrip / 10000);
                    tripSeconds = OTHERCRUISER_FTL_SPEED * starTripDist / 1000; 
                    if(oreMax > OTHERCRUISER_MAX_CARGO)
                        oreMax = OTHERCRUISER_MAX_CARGO;
                }
            }
    
            //Make Round Trip + Mining
            tripSeconds = ((tripSeconds * 2) + miningTimePerTrip); //3600 for an hour - 0 for testing ***************************
    
            //calculate travel time
            uint256 returnTime = logic.startMEAMission(_assetId, oreMax, starId, tripSeconds);
    
            //Confirm trip
            if(returnTime > 0) {
                assetIdNumberOfTripsMapping[uint32(_assetId)] += 1;
                assetIdToStarVisitedMapping[uint32(_assetId)] = starId;
                assetIdCurrentTripStartTimeMapping[uint32(_assetId)] = uint32(now);
            }
            
            return returnTime;
        }
    
    
        /*** PRIVATE FUNCTIONS ***/
    
        /// @dev  Safety check on _to address to prevent against an unexpected 0x0 default.
        function _addressNotNull(address _to) internal pure returns (bool) {
            return _to != address(0);
        }
    
        /// @dev  Claims and clears cargo -- ONLY INTERNAL
        function _claimOreAndClear (uint32 _assetId, uint8 _starId) internal {
            MEAHiddenLogic logic = MEAHiddenLogic(hiddenLogicAddress);
            uint256[12] memory _ores = logic.getAssetCollectedOreBallancesArray(_assetId);
            bool hasItems = false;
    
            for(uint8 i = 0; i < 12; i++) {
                if(_ores[i] > 0) {
                    collectedOreBalanceMapping[msg.sender][i] += uint32(_ores[i]);
                    hasItems = true;
                }
            }
    
            //Doesn't Let you Travel to empty stars but lets you collect
            if(hasItems == false && _starId > 0) {
                require(logic.getStarTotalSupply(_starId) > 0);
            }
    
            logic.emptyShipCargo(_assetId);
        }
    
        function _getShipInfo(uint256 _assetId) internal view returns (uint256 collectibleClass, address owner) {
            
            uint256 nulldata;
            bool nullbool;
            uint256 collectibleType;
    
            if(_assetId <= 3000) {
                CSCERC721 shipData = CSCERC721(cscERC721Address);
                (nulldata, nulldata, collectibleType, collectibleClass, nullbool, owner) = shipData.getCollectibleDetails(_assetId);
            } else {
                bytes32 nullstring;
                CSCFactoryERC721 shipFData = CSCFactoryERC721(cscFactoryERC721Address);
                (nulldata, nulldata, collectibleType, collectibleClass, nullstring, nullbool, owner) = shipFData.getCollectibleDetails(_assetId);
            }
    
        }
    
        
        
        
        
    }

    File 2 of 2: CSCPreSaleManager
    pragma solidity ^0.4.19;
    
    /* Adapted from strings.sol created by Nick Johnson <[email protected]>
     * Ref: https://github.com/Arachnid/solidity-stringutils/blob/2f6ca9accb48ae14c66f1437ec50ed19a0616f78/strings.sol
     * @title String & slice utility library for Solidity contracts.
     * @author Nick Johnson <[email protected]>
     */
    library strings {
        
        struct slice {
            uint _len;
            uint _ptr;
        }
    
        /*
         * @dev Returns a slice containing the entire string.
         * @param self The string to make a slice from.
         * @return A newly allocated slice containing the entire string.
         */
        function toSlice(string self) internal pure returns (slice) {
            uint ptr;
            assembly {
                ptr := add(self, 0x20)
            }
            return slice(bytes(self).length, ptr);
        }
    
        function memcpy(uint dest, uint src, uint len) private pure {
            // Copy word-length chunks while possible
            for(; len >= 32; len -= 32) {
                assembly {
                    mstore(dest, mload(src))
                }
                dest += 32;
                src += 32;
            }
    
            // Copy remaining bytes
            uint mask = 256 ** (32 - len) - 1;
            assembly {
                let srcpart := and(mload(src), not(mask))
                let destpart := and(mload(dest), mask)
                mstore(dest, or(destpart, srcpart))
            }
        }
    
        
        function concat(slice self, slice other) internal returns (string) {
            var ret = new string(self._len + other._len);
            uint retptr;
            assembly { retptr := add(ret, 32) }
            memcpy(retptr, self._ptr, self._len);
            memcpy(retptr + self._len, other._ptr, other._len);
            return ret;
        }
    
        /*
         * @dev Counts the number of nonoverlapping occurrences of `needle` in `self`.
         * @param self The slice to search.
         * @param needle The text to search for in `self`.
         * @return The number of occurrences of `needle` found in `self`.
         */
        function count(slice self, slice needle) internal returns (uint cnt) {
            uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr) + needle._len;
            while (ptr <= self._ptr + self._len) {
                cnt++;
                ptr = findPtr(self._len - (ptr - self._ptr), ptr, needle._len, needle._ptr) + needle._len;
            }
        }
    
        // Returns the memory address of the first byte of the first occurrence of
        // `needle` in `self`, or the first byte after `self` if not found.
        function findPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private returns (uint) {
            uint ptr;
            uint idx;
    
            if (needlelen <= selflen) {
                if (needlelen <= 32) {
                    // Optimized assembly for 68 gas per byte on short strings
                    assembly {
                        let mask := not(sub(exp(2, mul(8, sub(32, needlelen))), 1))
                        let needledata := and(mload(needleptr), mask)
                        let end := add(selfptr, sub(selflen, needlelen))
                        ptr := selfptr
                        loop:
                        jumpi(exit, eq(and(mload(ptr), mask), needledata))
                        ptr := add(ptr, 1)
                        jumpi(loop, lt(sub(ptr, 1), end))
                        ptr := add(selfptr, selflen)
                        exit:
                    }
                    return ptr;
                } else {
                    // For long needles, use hashing
                    bytes32 hash;
                    assembly { hash := sha3(needleptr, needlelen) }
                    ptr = selfptr;
                    for (idx = 0; idx <= selflen - needlelen; idx++) {
                        bytes32 testHash;
                        assembly { testHash := sha3(ptr, needlelen) }
                        if (hash == testHash)
                            return ptr;
                        ptr += 1;
                    }
                }
            }
            return selfptr + selflen;
        }
    
        /*
         * @dev Splits the slice, setting `self` to everything after the first
         *      occurrence of `needle`, and `token` to everything before it. If
         *      `needle` does not occur in `self`, `self` is set to the empty slice,
         *      and `token` is set to the entirety of `self`.
         * @param self The slice to split.
         * @param needle The text to search for in `self`.
         * @param token An output parameter to which the first token is written.
         * @return `token`.
         */
        function split(slice self, slice needle, slice token) internal returns (slice) {
            uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
            token._ptr = self._ptr;
            token._len = ptr - self._ptr;
            if (ptr == self._ptr + self._len) {
                // Not found
                self._len = 0;
            } else {
                self._len -= token._len + needle._len;
                self._ptr = ptr + needle._len;
            }
            return token;
        }
    
         /*
         * @dev Splits the slice, setting `self` to everything after the first
         *      occurrence of `needle`, and returning everything before it. If
         *      `needle` does not occur in `self`, `self` is set to the empty slice,
         *      and the entirety of `self` is returned.
         * @param self The slice to split.
         * @param needle The text to search for in `self`.
         * @return The part of `self` up to the first occurrence of `delim`.
         */
        function split(slice self, slice needle) internal returns (slice token) {
            split(self, needle, token);
        }
    
        /*
         * @dev Copies a slice to a new string.
         * @param self The slice to copy.
         * @return A newly allocated string containing the slice's text.
         */
        function toString(slice self) internal pure returns (string) {
            var ret = new string(self._len);
            uint retptr;
            assembly { retptr := add(ret, 32) }
    
            memcpy(retptr, self._ptr, self._len);
            return ret;
        }
    
    }
    
    /* Helper String Functions for Game Manager Contract
     * @title String Healpers
     * @author Fazri Zubair & Farhan Khwaja (Lucid Sight, Inc.)
     */
    contract StringHelpers {
        using strings for *;
        
        function stringToBytes32(string memory source) internal returns (bytes32 result) {
            bytes memory tempEmptyStringTest = bytes(source);
            if (tempEmptyStringTest.length == 0) {
                return 0x0;
            }
        
            assembly {
                result := mload(add(source, 32))
            }
        }
    
        function bytes32ToString(bytes32 x) constant internal returns (string) {
            bytes memory bytesString = new bytes(32);
            uint charCount = 0;
            for (uint j = 0; j < 32; j++) {
                byte char = byte(bytes32(uint(x) * 2 ** (8 * j)));
                if (char != 0) {
                    bytesString[charCount] = char;
                    charCount++;
                }
            }
            bytes memory bytesStringTrimmed = new bytes(charCount);
            for (j = 0; j < charCount; j++) {
                bytesStringTrimmed[j] = bytesString[j];
            }
            return string(bytesStringTrimmed);
        }
    }
    
    /// @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens
    /// @author Dieter Shirley <[email protected]> (https://github.com/dete)
    contract ERC721 {
      // Required methods
      function balanceOf(address _owner) public view returns (uint256 balance);
      function ownerOf(uint256 _tokenId) public view returns (address owner);
      function approve(address _to, uint256 _tokenId) public;
      function transfer(address _to, uint256 _tokenId) public;
      function transferFrom(address _from, address _to, uint256 _tokenId) public;
      function implementsERC721() public pure returns (bool);
      function takeOwnership(uint256 _tokenId) public;
      function totalSupply() public view returns (uint256 total);
    
      event Transfer(address indexed from, address indexed to, uint256 tokenId);
      event Approval(address indexed owner, address indexed approved, uint256 tokenId);
    
      // Optional
      // function name() public view returns (string name);
      // function symbol() public view returns (string symbol);
      // function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256 tokenId);
      // function tokenMetadata(uint256 _tokenId) public view returns (string infoUrl);
    
      // ERC-165 Compatibility (https://github.com/ethereum/EIPs/issues/165)
      function supportsInterface(bytes4 _interfaceID) external view returns (bool);
    }
    
    /* Controls state and access rights for contract functions
     * @title Operational Control
     * @author Fazri Zubair & Farhan Khwaja (Lucid Sight, Inc.)
     * Inspired and adapted from contract created by OpenZeppelin
     * Ref: https://github.com/OpenZeppelin/zeppelin-solidity/
     */
    contract OperationalControl {
        // Facilitates access & control for the game.
        // Roles:
        //  -The Managers (Primary/Secondary): Has universal control of all elements (No ability to withdraw)
        //  -The Banker: The Bank can withdraw funds and adjust fees / prices.
    
        /// @dev Emited when contract is upgraded
        event ContractUpgrade(address newContract);
    
        // The addresses of the accounts (or contracts) that can execute actions within each roles.
        address public managerPrimary;
        address public managerSecondary;
        address public bankManager;
    
        // @dev Keeps track whether the contract is paused. When that is true, most actions are blocked
        bool public paused = false;
    
        // @dev Keeps track whether the contract erroredOut. When that is true, most actions are blocked & refund can be claimed
        bool public error = false;
    
        /// @dev Operation modifiers for limiting access
        modifier onlyManager() {
            require(msg.sender == managerPrimary || msg.sender == managerSecondary);
            _;
        }
    
        modifier onlyBanker() {
            require(msg.sender == bankManager);
            _;
        }
    
        modifier anyOperator() {
            require(
                msg.sender == managerPrimary ||
                msg.sender == managerSecondary ||
                msg.sender == bankManager
            );
            _;
        }
    
        /// @dev Assigns a new address to act as the Primary Manager.
        function setPrimaryManager(address _newGM) external onlyManager {
            require(_newGM != address(0));
    
            managerPrimary = _newGM;
        }
    
        /// @dev Assigns a new address to act as the Secondary Manager.
        function setSecondaryManager(address _newGM) external onlyManager {
            require(_newGM != address(0));
    
            managerSecondary = _newGM;
        }
    
        /// @dev Assigns a new address to act as the Banker.
        function setBanker(address _newBK) external onlyManager {
            require(_newBK != address(0));
    
            bankManager = _newBK;
        }
    
        /*** Pausable functionality adapted from OpenZeppelin ***/
    
        /// @dev Modifier to allow actions only when the contract IS NOT paused
        modifier whenNotPaused() {
            require(!paused);
            _;
        }
    
        /// @dev Modifier to allow actions only when the contract IS paused
        modifier whenPaused {
            require(paused);
            _;
        }
    
        /// @dev Modifier to allow actions only when the contract has Error
        modifier whenError {
            require(error);
            _;
        }
    
        /// @dev Called by any Operator role to pause the contract.
        /// Used only if a bug or exploit is discovered (Here to limit losses / damage)
        function pause() external onlyManager whenNotPaused {
            paused = true;
        }
    
        /// @dev Unpauses the smart contract. Can only be called by the Game Master
        /// @notice This is public rather than external so it can be called by derived contracts. 
        function unpause() public onlyManager whenPaused {
            // can't unpause if contract was upgraded
            paused = false;
        }
    
        /// @dev Unpauses the smart contract. Can only be called by the Game Master
        /// @notice This is public rather than external so it can be called by derived contracts. 
        function hasError() public onlyManager whenPaused {
            error = true;
        }
    
        /// @dev Unpauses the smart contract. Can only be called by the Game Master
        /// @notice This is public rather than external so it can be called by derived contracts. 
        function noError() public onlyManager whenPaused {
            error = false;
        }
    }
    
    contract CSCPreSaleItemBase is ERC721, OperationalControl, StringHelpers {
    
        /*** EVENTS ***/
        /// @dev The Created event is fired whenever a new collectible comes into existence.
        event CollectibleCreated(address owner, uint256 globalId, uint256 collectibleType, uint256 collectibleClass, uint256 sequenceId, bytes32 collectibleName);
        
        /*** CONSTANTS ***/
        
        /// @notice Name and symbol of the non fungible token, as defined in ERC721.
        string public constant NAME = "CSCPreSaleFactory";
        string public constant SYMBOL = "CSCPF";
        bytes4 constant InterfaceSignature_ERC165 = bytes4(keccak256('supportsInterface(bytes4)'));
        bytes4 constant InterfaceSignature_ERC721 =
            bytes4(keccak256('name()')) ^
            bytes4(keccak256('symbol()')) ^
            bytes4(keccak256('totalSupply()')) ^
            bytes4(keccak256('balanceOf(address)')) ^
            bytes4(keccak256('ownerOf(uint256)')) ^
            bytes4(keccak256('approve(address,uint256)')) ^
            bytes4(keccak256('transfer(address,uint256)')) ^
            bytes4(keccak256('transferFrom(address,address,uint256)')) ^
            bytes4(keccak256('tokensOfOwner(address)')) ^
            bytes4(keccak256('tokenMetadata(uint256,string)'));
        
        /// @dev CSC Pre Sale Struct, having details of the collectible
        struct CSCPreSaleItem {
        
            /// @dev sequence ID i..e Local Index
            uint256 sequenceId;
            
            /// @dev name of the collectible stored in bytes
            bytes32 collectibleName;
            
            /// @dev Collectible Type
            uint256 collectibleType;
            
            /// @dev Collectible Class
            uint256 collectibleClass;
            
            /// @dev owner address
            address owner;
            
            /// @dev redeemed flag (to help whether it got redeemed or not)
            bool isRedeemed;
        }
        
        /// @dev array of CSCPreSaleItem type holding information on the Collectibles Created
        CSCPreSaleItem[] allPreSaleItems;
        
        /// @dev Max Count for preSaleItem type -> preSaleItem class -> max. limit
        mapping(uint256 => mapping(uint256 => uint256)) public preSaleItemTypeToClassToMaxLimit;
        
        /// @dev Map from preSaleItem type -> preSaleItem class -> max. limit set (bool)
        mapping(uint256 => mapping(uint256 => bool)) public preSaleItemTypeToClassToMaxLimitSet;
    
        /// @dev Map from preSaleItem type -> preSaleItem class -> Name (string / bytes32)
        mapping(uint256 => mapping(uint256 => bytes32)) public preSaleItemTypeToClassToName;
        
        // @dev mapping which holds all the possible addresses which are allowed to interact with the contract
        mapping (address => bool) approvedAddressList;
        
        // @dev mapping holds the preSaleItem -> owner details
        mapping (uint256 => address) public preSaleItemIndexToOwner;
        
        // @dev A mapping from owner address to count of tokens that address owns.
        //  Used internally inside balanceOf() to resolve ownership count.
        mapping (address => uint256) private ownershipTokenCount;
        
        /// @dev A mapping from preSaleItem to an address that has been approved to call
        ///  transferFrom(). Each Collectible can only have one approved address for transfer
        ///  at any time. A zero value means no approval is outstanding.
        mapping (uint256 => address) public preSaleItemIndexToApproved;
        
        /// @dev A mapping of preSaleItem Type to Type Sequence Number to Collectible
        mapping (uint256 => mapping (uint256 => mapping ( uint256 => uint256 ) ) ) public preSaleItemTypeToSequenceIdToCollectible;
        
        /// @dev A mapping from Pre Sale Item Type IDs to the Sequqence Number .
        mapping (uint256 => mapping ( uint256 => uint256 ) ) public preSaleItemTypeToCollectibleCount;
    
        /// @dev Token Starting Index taking into account the old presaleContract total assets that can be generated
        uint256 public STARTING_ASSET_BASE = 3000;
        
        /// @notice Introspection interface as per ERC-165 (https://github.com/ethereum/EIPs/issues/165).
        ///  Returns true for any standardized interfaces implemented by this contract. We implement
        ///  ERC-165 (obviously!) and ERC-721.
        function supportsInterface(bytes4 _interfaceID) external view returns (bool)
        {
            // DEBUG ONLY
            //require((InterfaceSignature_ERC165 == 0x01ffc9a7) && (InterfaceSignature_ERC721 == 0x9a20483d));
            return ((_interfaceID == InterfaceSignature_ERC165) || (_interfaceID == InterfaceSignature_ERC721));
        }
        
        function setMaxLimit(string _collectibleName, uint256 _collectibleType, uint256 _collectibleClass, uint256 _maxLimit) external onlyManager whenNotPaused {
            require(_maxLimit > 0);
            require(_collectibleType >= 0 && _collectibleClass >= 0);
            require(stringToBytes32(_collectibleName) != stringToBytes32(""));
    
            require(!preSaleItemTypeToClassToMaxLimitSet[_collectibleType][_collectibleClass]);
            preSaleItemTypeToClassToMaxLimit[_collectibleType][_collectibleClass] = _maxLimit;
            preSaleItemTypeToClassToMaxLimitSet[_collectibleType][_collectibleClass] = true;
            preSaleItemTypeToClassToName[_collectibleType][_collectibleClass] = stringToBytes32(_collectibleName);
        }
        
        /// @dev Method to fetch collectible details
        function getCollectibleDetails(uint256 _tokenId) external view returns(uint256 assetId, uint256 sequenceId, uint256 collectibleType, uint256 collectibleClass, string collectibleName, bool isRedeemed, address owner) {
    
            require (_tokenId > STARTING_ASSET_BASE);
            uint256 generatedCollectibleId = _tokenId - STARTING_ASSET_BASE;
            
            CSCPreSaleItem memory _Obj = allPreSaleItems[generatedCollectibleId];
            assetId = _tokenId;
            sequenceId = _Obj.sequenceId;
            collectibleType = _Obj.collectibleType;
            collectibleClass = _Obj.collectibleClass;
            collectibleName = bytes32ToString(_Obj.collectibleName);
            owner = _Obj.owner;
            isRedeemed = _Obj.isRedeemed;
        }
        
        /*** PUBLIC FUNCTIONS ***/
        /// @notice Grant another address the right to transfer token via takeOwnership() and transferFrom().
        /// @param _to The address to be granted transfer approval. Pass address(0) to
        ///  clear all approvals.
        /// @param _tokenId The ID of the Token that can be transferred if this call succeeds.
        /// @dev Required for ERC-721 compliance.
        function approve(address _to, uint256 _tokenId) public {
            // Caller must own token.
            require (_tokenId > STARTING_ASSET_BASE);
            
            require(_owns(msg.sender, _tokenId));
            preSaleItemIndexToApproved[_tokenId] = _to;
            
            Approval(msg.sender, _to, _tokenId);
        }
        
        /// For querying balance of a particular account
        /// @param _owner The address for balance query
        /// @dev Required for ERC-721 compliance.
        function balanceOf(address _owner) public view returns (uint256 balance) {
            return ownershipTokenCount[_owner];
        }
        
        function implementsERC721() public pure returns (bool) {
            return true;
        }
        
        /// For querying owner of token
        /// @param _tokenId The tokenID for owner inquiry
        /// @dev Required for ERC-721 compliance.
        function ownerOf(uint256 _tokenId) public view returns (address owner) {
            require (_tokenId > STARTING_ASSET_BASE);
    
            owner = preSaleItemIndexToOwner[_tokenId];
            require(owner != address(0));
        }
        
        /// @dev Required for ERC-721 compliance.
        function symbol() public pure returns (string) {
            return SYMBOL;
        }
        
        /// @notice Allow pre-approved user to take ownership of a token
        /// @param _tokenId The ID of the Token that can be transferred if this call succeeds.
        /// @dev Required for ERC-721 compliance.
        function takeOwnership(uint256 _tokenId) public {
            require (_tokenId > STARTING_ASSET_BASE);
    
            address newOwner = msg.sender;
            address oldOwner = preSaleItemIndexToOwner[_tokenId];
            
            // Safety check to prevent against an unexpected 0x0 default.
            require(_addressNotNull(newOwner));
            
            // Making sure transfer is approved
            require(_approved(newOwner, _tokenId));
            
            _transfer(oldOwner, newOwner, _tokenId);
        }
        
        /// @param _owner The owner whose collectibles tokens we are interested in.
        /// @dev This method MUST NEVER be called by smart contract code. First, it's fairly
        ///  expensive (it walks the entire CSCPreSaleItem array looking for collectibles belonging to owner),
        ///  but it also returns a dynamic array, which is only supported for web3 calls, and
        ///  not contract-to-contract calls.
        function tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) {
            uint256 tokenCount = balanceOf(_owner);
            
            if (tokenCount == 0) {
                // Return an empty array
                return new uint256[](0);
            } else {
                uint256[] memory result = new uint256[](tokenCount);
                uint256 totalCount = totalSupply() + 1 + STARTING_ASSET_BASE;
                uint256 resultIndex = 0;
            
                // We count on the fact that all LS PreSaleItems have IDs starting at 0 and increasing
                // sequentially up to the total count.
                uint256 _tokenId;
            
                for (_tokenId = STARTING_ASSET_BASE; _tokenId < totalCount; _tokenId++) {
                    if (preSaleItemIndexToOwner[_tokenId] == _owner) {
                        result[resultIndex] = _tokenId;
                        resultIndex++;
                    }
                }
            
                return result;
            }
        }
        
        /// For querying totalSupply of token
        /// @dev Required for ERC-721 compliance.
        function totalSupply() public view returns (uint256 total) {
            return allPreSaleItems.length - 1; //Removed 0 index
        }
        
        /// Owner initates the transfer of the token to another account
        /// @param _to The address for the token to be transferred to.
        /// @param _tokenId The ID of the Token that can be transferred if this call succeeds.
        /// @dev Required for ERC-721 compliance.
        function transfer(address _to, uint256 _tokenId) public {
    
            require (_tokenId > STARTING_ASSET_BASE);
            
            require(_addressNotNull(_to));
            require(_owns(msg.sender, _tokenId));
            
            _transfer(msg.sender, _to, _tokenId);
        }
        
        /// Third-party initiates transfer of token from address _from to address _to
        /// @param _from The address for the token to be transferred from.
        /// @param _to The address for the token to be transferred to.
        /// @param _tokenId The ID of the Token that can be transferred if this call succeeds.
        /// @dev Required for ERC-721 compliance.
        function transferFrom(address _from, address _to, uint256 _tokenId) public {
            require (_tokenId > STARTING_ASSET_BASE);
    
            require(_owns(_from, _tokenId));
            require(_approved(_to, _tokenId));
            require(_addressNotNull(_to));
            
            _transfer(_from, _to, _tokenId);
        }
        
        /*** PRIVATE FUNCTIONS ***/
        /// @dev  Safety check on _to address to prevent against an unexpected 0x0 default.
        function _addressNotNull(address _to) internal pure returns (bool) {
            return _to != address(0);
        }
        
        /// @dev  For checking approval of transfer for address _to
        function _approved(address _to, uint256 _tokenId) internal view returns (bool) {
            return preSaleItemIndexToApproved[_tokenId] == _to;
        }
        
        /// @dev For creating CSC Collectible
        function _createCollectible(bytes32 _collectibleName, uint256 _collectibleType, uint256 _collectibleClass) internal returns(uint256) {
            uint256 _sequenceId = uint256(preSaleItemTypeToCollectibleCount[_collectibleType][_collectibleClass]) + 1;
            
            // These requires are not strictly necessary, our calling code should make
            // sure that these conditions are never broken.
            require(_sequenceId == uint256(uint32(_sequenceId)));
            
            CSCPreSaleItem memory _collectibleObj = CSCPreSaleItem(
              _sequenceId,
              _collectibleName,
              _collectibleType,
              _collectibleClass,
              address(0),
              false
            );
            
            uint256 generatedCollectibleId = allPreSaleItems.push(_collectibleObj) - 1;
            uint256 collectibleIndex = generatedCollectibleId + STARTING_ASSET_BASE;
            
            preSaleItemTypeToSequenceIdToCollectible[_collectibleType][_collectibleClass][_sequenceId] = collectibleIndex;
            preSaleItemTypeToCollectibleCount[_collectibleType][_collectibleClass] = _sequenceId;
            
            // emit Created event
            // CollectibleCreated(address owner, uint256 globalId, uint256 collectibleType, uint256 collectibleClass, uint256 sequenceId, bytes32 collectibleName);
            CollectibleCreated(address(this), collectibleIndex, _collectibleType, _collectibleClass, _sequenceId, _collectibleObj.collectibleName);
            
            // This will assign ownership, and also emit the Transfer event as
            // per ERC721 draft
            _transfer(address(0), address(this), collectibleIndex);
            
            return collectibleIndex;
        }
        
        /// @dev Check for token ownership
        function _owns(address claimant, uint256 _tokenId) internal view returns (bool) {
            return claimant == preSaleItemIndexToOwner[_tokenId];
        }
        
        /// @dev Assigns ownership of a specific preSaleItem to an address.
        function _transfer(address _from, address _to, uint256 _tokenId) internal {
            uint256 generatedCollectibleId = _tokenId - STARTING_ASSET_BASE;
    
            // Updating the owner details of the collectible
            CSCPreSaleItem memory _Obj = allPreSaleItems[generatedCollectibleId];
            _Obj.owner = _to;
            allPreSaleItems[generatedCollectibleId] = _Obj;
            
            // Since the number of preSaleItem is capped to 2^32 we can't overflow this
            ownershipTokenCount[_to]++;
            
            //transfer ownership
            preSaleItemIndexToOwner[_tokenId] = _to;
            
            // When creating new collectibles _from is 0x0, but we can't account that address.
            if (_from != address(0)) {
              ownershipTokenCount[_from]--;
              // clear any previously approved ownership exchange
              delete preSaleItemIndexToApproved[_tokenId];
            }
            
            // Emit the transfer event.
            Transfer(_from, _to, _tokenId);
        }
        
        /// @dev Checks if a given address currently has transferApproval for a particular CSCPreSaleItem.
        /// 0 is a valid value as it will be the starter
        function _approvedFor(address _claimant, uint256 _tokenId) internal view returns (bool) {
            require(_tokenId > STARTING_ASSET_BASE);
    
            return preSaleItemIndexToApproved[_tokenId] == _claimant;
        }
    }
    
    /* Lucid Sight, Inc. ERC-721 Collectibles Manager. 
     * @title LSPreSaleManager - Lucid Sight, Inc. Non-Fungible Token
     * @author Fazri Zubair & Farhan Khwaja (Lucid Sight, Inc.)
     */
    contract CSCPreSaleManager is CSCPreSaleItemBase {
    
        event RefundClaimed(address owner, uint256 refundValue);
    
        /// @dev defines if preSaleItem type -> preSaleItem class -> Vending Machine to set limit (bool)
        mapping(uint256 => mapping(uint256 => bool)) public preSaleItemTypeToClassToCanBeVendingMachine;
    
        /// @dev defines if preSaleItem type -> preSaleItem class -> Vending Machine Fee
        mapping(uint256 => mapping(uint256 => uint256)) public preSaleItemTypeToClassToVendingFee;
    
        /// @dev Mapping created store the amount of value a wallet address used to buy assets
        mapping(address => uint256) public addressToValue;
        
        bool CSCPreSaleInit = false;
        /// @dev Constructor creates a reference to the NFT (ERC721) ownership contract
        function CSCPreSaleManager() public {
            require(msg.sender != address(0));
            paused = true;
            error = false;
            managerPrimary = msg.sender;
        }
    
        /// @dev allows the contract to accept ETH
        function() external payable {
        }
        
        /// @dev Function to add approved address to the 
        /// approved address list
        function addToApprovedAddress (address _newAddr) onlyManager whenNotPaused {
            require(_newAddr != address(0));
            require(!approvedAddressList[_newAddr]);
            approvedAddressList[_newAddr] = true;
        }
        
        /// @dev Function to remove an approved address from the 
        /// approved address list
        function removeFromApprovedAddress (address _newAddr) onlyManager whenNotPaused {
            require(_newAddr != address(0));
            require(approvedAddressList[_newAddr]);
            approvedAddressList[_newAddr] = false;
        }
    
        /// @dev Function toggle vending for collectible
        function toggleVending (uint256 _collectibleType, uint256 _collectibleClass) external onlyManager {
            if(preSaleItemTypeToClassToCanBeVendingMachine[_collectibleType][_collectibleClass] == false) {
                preSaleItemTypeToClassToCanBeVendingMachine[_collectibleType][_collectibleClass] = true;
            } else {
                preSaleItemTypeToClassToCanBeVendingMachine[_collectibleType][_collectibleClass] = false;
            }
        }
    
        /// @dev Function toggle vending for collectible
        function setVendingFee (uint256 _collectibleType, uint256 _collectibleClass, uint fee) external onlyManager {
            preSaleItemTypeToClassToVendingFee[_collectibleType][_collectibleClass] = fee;
        }
        
        /// @dev This helps in creating a collectible and then 
        /// transfer it _toAddress
        function createCollectible(uint256 _collectibleType, uint256 _collectibleClass, address _toAddress) onlyManager external whenNotPaused {
            require(msg.sender != address(0));
            require(msg.sender != address(this));
            
            require(_toAddress != address(0));
            require(_toAddress != address(this));
            
            require(preSaleItemTypeToClassToMaxLimitSet[_collectibleType][_collectibleClass]);
            require(preSaleItemTypeToCollectibleCount[_collectibleType][_collectibleClass] < preSaleItemTypeToClassToMaxLimit[_collectibleType][_collectibleClass]);
            
            uint256 _tokenId = _createCollectible(preSaleItemTypeToClassToName[_collectibleType][_collectibleClass], _collectibleType, _collectibleClass);
            
            _transfer(address(this), _toAddress, _tokenId);
        }
    
    
        /// @dev This helps in creating a collectible and then 
        /// transfer it _toAddress
        function vendingCreateCollectible(uint256 _collectibleType, uint256 _collectibleClass, address _toAddress) payable external whenNotPaused {
            
            //Only if Vending is Allowed for this Asset
            require(preSaleItemTypeToClassToCanBeVendingMachine[_collectibleType][_collectibleClass]);
    
            require(msg.value >= preSaleItemTypeToClassToVendingFee[_collectibleType][_collectibleClass]);
    
            require(msg.sender != address(0));
            require(msg.sender != address(this));
            
            require(_toAddress != address(0));
            require(_toAddress != address(this));
            
            require(preSaleItemTypeToClassToMaxLimitSet[_collectibleType][_collectibleClass]);
            require(preSaleItemTypeToCollectibleCount[_collectibleType][_collectibleClass] < preSaleItemTypeToClassToMaxLimit[_collectibleType][_collectibleClass]);
            
            uint256 _tokenId = _createCollectible(preSaleItemTypeToClassToName[_collectibleType][_collectibleClass], _collectibleType, _collectibleClass);
            uint256 excessBid = msg.value - preSaleItemTypeToClassToVendingFee[_collectibleType][_collectibleClass];
            
            if(excessBid > 0) {
                msg.sender.transfer(excessBid);
            }
    
            addressToValue[msg.sender] += preSaleItemTypeToClassToVendingFee[_collectibleType][_collectibleClass];
            
            _transfer(address(this), _toAddress, _tokenId);
        }
    
        
        
        /// @dev Override unpause so it requires all external contract addresses
        ///  to be set before contract can be unpaused. Also, we can't have
        ///  newContractAddress set either, because then the contract was upgraded.
        /// @notice This is public rather than external so we can call super.unpause
        ///  without using an expensive CALL.
        function unpause() public onlyManager whenPaused {
            // Actually unpause the contract.
            super.unpause();
        }
    
        /// @dev Override unpause so it requires all external contract addresses
        ///  to be set before contract can be unpaused. Also, we can't have
        ///  newContractAddress set either, because then the contract was upgraded.
        /// @notice This is public rather than external so we can call super.unpause
        ///  without using an expensive CALL.
        function hasError() public onlyManager whenPaused {
            // Actually error out the contract.
            super.hasError();
        }
        
        /// @dev Function does the init step and thus allow
        /// to create a Dummy 0th colelctible
        function preSaleInit() onlyManager {
            require(!CSCPreSaleInit);
            require(allPreSaleItems.length == 0);
            
            CSCPreSaleInit = true;
            
            //Fill in index 0 to null requests
            CSCPreSaleItem memory _Obj = CSCPreSaleItem(0, stringToBytes32("DummyAsset"), 0, 0, address(this), true);
            allPreSaleItems.push(_Obj);
        }
    
        /// @dev Remove all Ether from the contract, which is the owner's cuts
        ///  as well as any Ether sent directly to the contract address.
        ///  Always transfers to the NFT (ERC721) contract, but can be called either by
        ///  the owner or the NFT (ERC721) contract.
        function withdrawBalance() onlyBanker {
            // We are using this boolean method to make sure that even if one fails it will still work
            bankManager.transfer(this.balance);
        }
    
        // @dev a function to claim refund if and only if theres an error in the contract
        function claimRefund(address _ownerAddress) whenError {
            uint256 refundValue = addressToValue[_ownerAddress];
    
            require (refundValue > 0);
            
            addressToValue[_ownerAddress] = 0;
    
            _ownerAddress.transfer(refundValue);
            RefundClaimed(_ownerAddress, refundValue);
        }
        
    
        /// @dev Function used to set the flag isRedeemed to true
        /// can be called by addresses in the approvedAddressList
        function isRedeemed(uint256 _tokenId) {
            require(approvedAddressList[msg.sender]);
            require(_tokenId > STARTING_ASSET_BASE);
            uint256 generatedCollectibleId = _tokenId - STARTING_ASSET_BASE;
            
            CSCPreSaleItem memory _Obj = allPreSaleItems[generatedCollectibleId];
            _Obj.isRedeemed = true;
            
            allPreSaleItems[generatedCollectibleId] = _Obj;
        }
    }