contract RobotoPlayerOne is IERC721Receiver, DSMath, Ownable {
    
    // Public Properties
    
    uint8   public nftCount;
    bool    public claimed;
    address public robotosContractAddress = 0x099689220846644F87D1137665CDED7BF3422747;
    
    // A running tally of how many attempts have been made to claim the hidden NFT.
    uint256 public claimAttempts;
    
    // The address of the person who held the winning Roboto!
    address public winnerAddress;
    
    // The address of the wallet who aped in and bought out the contract.
    address public buyoutClaimerAddress;
    
    // Constants
    
    uint256 public constant checkPrice = 0.02 ether;
    
    uint256 public constant buyoutPrice = 10 ether;
    
    // Private Properties
    
    // The number of the magic Roboto you need to claim this contract's prize.
    uint256 private winningRobotoIndex;
    
    // The prize NFT's number in its collection.
    // I used a tool to randomly pick a reply to this tweet: https://twitter.com/backseats_eth/status/1424860091375833096
    uint256 private prizeNftIndex;
    
    // The contract address of the prize NFT.
    address private externalContractAddress;
    
    // Withdraw Addresses
    
    address p1 = 0x3a6372B2013f9876a84761187d933DEe0653E377;
    address p2 = 0xef7639fADB98b76867cE29927B8347816C86A6eD;
    
    // Events
    
    event BuyoutOccurred(address _who);
    event FundsWithdrawn(string _str, uint256 _p1, uint256 _p2);
    event NftReceived();
    event NftCheck(address _checker, string _message);
    event TransferNFTToClaimer(address _keyHolder);
    event ValueReceived(address _from, uint256 _amount);
    
    // Constructor
    
    constructor(
        uint256 _winningRobotoIndex,
        uint256 _prizeNftIndex,
        address _externalContract
    ) {
        winningRobotoIndex = _winningRobotoIndex;
        prizeNftIndex = _prizeNftIndex;
        externalContractAddress = _externalContract;
        owner = msg.sender;
    }

    // IERC721Receiver Conformance Function

    // @dev: Attribute names not included below because I don't need them in my function's logic.
    function onERC721Received(address, address, uint256, bytes memory) public override returns(bytes4) {
        require(nftCount == 0, "Already holding NFT!");
        
        nftCount++;
        emit NftReceived();
        return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
    }
    
    // Public Functions
    
    // @dev: At any time before being claimed, anyone can buy the mystery NFT from this contract for 10 ETH.
    function buyout() public payable {
        require(!claimed, "NFT has already been claimed!");
        require(msg.value == buyoutPrice, "Send 10 ETH.");
        
        emit BuyoutOccurred(msg.sender);
        buyoutClaimerAddress = msg.sender;
        _transfer();
    }

     // @dev: Function checks to see if your wallet holds the magic Roboto, costs 0.02 ETH.
     // If so, transfers; If not, emits event and returns false.
    function checkForKey() public payable returns (bool) {
        require(!claimed, "NFT has already been claimed!");
        require(msg.value == checkPrice, "Send 0.02 ETH");

        claimAttempts++;
        if (ERC721(robotosContractAddress).ownerOf(winningRobotoIndex) == msg.sender) {
            emit NftCheck(msg.sender, "is the key holder!");
            winnerAddress = msg.sender;
            _transfer();
            return true;
        }
        
        emit NftCheck(msg.sender, "was not the key holder");
        return false;
    }
    
    // Fallback Function

    // @dev: A fallback receive function in case random ETH is sent.
    receive() external payable {
        emit ValueReceived(msg.sender, msg.value);
    }
    
    // Private Function 

    // @dev: Tranfers the prize NFT stored in the contract and sets `claimed` to true, essentially ending the functionality of this contract.
    function _transfer() internal {
        emit TransferNFTToClaimer(msg.sender);
        ERC721(externalContractAddress).safeTransferFrom(address(this), msg.sender, prizeNftIndex);
        claimed = true;
        nftCount --;
    }
    
    // Ownable Function
    
    // @dev: Allows the owner of this contract to withdraw any funds accrued from usage.
    function returnFunds() public onlyOwner {
        uint256 balance = address(this).balance;
        uint256 p1bal = wmul(balance, 0.9 ether);
        uint256 p2bal = wmul(balance, 0.1 ether);
        
        require(payable(p1).send(p1bal));
        require(payable(p2).send(p2bal));
        
        emit FundsWithdrawn("Paid:", p1bal, p2bal);
    }

}
// Fallback Function
// @dev: A fallback receive function in case random ETH is sent.