contract ERC721DutchAuction is Ownable, Pausable {

    /* ======== STRUCTS/ENUMS ======== */

    // Represents an auction of an ERC721 token.
    struct Auction {

        // Current owner of the ERC721 token.
        address seller;

        // Price (in wei) at beginning of auction.
        uint128 startingPrice;

        // Price (in wei) at end of auction.
        uint128 endingPrice;

        // Duration (in seconds) of auction.
        uint64 duration;

        // Time when auction started.
        // NOTE: 0 if this auction has been concluded.
        uint64 startedAt;

    }


    /* ======== CONTRACTS ======== */

    // Reference to contract tracking ERC721 token ownership.
    ERC721 public nonFungibleContract;


    /* ======== STATE VARIABLES ======== */

    // Cut owner takes on each auction, measured in basis points (1/100 of a percent).
    // Values 0-10,000 map to 0%-100%
    uint public ownerCut;

    // Map from token ID to their corresponding auction.
    mapping (uint => Auction) tokenIdToAuction;


    /* ======== EVENTS ======== */

    event AuctionCreated(uint timestamp, address indexed seller, uint indexed tokenId, uint startingPrice, uint endingPrice, uint duration);
    event AuctionSuccessful(uint timestamp, address indexed seller, uint indexed tokenId, uint totalPrice, address winner);
    event AuctionCancelled(uint timestamp, address indexed seller, uint indexed tokenId);

    /**
     * @dev Constructor creates a reference to the ERC721 token ownership contract and verifies the owner cut is in the valid range.
     * @param _tokenAddress - address of a deployed contract implementing the Nonfungible Interface.
     * @param _ownerCut - percent cut the owner takes on each auction, must be between 0-10,000.
     */
    function ERC721DutchAuction(address _tokenAddress, uint _ownerCut) public {
        require(_ownerCut <= 10000);

        nonFungibleContract = ERC721(_tokenAddress);
        ownerCut = _ownerCut;
    }


    /* ======== PUBLIC/EXTERNAL FUNCTIONS ======== */

    /**
     * @dev Bids on an open auction, completing the auction and transferring
     *  ownership of the token if enough Ether is supplied.
     * @param _tokenId - ID of token to bid on.
     */
    function bid(uint _tokenId) whenNotPaused external payable {
        // _bid will throw if the bid or funds transfer fails.
        _bid(_tokenId, msg.value);

        // Transfers the token owned by this contract to another address. It will throw if transfer fails.
        nonFungibleContract.transfer(msg.sender, _tokenId);
    }

    /**
     * @dev Cancels an auction that hasn't been won yet. Returns the token to original owner.
     * @notice This is a state-modifying function that can be called while the contract is paused.
     * @param _tokenId - ID of token on auction
     */
    function cancelAuction(uint _tokenId) external {
        Auction storage auction = tokenIdToAuction[_tokenId];
        require(_isOnAuction(auction));

        address seller = auction.seller;
        require(msg.sender == seller);

        _cancelAuction(_tokenId, seller);
    }

    /**
     * @dev Cancels an auction when the contract is paused.
     *  Only the owner may do this, and tokens are returned to
     *  the seller. This should only be used in emergencies.
     * @param _tokenId - ID of the token on auction to cancel.
     */
    function cancelAuctionWhenPaused(uint _tokenId) whenPaused onlyOwner external {
        Auction storage auction = tokenIdToAuction[_tokenId];
        require(_isOnAuction(auction));

        _cancelAuction(_tokenId, auction.seller);
    }

    /**
     * @dev Remove all Ether from the contract, which is the owner's cuts
     *  as well as any Ether sent directly to the contract address.
     */
    function withdrawBalance() onlyOwner external {
        msg.sender.transfer(this.balance);
    }

    /**
     * @dev Returns auction info for an token on auction.
     * @param _tokenId - ID of token on auction.
     */
    function getAuction(uint _tokenId) external view returns (
        address seller,
        uint startingPrice,
        uint endingPrice,
        uint duration,
        uint startedAt
    ) {
        Auction storage auction = tokenIdToAuction[_tokenId];
        require(_isOnAuction(auction));

        return (
            auction.seller,
            auction.startingPrice,
            auction.endingPrice,
            auction.duration,
            auction.startedAt
        );
    }

    /**
     * @dev Returns the current price of an auction.
     * @param _tokenId - ID of the token price we are checking.
     */
    function getCurrentPrice(uint _tokenId) external view returns (uint) {
        Auction storage auction = tokenIdToAuction[_tokenId];
        require(_isOnAuction(auction));

        return _computeCurrentPrice(auction);
    }


    /* ======== INTERNAL/PRIVATE FUNCTIONS ======== */

    /**
     * @dev Creates and begins a new auction. Perform all the checkings necessary.
     * @param _tokenId - ID of token to auction, sender must be owner.
     * @param _startingPrice - Price of item (in wei) at beginning of auction.
     * @param _endingPrice - Price of item (in wei) at end of auction.
     * @param _duration - Length of time to move between starting
     *  price and ending price (in seconds).
     * @param _seller - Seller, if not the message sender
     */
    function _createAuction(
        uint _tokenId,
        uint _startingPrice,
        uint _endingPrice,
        uint _duration,
        address _seller
    ) internal {
        // Sanity check that no inputs overflow how many bits we've allocated to store them in the auction struct.
        require(_startingPrice == uint(uint128(_startingPrice)));
        require(_endingPrice == uint(uint128(_endingPrice)));
        require(_duration == uint(uint64(_duration)));

        // If the token is already on any auction, this will throw
        // because it will be owned by the auction contract.
        require(nonFungibleContract.ownerOf(_tokenId) == msg.sender);

        // Throw if the _endingPrice is larger than _startingPrice.
        require(_startingPrice >= _endingPrice);

        // Require that all auctions have a duration of at least one minute.
        require(_duration >= 1 minutes);

        // Transfer the token from its owner to this contract. It will throw if transfer fails.
        nonFungibleContract.transferFrom(msg.sender, this, _tokenId);

        Auction memory auction = Auction(
            _seller,
            uint128(_startingPrice),
            uint128(_endingPrice),
            uint64(_duration),
            uint64(now)
        );

        _addAuction(_tokenId, auction);
    }

    /**
     * @dev Adds an auction to the list of open auctions. Also fires the
     *  AuctionCreated event.
     * @param _tokenId The ID of the token to be put on auction.
     * @param _auction Auction to add.
     */
    function _addAuction(uint _tokenId, Auction _auction) internal {
        tokenIdToAuction[_tokenId] = _auction;

        AuctionCreated(
            now,
            _auction.seller,
            _tokenId,
            _auction.startingPrice,
            _auction.endingPrice,
            _auction.duration
        );
    }

    /**
     * @dev Computes the price and transfers winnings.
     *  Does NOT transfer ownership of token.
     */
    function _bid(uint _tokenId, uint _bidAmount) internal returns (uint) {
        // Get a reference to the auction struct
        Auction storage auction = tokenIdToAuction[_tokenId];

        // Explicitly check that this auction is currently live.
        // (Because of how Ethereum mappings work, we can't just count
        // on the lookup above failing. An invalid _tokenId will just
        // return an auction object that is all zeros.)
        require(_isOnAuction(auction));

        // Check that the bid is greater than or equal to the current price
        uint price = _computeCurrentPrice(auction);
        require(_bidAmount >= price);

        // Grab a reference to the seller before the auction struct
        // gets deleted.
        address seller = auction.seller;

        // The bid is good! Remove the auction before sending the fees
        // to the sender so we can't have a reentrancy attack.
        _removeAuction(_tokenId);

        // Transfer proceeds to seller (if there are any!)
        if (price > 0) {
            // Calculate the auctioneer's cut.
            uint auctioneerCut = price * ownerCut / 10000;
            uint sellerProceeds = price - auctioneerCut;

            seller.transfer(sellerProceeds);
        }

        // Calculate any excess funds included with the bid. If the excess
        // is anything worth worrying about, transfer it back to bidder.
        // NOTE: We checked above that the bid amount is greater than or
        // equal to the price so this cannot underflow.
        uint bidExcess = _bidAmount - price;

        // Return the funds. Similar to the previous transfer, this is
        // not susceptible to a re-entry attack because the auction is
        // removed before any transfers occur.
        msg.sender.transfer(bidExcess);

        // Tell the world!
        AuctionSuccessful(now, seller, _tokenId, price, msg.sender);

        return price;
    }

    /**
     * @dev Cancels an auction unconditionally.
     */
    function _cancelAuction(uint _tokenId, address _seller) internal {
        _removeAuction(_tokenId);

        // Transfers the token owned by this contract to its original owner. It will throw if transfer fails.
        nonFungibleContract.transfer(_seller, _tokenId);

        AuctionCancelled(now, _seller, _tokenId);
    }

    /**
     * @dev Removes an auction from the list of open auctions.
     * @param _tokenId - ID of token on auction.
     */
    function _removeAuction(uint _tokenId) internal {
        delete tokenIdToAuction[_tokenId];
    }

    /**
     * @dev Returns current price of an token on auction. Broken into two
     *  functions (this one, that computes the duration from the auction
     *  structure, and the other that does the price computation) so we
     *  can easily test that the price computation works correctly.
     */
    function _computeCurrentPrice(Auction storage _auction) internal view returns (uint) {
        uint secondsPassed = 0;

        // A bit of insurance against negative values (or wraparound).
        // Probably not necessary (since Ethereum guarnatees that the
        // now variable doesn't ever go backwards).
        if (now > _auction.startedAt) {
            secondsPassed = now - _auction.startedAt;
        }

        if (secondsPassed >= _auction.duration) {
            // We've reached the end of the dynamic pricing portion
            // of the auction, just return the end price.
            return _auction.endingPrice;
        } else {
            // Starting price can be higher than ending price (and often is!), so
            // this delta can be negative.
            int totalPriceChange = int(_auction.endingPrice) - int(_auction.startingPrice);

            // This multiplication can't overflow, _secondsPassed will easily fit within
            // 64-bits, and totalPriceChange will easily fit within 128-bits, their product
            // will always fit within 256-bits.
            int currentPriceChange = totalPriceChange * int(secondsPassed) / int(_auction.duration);

            // currentPriceChange can be negative, but if so, will have a magnitude
            // less that startingPrice. Thus, this result will always end up positive.
            int currentPrice = int(_auction.startingPrice) + currentPriceChange;

            return uint(currentPrice);
        }
    }


    /* ======== MODIFIERS ======== */

    /**
     * @dev Returns true if the token is on auction.
     * @param _auction - Auction to check.
     */
    function _isOnAuction(Auction storage _auction) internal view returns (bool) {
        return (_auction.startedAt > 0);
    }

}
/**
 * @title ERC721DutchAuction
 * @dev Dutch auction / Decreasing clock auction for ERC721 tokens.
 */
function _addAuction(uint _tokenId, Auction _auction) internal {
    tokenIdToAuction[_tokenId] = _auction;

    AuctionCreated(
        now,
        _auction.seller,
        _tokenId,
        _auction.startingPrice,
        _auction.endingPrice,
        _auction.duration
    );
}

/**
 * @dev Adds an auction to the list of open auctions. Also fires the
 *  AuctionCreated event.
 * @param _tokenId The ID of the token to be put on auction.
 * @param _auction Auction to add.
 */