contract KittyBountiesAdmin is Ownable, Pausable {

    /* ****** */
    /* EVENTS */
    /* ****** */

    /// @dev This event is fired whenever the owner changes the successfulBountyFeeInBasisPoints.
    /// @param newSuccessfulBountyFeeInBasisPoints  The SuccessfulFee is expressed in basis points (hundredths of a percantage), 
    ///  and is charged when a bounty is successfully completed.
    event SuccessfulBountyFeeInBasisPointsUpdated(uint256 newSuccessfulBountyFeeInBasisPoints);

    /// @dev This event is fired whenever the owner changes the unsuccessfulBountyFeeInWei. 
    /// @param newUnsuccessfulBountyFeeInWei  The UnsuccessfulBountyFee is paid by the original bounty creator if the bounty expires 
    ///  without being completed. When a bounty is created, the bounty creator specifies how long the bounty is valid for. If the 
    ///  bounty is not fulfilled by this expiration date, the original creator can then freely withdraw their funds, minus the 
    ///  UnsuccessfulBountyFee, although the bounty is still fulfillable until the bounty creator withdraws their funds.
    event UnsuccessfulBountyFeeInWeiUpdated(uint256 newUnsuccessfulBountyFeeInWei);

    /// @dev This event is fired whenever the owner changes the maximumLockupDurationInBlocks. 
    /// @param newMaximumLockoutDurationInBlocks  To prevent users from accidentally locking up ether for an eternity, the lockout 
    ///  period of all bounties is capped using this variable, which is inially set to 4 weeks. This is measured in blocks, which 
    ///  are created roughly once every 15 seconds. If the community expresses that they would like a longer maximumLockoutDuration,
    ///  the creator will adjust this variable.
    event MaximumLockoutDurationInBlocksUpdated(uint256 newMaximumLockoutDurationInBlocks);

    /* ******* */
    /* STORAGE */
    /* ******* */

    /// @dev The total amount that the contract creator has earned from fees since they last withdrew. Storing the owner's earnings
    ///  saves gas rather than performing an additional transfer() call on every successful bounty.
    uint256 public totalOwnerEarningsInWei = 0;

    /// @dev If a bounty is successfully fulfilled, this fee applies before the remaining funds are sent to the successful bounty
    ///  hunter. This fee is measured in basis points (hundredths of a percent), and is taken out of the total value that the bounty
    ///  creator locked up in the contract when they created the bounty.
    uint256 public successfulBountyFeeInBasisPoints = 375;

    /// @dev If a bounty is not fulfilled after the lockup period has completed, a bounty creator can withdraw their funds and
    ///  invalidate the bounty, but they are charged this flat fee to do so. This fee is measured in wei.
    uint256 public unsuccessfulBountyFeeInWei = 0.008 ether;

    /// @dev To prevent users from accidentally locking up ether for an eternity, the lockout period of all bounties is capped
    ///  using this variable, which is inially set to 4 weeks. This is measured in blocks, which are created roughly once every 15 seconds. 
    ///  If the community expresses that they would like a longer maximumLockoutDuration, the creator will adjust this variable.
    /// @notice This is initalized to 4 weeks in blocks (161280 = 4 (weeks) * 7 (days) * 24 (hours) * 60 (minutes) * 4 (blocks per minute))
    ///  Note that this rests on the assumption that each block takes 15 seconds to propagate. This maximum lockout can be changed by the owner
    ///  if this assumption is invalidated.
    uint256 public maximumLockoutDurationInBlocks = 161280; 

    /* ********* */
    /* CONSTANTS */
    /* ********* */

    /// @dev The owner is not capable of changing the address of the CryptoKitties Core contract once the contract has been deployed.
    ///  This prevents an attack vector where the owner could change the kittyCore contract once users had already deposited funds.
    ///  Since the CryptoKitties Core contract has the ability to migrate to a new contract, if Dapper Labs Inc. ever chooses to migrate
    ///  contract, this contract will have to be frozen, and users will be allowed to withdraw their funds without paying any fees.
    address public kittyCoreAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
    KittyCore kittyCore;

    /* ********* */
    /* FUNCTIONS */
    /* ********* */

    /// @dev The owner is not capable of changing the address of the CryptoKitties Core contract once the contract has been deployed.
    ///  This prevents an attack vector where the owner could change the kittyCore contract once users had already deposited funds.
    constructor() internal {
        kittyCore = KittyCore(kittyCoreAddress);
    }

    /// @notice Sets the successfulBountyFeeInBasisPoints value (in basis points). Any bounties that are successfully fulfilled 
    ///  will have this fee deducted from amount sent to the bounty hunter.
    /// @notice Only callable by the owner.
    /// @dev As this configuration is a basis point, the value to set must be less than or equal to 10000.
    /// @param _newSuccessfulBountyFeeInBasisPoints  The successfulBountyFeeInBasisPoints value to set (measured in basis points).
    function setSuccessfulBountyFeeInBasisPoints(uint256 _newSuccessfulBountyFeeInBasisPoints) external onlyOwner {
        require(_newSuccessfulBountyFeeInBasisPoints <= 10000, 'new successful bounty fee must be in basis points (hundredths of a percent), not wei');
        successfulBountyFeeInBasisPoints = _newSuccessfulBountyFeeInBasisPoints;
        emit SuccessfulBountyFeeInBasisPointsUpdated(_newSuccessfulBountyFeeInBasisPoints);
    }

    /// @notice Sets the unsuccessfulBountyFeeInWei value. If a bounty is still unfulfilled once the minimum number of blocks has passed,
    ///  an owner can withdraw the locked ETH. If they do so, this fee is deducted from the amount that they withdraw.
    /// @notice Only callable by the owner.
    /// @param _newUnsuccessfulBountyFeeInWei  The unsuccessfulBountyFeeInWei value to set (measured in wei).
    function setUnsuccessfulBountyFeeInWei(uint256 _newUnsuccessfulBountyFeeInWei) external onlyOwner {
        unsuccessfulBountyFeeInWei = _newUnsuccessfulBountyFeeInWei;
        emit UnsuccessfulBountyFeeInWeiUpdated(_newUnsuccessfulBountyFeeInWei);
    }

    /// @notice Sets the maximumLockoutDurationInBlocks value. To prevent users from accidentally locking up ether for an eternity, the 
    ///  lockout period of all bounties is capped using this variable, which is inially set to 4 weeks. This is measured in blocks, which 
    ///  are created roughly once every 15 seconds. If the assumption of 1 block every 15 seconds is ever invalidated, the owner is able
    ///  to change the maximumLockoutDurationInBlocks using this function.
    /// @notice Only callable by the owner.
    /// @param _newMaximumLockoutDurationInBlocks  The maximumLockoutDurationInBlocks value to set (measured in blocks).
    function setMaximumLockoutDurationInBlocks(uint256 _newMaximumLockoutDurationInBlocks) external onlyOwner {
        maximumLockoutDurationInBlocks = _newMaximumLockoutDurationInBlocks;
        emit MaximumLockoutDurationInBlocksUpdated(_newMaximumLockoutDurationInBlocks);
    }

    /// @notice Withdraws the fees that have been earned by the contract owner.
    /// @notice Only callable by the owner.
    function withdrawOwnerEarnings() external onlyOwner {
        uint256 balance = totalOwnerEarningsInWei;
        totalOwnerEarningsInWei = 0;
        msg.sender.transfer(balance);
    }

    /// @dev By calling 'revert' in the fallback function, we prevent anyone from accidentally sending funds directly to this contract.
    function() external payable {
        revert();
    }
}
/// @title Admin contract for KittyBounties. Holds owner-only functions to adjust contract-wide fees, change owners, etc.
/// @dev The owner is not capable of changing the address of the CryptoKitties Core contract once the contract has been deployed.
///  This prevents an attack vector where the owner could change the kittyCore contract once users had already deposited funds.
function setSuccessfulBountyFeeInBasisPoints(uint256 _newSuccessfulBountyFeeInBasisPoints) external onlyOwner {
    require(_newSuccessfulBountyFeeInBasisPoints <= 10000, 'new successful bounty fee must be in basis points (hundredths of a percent), not wei');
    successfulBountyFeeInBasisPoints = _newSuccessfulBountyFeeInBasisPoints;
    emit SuccessfulBountyFeeInBasisPointsUpdated(_newSuccessfulBountyFeeInBasisPoints);
}

/// @notice Sets the successfulBountyFeeInBasisPoints value (in basis points). Any bounties that are successfully fulfilled 
///  will have this fee deducted from amount sent to the bounty hunter.
/// @notice Only callable by the owner.
/// @dev As this configuration is a basis point, the value to set must be less than or equal to 10000.
/// @param _newSuccessfulBountyFeeInBasisPoints  The successfulBountyFeeInBasisPoints value to set (measured in basis points).