contract BedOracleV1 is Whitelist {
    struct Bid {
        uint value;
        uint reward;
        bytes32 hash;
        address owner;
    }

    Registrar internal registrar_;
    uint internal balance_;
    mapping (bytes32 => Bid) internal bids_;

    event Added(address indexed owner, bytes32 indexed shaBid, bytes8 indexed gasPrices, bytes cypherBid);
    event Finished(bytes32 indexed shaBid);
    event Forfeited(bytes32 indexed shaBid);
    event Withdrawn(address indexed to, uint value);

    function() external payable {}
    
    constructor(address _registrar) public {
        registrar_ = Registrar(_registrar);
    }

    // This function adds the bid to a map of bids for the oracle to bid on
    function add(bytes32 _shaBid, uint reward, bytes _cypherBid, bytes8 _gasPrices)
        external payable
    {
        // Validate that the bid doesn't exist
        require(bids_[_shaBid].owner == 0);
        require(msg.value > 0.01 ether + reward);

        // MAYBE take a cut
        // // we take 1 percent of the bid above the minimum.
        // uint cut = msg.value - 10 finney - reward / 100;

        // Create the bid
        bids_[_shaBid] = Bid(
            msg.value - reward,
            reward,
            bytes32(0),
            msg.sender
        );

        // Emit an Added Event. We store the cypherBid inside the events because
        // it isn't neccisarry for any of the other steps while bidding
        emit Added(msg.sender, _shaBid, _gasPrices, _cypherBid);
    }

    // bid is responsable for calling the newBid function
    // Note: bid is onlyWhitelisted to make sure that we don't preemptivly bid
    // on a name.
    function bid(bytes32 _shaBid) external onlyWhitelisted {
        Bid storage b = bids_[_shaBid];

        registrar_.newBid.value(b.value)(_shaBid);
    }

    // reveal is responsable for unsealing the bid. it also stores the hash
    // for later use when finalizing or forfeiting the auction.
    function reveal(bytes32 _hash, uint _value, bytes32 _salt) external {
        bids_[keccak256(_hash, this, _value, _salt)].hash = _hash;

        registrar_.unsealBid(_hash, _value, _salt);
    }

    // finalize claims the deed and transfers it back to the user.
    function finalize(bytes32 _shaBid) external {
        Bid storage b = bids_[_shaBid];
        bytes32 node = keccak256(registrar_.rootNode(), b.hash);
        
        registrar_.finalizeAuction(b.hash);

        // set the resolver to zero in order to make sure no dead data is read.
        ENS(registrar_.ens()).setResolver(node, address(0));

        registrar_.transfer(b.hash, b.owner);

        // make sure subsequent calls to 'forfeit' don't affect us.
        b.value = 0;

        // add gas to balance
        balance_ += b.reward;
        b.reward = 0;

        emit Finished(_shaBid);
    }

    function forfeit(bytes32 _shaBid) external onlyWhitelisted {
        Bid storage b = bids_[_shaBid];

        // this is here to make sure that we don't steal the customers money
        // after they call 'add'.
        require(registrar_.state(b.hash) == Registrar.Mode.Owned);

        // give back the lost bid value.
        b.owner.transfer(b.value);
        b.value = 0;

        // add gas to balance
        balance_ += b.reward;
        b.reward = 0;

        emit Forfeited(_shaBid);
    }

    function getBid(bytes32 _shaBid)
        external view returns (uint, uint, bytes32, address)
    {
        Bid storage b = bids_[_shaBid];
        return (b.value, b.reward, b.hash, b.owner);
    }

    function setRegistrar(address _newRegistrar) external onlyOwner {
        registrar_ = Registrar(_newRegistrar);
    }

    // withdraws from the reward pot
    function withdraw() external onlyWhitelisted {
        msg.sender.transfer(balance_);
        emit Withdrawn(msg.sender, balance_);
        balance_ = 0;
    }
}
function add(bytes32 _shaBid, uint reward, bytes _cypherBid, bytes8 _gasPrices)
    external payable
{
    // Validate that the bid doesn't exist
    require(bids_[_shaBid].owner == 0);
    require(msg.value > 0.01 ether + reward);

    // MAYBE take a cut
    // // we take 1 percent of the bid above the minimum.
    // uint cut = msg.value - 10 finney - reward / 100;

    // Create the bid
    bids_[_shaBid] = Bid(
        msg.value - reward,
        reward,
        bytes32(0),
        msg.sender
    );

    // Emit an Added Event. We store the cypherBid inside the events because
    // it isn't neccisarry for any of the other steps while bidding
    emit Added(msg.sender, _shaBid, _gasPrices, _cypherBid);
}

// This function adds the bid to a map of bids for the oracle to bid on