contract SkinMarket is SkinMix {

    // Cut ratio for a transaction
    // Values 0-10,000 map to 0%-100%
    uint128 public trCut = 400;

    // Sale orders list 
    mapping (uint256 => uint256) public desiredPrice;

    // events
    event PutOnSale(address account, uint256 skinId);
    event WithdrawSale(address account, uint256 skinId);
    event BuyInMarket(address buyer, uint256 skinId);

    // functions

    function setTrCut(uint256 newCut) external onlyCOO {
        trCut = uint128(newCut);
    }

    // Put asset on sale
    function putOnSale(uint256 skinId, uint256 price) public whenNotPaused {
        // Only owner of skin pass
        require(skinIdToOwner[skinId] == msg.sender);
        require(accountsToActiveSkin[msg.sender] != skinId);

        // Check whether skin is mixing 
        require(skins[skinId].mixingWithId == 0);

        // Check whether skin is already on sale
        require(isOnSale[skinId] == false);

        require(price > 0); 

        // Put on sale
        desiredPrice[skinId] = price;
        isOnSale[skinId] = true;

        // Emit the Approval event
        emit PutOnSale(msg.sender, skinId);
    }
  
    // Withdraw an sale order
    function withdrawSale(uint256 skinId) external whenNotPaused {
        // Check whether this skin is on sale
        require(isOnSale[skinId] == true);
        
        // Can only withdraw self's sale
        require(skinIdToOwner[skinId] == msg.sender);

        // Withdraw
        isOnSale[skinId] = false;
        desiredPrice[skinId] = 0;

        // Emit the cancel event
        emit WithdrawSale(msg.sender, skinId);
    }
 
    // Buy skin in market
    function buyInMarket(uint256 skinId) external payable whenNotPaused {
        // Check whether this skin is on sale
        require(isOnSale[skinId] == true);

        address seller = skinIdToOwner[skinId];

        // Check the sender isn't the seller
        require(msg.sender != seller);

        uint256 _price = desiredPrice[skinId];
        // Check whether pay value is enough
        require(msg.value >= _price);

        // Cut and then send the proceeds to seller
        uint256 sellerProceeds = _price - _computeCut(_price);

        seller.transfer(sellerProceeds);

        // Transfer skin from seller to buyer
        numSkinOfAccounts[seller] -= 1;
        skinIdToOwner[skinId] = msg.sender;
        numSkinOfAccounts[msg.sender] += 1;
        isOnSale[skinId] = false;
        desiredPrice[skinId] = 0;

        // Emit the buy event
        emit BuyInMarket(msg.sender, skinId);
    }

    // Compute the marketCut
    function _computeCut(uint256 _price) internal view returns (uint256) {
        return _price / 10000 * trCut;
    }
}
function setTrCut(uint256 newCut) external onlyCOO {
    trCut = uint128(newCut);
}

// functions