// File: Address.sol



pragma solidity ^0.5.0;

/**
 * Utility library of inline functions on addresses
 */
library Address {
    /**
     * Returns whether the target address is a contract
     * @dev This function will return false if invoked during the constructor of a contract,
     * as the code is not actually created until after the constructor finishes.
     * @param account address of the account to check
     * @return whether the target address is a contract
     */
    function isContract(address account) internal view returns (bool) {
        uint256 size;
        // XXX Currently there is no better way to check if there is a contract in an address
        // than to check the size of the code at that address.
        // See https://ethereum.stackexchange.com/a/14016/36603
        // for more details about how this works.
        // TODO Check this again before the Serenity release, because all addresses will be
        // contracts then.
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}

// File: Controllable.sol



pragma solidity ^0.5.0;

import "./Ownable.sol";

contract Controllable is Ownable {
    mapping(address=>bool) public controllers;

    modifier onlyController {
        require(controllers[msg.sender]);
        _;
    }

    function setController(address controller, bool enabled) public onlyOwner {
        controllers[controller] = enabled;
    }
}

// File: Deed.sol



pragma solidity >=0.4.24;

interface Deed {

    function setOwner(address payable newOwner) external;
    function setRegistrar(address newRegistrar) external;
    function setBalance(uint newValue, bool throwOnFailure) external;
    function closeDeed(uint refundRatio) external;
    function destroyDeed() external;

    function owner() external view returns (address);
    function previousOwner() external view returns (address);
    function value() external view returns (uint);
    function creationDate() external view returns (uint);

}

// File: DeedImplementation.sol



pragma solidity ^0.5.0;

import "./Deed.sol";

/**
 * @title Deed to hold ether in exchange for ownership of a node
 * @dev The deed can be controlled only by the registrar and can only send ether back to the owner.
 */
contract DeedImplementation is Deed {

    address payable constant burn = address(0xdead);

    address payable private _owner;
    address private _previousOwner;
    address private _registrar;

    uint private _creationDate;
    uint private _value;

    bool active;

    event OwnerChanged(address newOwner);
    event DeedClosed();

    modifier onlyRegistrar {
        require(msg.sender == _registrar);
        _;
    }

    modifier onlyActive {
        require(active);
        _;
    }

    constructor(address payable initialOwner) public payable {
        _owner = initialOwner;
        _registrar = msg.sender;
        _creationDate = now;
        active = true;
        _value = msg.value;
    }

    function setOwner(address payable newOwner) external onlyRegistrar {
        require(newOwner != address(0x0));
        _previousOwner = _owner;  // This allows contracts to check who sent them the ownership
        _owner = newOwner;
        emit OwnerChanged(newOwner);
    }

    function setRegistrar(address newRegistrar) external onlyRegistrar {
        _registrar = newRegistrar;
    }

    function setBalance(uint newValue, bool throwOnFailure) external onlyRegistrar onlyActive {
        // Check if it has enough balance to set the value
        require(_value >= newValue);
        _value = newValue;
        // Send the difference to the owner
        require(_owner.send(address(this).balance - newValue) || !throwOnFailure);
    }

    /**
     * @dev Close a deed and refund a specified fraction of the bid value
     *
     * @param refundRatio The amount*1/1000 to refund
     */
    function closeDeed(uint refundRatio) external onlyRegistrar onlyActive {
        active = false;
        require(burn.send(((1000 - refundRatio) * address(this).balance)/1000));
        emit DeedClosed();
        _destroyDeed();
    }

    /**
     * @dev Close a deed and refund a specified fraction of the bid value
     */
    function destroyDeed() external {
        _destroyDeed();
    }

    function owner() external view returns (address) {
        return _owner;
    }

    function previousOwner() external view returns (address) {
        return _previousOwner;
    }

    function value() external view returns (uint) {
        return _value;
    }

    function creationDate() external view returns (uint) {
        _creationDate;
    }

    function _destroyDeed() internal {
        require(!active);

        // Instead of selfdestruct(owner), invoke owner fallback function to allow
        // owner to log an event if desired; but owner should also be aware that
        // its fallback function can also be invoked by setBalance
        if (_owner.send(address(this).balance)) {
            selfdestruct(burn);
        }
    }
}

// File: ENS.sol



pragma solidity >=0.4.24;

interface ENS {

    // Logged when the owner of a node assigns a new owner to a subnode.
    event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);

    // Logged when the owner of a node transfers ownership to a new account.
    event Transfer(bytes32 indexed node, address owner);

    // Logged when the resolver for a node changes.
    event NewResolver(bytes32 indexed node, address resolver);

    // Logged when the TTL of a node changes
    event NewTTL(bytes32 indexed node, uint64 ttl);


    function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external;
    function setResolver(bytes32 node, address resolver) external;
    function setOwner(bytes32 node, address owner) external;
    function setTTL(bytes32 node, uint64 ttl) external;
    function owner(bytes32 node) external view returns (address);
    function resolver(bytes32 node) external view returns (address);
    function ttl(bytes32 node) external view returns (uint64);

}

// File: HashRegistrar.sol



pragma solidity ^0.5.0;


/*

Temporary Hash Registrar
========================

This is a simplified version of a hash registrar. It is purporsefully limited:
names cannot be six letters or shorter, new auctions will stop after 4 years.

The plan is to test the basic features and then move to a new contract in at most
2 years, when some sort of renewal mechanism will be enabled.
*/


import "./ENS.sol";
import "./DeedImplementation.sol";
import "./Registrar.sol";

/**
 * @title Registrar
 * @dev The registrar handles the auction process for each subnode of the node it owns.
 */
contract HashRegistrar is Registrar {
    ENS public ens;
    bytes32 public rootNode;

    mapping (bytes32 => Entry) _entries;
    mapping (address => mapping (bytes32 => Deed)) public sealedBids;

    uint32 constant totalAuctionLength = 5 days;
    uint32 constant revealPeriod = 48 hours;
    uint32 public constant launchLength = 8 weeks;

    uint constant minPrice = 0.01 ether;
    uint public registryStarted;

    struct Entry {
        Deed deed;
        uint registrationDate;
        uint value;
        uint highestBid;
    }

    modifier inState(bytes32 _hash, Mode _state) {
        require(state(_hash) == _state);
        _;
    }

    modifier onlyOwner(bytes32 _hash) {
        require(state(_hash) == Mode.Owned && msg.sender == _entries[_hash].deed.owner());
        _;
    }

    modifier registryOpen() {
        require(now >= registryStarted && now <= registryStarted + (365 * 4) * 1 days && ens.owner(rootNode) == address(this));
        _;
    }

    /**
     * @dev Constructs a new Registrar, with the provided address as the owner of the root node.
     *
     * @param _ens The address of the ENS
     * @param _rootNode The hash of the rootnode.
     */
    constructor(ENS _ens, bytes32 _rootNode, uint _startDate) public {
        ens = _ens;
        rootNode = _rootNode;
        registryStarted = _startDate > 0 ? _startDate : now;
    }

    /**
     * @dev Start an auction for an available hash
     *
     * @param _hash The hash to start an auction on
     */
    function startAuction(bytes32 _hash) external {
        _startAuction(_hash);
    }

    /**
     * @dev Start multiple auctions for better anonymity
     *
     * Anyone can start an auction by sending an array of hashes that they want to bid for.
     * Arrays are sent so that someone can open up an auction for X dummy hashes when they
     * are only really interested in bidding for one. This will increase the cost for an
     * attacker to simply bid blindly on all new auctions. Dummy auctions that are
     * open but not bid on are closed after a week.
     *
     * @param _hashes An array of hashes, at least one of which you presumably want to bid on
     */
    function startAuctions(bytes32[] calldata _hashes) external {
        _startAuctions(_hashes);
    }

    /**
     * @dev Submit a new sealed bid on a desired hash in a blind auction
     *
     * Bids are sent by sending a message to the main contract with a hash and an amount. The hash
     * contains information about the bid, including the bidded hash, the bid amount, and a random
     * salt. Bids are not tied to any one auction until they are revealed. The value of the bid
     * itself can be masqueraded by sending more than the value of your actual bid. This is
     * followed by a 48h reveal period. Bids revealed after this period will be burned and the ether unrecoverable.
     * Since this is an auction, it is expected that most public hashes, like known domains and common dictionary
     * words, will have multiple bidders pushing the price up.
     *
     * @param sealedBid A sealedBid, created by the shaBid function
     */
    function newBid(bytes32 sealedBid) external payable {
        _newBid(sealedBid);
    }

    /**
     * @dev Start a set of auctions and bid on one of them
     *
     * This method functions identically to calling `startAuctions` followed by `newBid`,
     * but all in one transaction.
     *
     * @param hashes A list of hashes to start auctions on.
     * @param sealedBid A sealed bid for one of the auctions.
     */
    function startAuctionsAndBid(bytes32[] calldata hashes, bytes32 sealedBid) external payable {
        _startAuctions(hashes);
        _newBid(sealedBid);
    }

    /**
     * @dev Submit the properties of a bid to reveal them
     *
     * @param _hash The node in the sealedBid
     * @param _value The bid amount in the sealedBid
     * @param _salt The sale in the sealedBid
     */
    function unsealBid(bytes32 _hash, uint _value, bytes32 _salt) external {
        bytes32 seal = shaBid(_hash, msg.sender, _value, _salt);
        Deed bid = sealedBids[msg.sender][seal];
        require(address(bid) != address(0x0));

        sealedBids[msg.sender][seal] = Deed(address(0x0));
        Entry storage h = _entries[_hash];
        uint value = min(_value, bid.value());
        bid.setBalance(value, true);

        Mode auctionState = state(_hash);
        if (auctionState == Mode.Owned) {
            // Too late! Bidder loses their bid. Gets 0.5% back.
            bid.closeDeed(5);
            emit BidRevealed(_hash, msg.sender, value, 1);
        } else if (auctionState != Mode.Reveal) {
            // Invalid phase
            revert();
        } else if (value < minPrice || bid.creationDate() > h.registrationDate - revealPeriod) {
            // Bid too low or too late, refund 99.5%
            bid.closeDeed(995);
            emit BidRevealed(_hash, msg.sender, value, 0);
        } else if (value > h.highestBid) {
            // New winner
            // Cancel the other bid, refund 99.5%
            if (address(h.deed) != address(0x0)) {
                Deed previousWinner = h.deed;
                previousWinner.closeDeed(995);
            }

            // Set new winner
            // Per the rules of a vickery auction, the value becomes the previous highestBid
            h.value = h.highestBid;  // will be zero if there's only 1 bidder
            h.highestBid = value;
            h.deed = bid;
            emit BidRevealed(_hash, msg.sender, value, 2);
        } else if (value > h.value) {
            // Not winner, but affects second place
            h.value = value;
            bid.closeDeed(995);
            emit BidRevealed(_hash, msg.sender, value, 3);
        } else {
            // Bid doesn't affect auction
            bid.closeDeed(995);
            emit BidRevealed(_hash, msg.sender, value, 4);
        }
    }

    /**
     * @dev Cancel a bid
     *
     * @param seal The value returned by the shaBid function
     */
    function cancelBid(address bidder, bytes32 seal) external {
        Deed bid = sealedBids[bidder][seal];
        
        // If a sole bidder does not `unsealBid` in time, they have a few more days
        // where they can call `startAuction` (again) and then `unsealBid` during
        // the revealPeriod to get back their bid value.
        // For simplicity, they should call `startAuction` within
        // 9 days (2 weeks - totalAuctionLength), otherwise their bid will be
        // cancellable by anyone.
        require(address(bid) != address(0x0) && now >= bid.creationDate() + totalAuctionLength + 2 weeks);

        // Send the canceller 0.5% of the bid, and burn the rest.
        bid.setOwner(msg.sender);
        bid.closeDeed(5);
        sealedBids[bidder][seal] = Deed(0);
        emit BidRevealed(seal, bidder, 0, 5);
    }

    /**
     * @dev Finalize an auction after the registration date has passed
     *
     * @param _hash The hash of the name the auction is for
     */
    function finalizeAuction(bytes32 _hash) external onlyOwner(_hash) {
        Entry storage h = _entries[_hash];
        
        // Handles the case when there's only a single bidder (h.value is zero)
        h.value = max(h.value, minPrice);
        h.deed.setBalance(h.value, true);

        trySetSubnodeOwner(_hash, h.deed.owner());
        emit HashRegistered(_hash, h.deed.owner(), h.value, h.registrationDate);
    }

    /**
     * @dev The owner of a domain may transfer it to someone else at any time.
     *
     * @param _hash The node to transfer
     * @param newOwner The address to transfer ownership to
     */
    function transfer(bytes32 _hash, address payable newOwner) external onlyOwner(_hash) {
        require(newOwner != address(0x0));

        Entry storage h = _entries[_hash];
        h.deed.setOwner(newOwner);
        trySetSubnodeOwner(_hash, newOwner);
    }

    /**
     * @dev After some time, or if we're no longer the registrar, the owner can release
     *      the name and get their ether back.
     *
     * @param _hash The node to release
     */
    function releaseDeed(bytes32 _hash) external onlyOwner(_hash) {
        Entry storage h = _entries[_hash];
        Deed deedContract = h.deed;

        require(now >= h.registrationDate + 365 days || ens.owner(rootNode) != address(this));

        h.value = 0;
        h.highestBid = 0;
        h.deed = Deed(0);

        _tryEraseSingleNode(_hash);
        deedContract.closeDeed(1000);
        emit HashReleased(_hash, h.value);        
    }

    /**
     * @dev Submit a name 6 characters long or less. If it has been registered,
     *      the submitter will earn 50% of the deed value. 
     * 
     * We are purposefully handicapping the simplified registrar as a way 
     * to force it into being restructured in a few years.
     *
     * @param unhashedName An invalid name to search for in the registry.
     */
    function invalidateName(string calldata unhashedName)
        external
        inState(keccak256(abi.encode(unhashedName)), Mode.Owned)
    {
        require(strlen(unhashedName) <= 6);
        bytes32 hash = keccak256(abi.encode(unhashedName));

        Entry storage h = _entries[hash];

        _tryEraseSingleNode(hash);

        if (address(h.deed) != address(0x0)) {
            // Reward the discoverer with 50% of the deed
            // The previous owner gets 50%
            h.value = max(h.value, minPrice);
            h.deed.setBalance(h.value/2, false);
            h.deed.setOwner(msg.sender);
            h.deed.closeDeed(1000);
        }

        emit HashInvalidated(hash, unhashedName, h.value, h.registrationDate);

        h.value = 0;
        h.highestBid = 0;
        h.deed = Deed(0);
    }

    /**
     * @dev Allows anyone to delete the owner and resolver records for a (subdomain of) a
     *      name that is not currently owned in the registrar. If passing, eg, 'foo.bar.eth',
     *      the owner and resolver fields on 'foo.bar.eth' and 'bar.eth' will all be cleared.
     *
     * @param labels A series of label hashes identifying the name to zero out, rooted at the
     *        registrar's root. Must contain at least one element. For instance, to zero 
     *        'foo.bar.eth' on a registrar that owns '.eth', pass an array containing
     *        [keccak256('foo'), keccak256('bar')].
     */
    function eraseNode(bytes32[] calldata labels) external {
        require(labels.length != 0);
        require(state(labels[labels.length - 1]) != Mode.Owned);

        _eraseNodeHierarchy(labels.length - 1, labels, rootNode);
    }

    /**
     * @dev Transfers the deed to the current registrar, if different from this one.
     *
     * Used during the upgrade process to a permanent registrar.
     *
     * @param _hash The name hash to transfer.
     */
    function transferRegistrars(bytes32 _hash) external onlyOwner(_hash) {
        address registrar = ens.owner(rootNode);
        require(registrar != address(this));

        // Migrate the deed
        Entry storage h = _entries[_hash];
        h.deed.setRegistrar(registrar);

        // Call the new registrar to accept the transfer
        Registrar(registrar).acceptRegistrarTransfer(_hash, h.deed, h.registrationDate);

        // Zero out the Entry
        h.deed = Deed(0);
        h.registrationDate = 0;
        h.value = 0;
        h.highestBid = 0;
    }

    /**
     * @dev Accepts a transfer from a previous registrar; stubbed out here since there
     *      is no previous registrar implementing this interface.
     *
     * @param hash The sha3 hash of the label to transfer.
     * @param deed The Deed object for the name being transferred in.
     * @param registrationDate The date at which the name was originally registered.
     */
    function acceptRegistrarTransfer(bytes32 hash, Deed deed, uint registrationDate) external {
        hash; deed; registrationDate; // Don't warn about unused variables
    }

    function entries(bytes32 _hash) external view returns (Mode, address, uint, uint, uint) {
        Entry storage h = _entries[_hash];
        return (state(_hash), address(h.deed), h.registrationDate, h.value, h.highestBid);
    }

    // State transitions for names:
    //   Open -> Auction (startAuction)
    //   Auction -> Reveal
    //   Reveal -> Owned
    //   Reveal -> Open (if nobody bid)
    //   Owned -> Open (releaseDeed or invalidateName)
    function state(bytes32 _hash) public view returns (Mode) {
        Entry storage entry = _entries[_hash];

        if (!isAllowed(_hash, now)) {
            return Mode.NotYetAvailable;
        } else if (now < entry.registrationDate) {
            if (now < entry.registrationDate - revealPeriod) {
                return Mode.Auction;
            } else {
                return Mode.Reveal;
            }
        } else {
            if (entry.highestBid == 0) {
                return Mode.Open;
            } else {
                return Mode.Owned;
            }
        }
    }

    /**
     * @dev Determines if a name is available for registration yet
     *
     * Each name will be assigned a random date in which its auction
     * can be started, from 0 to 8 weeks
     *
     * @param _hash The hash to start an auction on
     * @param _timestamp The timestamp to query about
     */
    function isAllowed(bytes32 _hash, uint _timestamp) public view returns (bool allowed) {
        return _timestamp > getAllowedTime(_hash);
    }

    /**
     * @dev Returns available date for hash
     *
     * The available time from the `registryStarted` for a hash is proportional
     * to its numeric value.
     *
     * @param _hash The hash to start an auction on
     */
    function getAllowedTime(bytes32 _hash) public view returns (uint) {
        return registryStarted + ((launchLength * (uint(_hash) >> 128)) >> 128);
        // Right shift operator: a >> b == a / 2**b
    }

    /**
     * @dev Hash the values required for a secret bid
     *
     * @param hash The node corresponding to the desired namehash
     * @param value The bid amount
     * @param salt A random value to ensure secrecy of the bid
     * @return The hash of the bid values
     */
    function shaBid(bytes32 hash, address owner, uint value, bytes32 salt) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(hash, owner, value, salt));
    }

    function _tryEraseSingleNode(bytes32 label) internal {
        if (ens.owner(rootNode) == address(this)) {
            ens.setSubnodeOwner(rootNode, label, address(this));
            bytes32 node = keccak256(abi.encodePacked(rootNode, label));
            ens.setResolver(node, address(0x0));
            ens.setOwner(node, address(0x0));
        }
    }

    function _startAuction(bytes32 _hash) internal registryOpen() {
        Mode mode = state(_hash);
        if (mode == Mode.Auction) return;
        require(mode == Mode.Open);

        Entry storage newAuction = _entries[_hash];
        newAuction.registrationDate = now + totalAuctionLength;
        newAuction.value = 0;
        newAuction.highestBid = 0;
        emit AuctionStarted(_hash, newAuction.registrationDate);
    }

    function _startAuctions(bytes32[] memory _hashes) internal {
        for (uint i = 0; i < _hashes.length; i ++) {
            _startAuction(_hashes[i]);
        }
    }

    function _newBid(bytes32 sealedBid) internal {
        require(address(sealedBids[msg.sender][sealedBid]) == address(0x0));
        require(msg.value >= minPrice);

        // Creates a new hash contract with the owner
        Deed bid = (new DeedImplementation).value(msg.value)(msg.sender);
        sealedBids[msg.sender][sealedBid] = bid;
        emit NewBid(sealedBid, msg.sender, msg.value);
    }

    function _eraseNodeHierarchy(uint idx, bytes32[] memory labels, bytes32 node) internal {
        // Take ownership of the node
        ens.setSubnodeOwner(node, labels[idx], address(this));
        node = keccak256(abi.encodePacked(node, labels[idx]));

        // Recurse if there are more labels
        if (idx > 0) {
            _eraseNodeHierarchy(idx - 1, labels, node);
        }

        // Erase the resolver and owner records
        ens.setResolver(node, address(0x0));
        ens.setOwner(node, address(0x0));
    }

    /**
     * @dev Assign the owner in ENS, if we're still the registrar
     *
     * @param _hash hash to change owner
     * @param _newOwner new owner to transfer to
     */
    function trySetSubnodeOwner(bytes32 _hash, address _newOwner) internal {
        if (ens.owner(rootNode) == address(this))
            ens.setSubnodeOwner(rootNode, _hash, _newOwner);
    }

    /**
     * @dev Returns the maximum of two unsigned integers
     *
     * @param a A number to compare
     * @param b A number to compare
     * @return The maximum of two unsigned integers
     */
    function max(uint a, uint b) internal pure returns (uint) {
        if (a > b)
            return a;
        else
            return b;
    }

    /**
     * @dev Returns the minimum of two unsigned integers
     *
     * @param a A number to compare
     * @param b A number to compare
     * @return The minimum of two unsigned integers
     */
    function min(uint a, uint b) internal pure returns (uint) {
        if (a < b)
            return a;
        else
            return b;
    }

    /**
     * @dev Returns the length of a given string
     *
     * @param s The string to measure the length of
     * @return The length of the input string
     */
    function strlen(string memory s) internal pure returns (uint) {
        s; // Don't warn about unused variables
        // Starting here means the LSB will be the byte we care about
        uint ptr;
        uint end;
        assembly {
            ptr := add(s, 1)
            end := add(mload(s), ptr)
        }
        uint len = 0;
        for (len; ptr < end; len++) {
            uint8 b;
            assembly { b := and(mload(ptr), 0xFF) }
            if (b < 0x80) {
                ptr += 1;
            } else if (b < 0xE0) {
                ptr += 2;
            } else if (b < 0xF0) {
                ptr += 3;
            } else if (b < 0xF8) {
                ptr += 4;
            } else if (b < 0xFC) {
                ptr += 5;
            } else {
                ptr += 6;
            }
        }
        return len;
    }

}

// File: MultiSigWallet.sol



/**
 * Source Code first verified at https://etherscan.io on Friday, March 3, 2017
 (UTC) */

pragma solidity ^0.5.0;


/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
/// @author Stefan George - <stefan.george@consensys.net>
contract MultiSigWallet {

  uint constant public MAX_OWNER_COUNT = 50;

  event Confirmation(address indexed sender, uint indexed transactionId);
  event Revocation(address indexed sender, uint indexed transactionId);
  event Submission(uint indexed transactionId);
  event Execution(uint indexed transactionId, bytes data);
  event ExecutionFailure(uint indexed transactionId);
  event Deposit(address indexed sender, uint value);
  event OwnerAddition(address indexed owner);
  event OwnerRemoval(address indexed owner);
  event RequirementChange(uint required);

  mapping (uint => Transaction) public transactions;
  mapping (uint => mapping (address => bool)) public confirmations;
  mapping (address => bool) public isOwner;
  address[] public owners;
  uint public required;
  uint public transactionCount;

  struct Transaction {
    address destination;
    uint value;
    bytes data;
    bool executed;
  }

  modifier onlyWallet() {
    if (msg.sender != address(this))
      revert();
    _;
  }

  modifier ownerDoesNotExist(address owner) {
    if (isOwner[owner])
      revert();
    _;
  }

  modifier ownerExists(address owner) {
    if (!isOwner[owner])
      revert();
    _;
  }

  modifier transactionExists(uint transactionId) {
    if (transactions[transactionId].destination == address(0))
      revert();
    _;
  }

  modifier confirmed(uint transactionId, address owner) {
    if (!confirmations[transactionId][owner])
      revert();
    _;
  }

  modifier notConfirmed(uint transactionId, address owner) {
    if (confirmations[transactionId][owner])
      revert();
    _;
  }

  modifier notExecuted(uint transactionId) {
    if (transactions[transactionId].executed)
      revert();
    _;
  }

  modifier notNull(address _address) {
    if (_address == address(0))
      revert();
    _;
  }

  modifier validRequirement(uint ownerCount, uint _required) {
    if (   ownerCount > MAX_OWNER_COUNT
    || _required > ownerCount
    || _required == 0
    || ownerCount == 0)
      revert();
    _;
  }

  /*
   * Public functions
   */
  /// @dev Contract constructor sets initial owners and required number of confirmations.
  /// @param _owners List of initial owners.
  /// @param _required Number of required confirmations.
  constructor(address[] memory _owners, uint _required)
  public
  validRequirement(_owners.length, _required)
  {
    for (uint i=0; i<_owners.length; i++) {
      if (isOwner[_owners[i]] || _owners[i] == address(0))
        revert();
      isOwner[_owners[i]] = true;
    }
    owners = _owners;
    required = _required;
  }

  /// @dev Allows to add a new owner. Transaction has to be sent by wallet.
  /// @param owner Address of new owner.
  function addOwner(address owner)
  public
  onlyWallet
  ownerDoesNotExist(owner)
  notNull(owner)
  validRequirement(owners.length + 1, required)
  {
    isOwner[owner] = true;
    owners.push(owner);
    emit OwnerAddition(owner);
  }

  /// @dev Allows to remove an owner. Transaction has to be sent by wallet.
  /// @param owner Address of owner.
  function removeOwner(address owner)
  public
  onlyWallet
  ownerExists(owner)
  {
    isOwner[owner] = false;
    for (uint i=0; i<owners.length - 1; i++)
      if (owners[i] == owner) {
        owners[i] = owners[owners.length - 1];
        break;
      }
    owners.length -= 1;
    if (required > owners.length)
      changeRequirement(owners.length);
    emit OwnerRemoval(owner);
  }

  /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
  /// @param owner Address of owner to be replaced.
  /// @param owner Address of new owner.
  function replaceOwner(address owner, address newOwner)
  public
  onlyWallet
  ownerExists(owner)
  ownerDoesNotExist(newOwner)
  {
    for (uint i=0; i<owners.length; i++)
      if (owners[i] == owner) {
        owners[i] = newOwner;
        break;
      }
    isOwner[owner] = false;
    isOwner[newOwner] = true;
    emit OwnerRemoval(owner);
    emit OwnerAddition(newOwner);
  }

  /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
  /// @param _required Number of required confirmations.
  function changeRequirement(uint _required)
  public
  onlyWallet
  validRequirement(owners.length, _required)
  {
    required = _required;
    emit RequirementChange(_required);
  }

  /// @dev Allows an owner to submit and confirm a transaction.
  /// @param destination Transaction target address.
  /// @param value Transaction ether value.
  /// @param data Transaction data payload.
  /// @return Returns transaction ID.
  function submitTransaction(address destination, uint value, bytes memory data)
  public
  returns (uint transactionId)
  {
    transactionId = addTransaction(destination, value, data);
    confirmTransaction(transactionId);
  }

  /// @dev Allows an owner to confirm a transaction.
  /// @param transactionId Transaction ID.
  function confirmTransaction(uint transactionId)
  public
  ownerExists(msg.sender)
  transactionExists(transactionId)
  notConfirmed(transactionId, msg.sender)
  {
    confirmations[transactionId][msg.sender] = true;
    emit Confirmation(msg.sender, transactionId);
    executeTransaction(transactionId);
  }

  /// @dev Allows an owner to revoke a confirmation for a transaction.
  /// @param transactionId Transaction ID.
  function revokeConfirmation(uint transactionId)
  public
  ownerExists(msg.sender)
  confirmed(transactionId, msg.sender)
  notExecuted(transactionId)
  {
    confirmations[transactionId][msg.sender] = false;
    emit Revocation(msg.sender, transactionId);
  }

  /// @dev Allows anyone to execute a confirmed transaction.
  /// @param transactionId Transaction ID.
  function executeTransaction(uint transactionId)
  public
  notExecuted(transactionId)
  {
    if (isConfirmed(transactionId)) {
      Transaction storage tx = transactions[transactionId];
      tx.executed = true;
      bool success;
      (success,) = tx.destination.call.value(tx.value)(tx.data);
      if (success)
        emit Execution(transactionId, tx.data);
      else {
        emit ExecutionFailure(transactionId);
        tx.executed = false;
      }
    }
  }

  /// @dev Returns the confirmation status of a transaction.
  /// @param transactionId Transaction ID.
  /// @return Confirmation status.
  function isConfirmed(uint transactionId)
  public
  view
  returns (bool)
  {
    uint count = 0;
    for (uint i=0; i<owners.length; i++) {
      if (confirmations[transactionId][owners[i]])
        count += 1;
      if (count == required)
        return true;
    }
  }

  /*
   * Internal functions
   */
  /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
  /// @param destination Transaction target address.
  /// @param value Transaction ether value.
  /// @param data Transaction data payload.
  /// @return Returns transaction ID.
  function addTransaction(address destination, uint value, bytes memory data)
  internal
  notNull(destination)
  returns (uint transactionId)
  {
    transactionId = transactionCount;
    transactions[transactionId] = Transaction({
      destination: destination,
      value: value,
      data: data,
      executed: false
      });
    transactionCount += 1;
    emit Submission(transactionId);
  }

  /*
   * Web3 call functions
   */
  /// @dev Returns number of confirmations of a transaction.
  /// @param transactionId Transaction ID.
  /// @return Number of confirmations.
  function getConfirmationCount(uint transactionId)
  public
  view
  returns (uint count)
  {
    for (uint i=0; i<owners.length; i++)
      if (confirmations[transactionId][owners[i]])
        count += 1;
  }

  /// @dev Returns total number of transactions after filers are applied.
  /// @param pending Include pending transactions.
  /// @param executed Include executed transactions.
  /// @return Total number of transactions after filters are applied.
  function getTransactionCount(bool pending, bool executed)
  public
  view
  returns (uint count)
  {
    for (uint i=0; i<transactionCount; i++)
      if (   pending && !transactions[i].executed
      || executed && transactions[i].executed)
        count += 1;
  }

  /// @dev Returns list of owners.
  /// @return List of owner addresses.
  function getOwners()
  public
  view
  returns (address[] memory)
  {
    return owners;
  }

  /// @dev Returns array with owner addresses, which confirmed transaction.
  /// @param transactionId Transaction ID.
  /// @return Returns array of owner addresses.
  function getConfirmations(uint transactionId)
  public
  view
  returns (address[] memory _confirmations)
  {
    address[] memory confirmationsTemp = new address[](owners.length);
    uint count = 0;
    uint i;
    for (i=0; i<owners.length; i++)
      if (confirmations[transactionId][owners[i]]) {
        confirmationsTemp[count] = owners[i];
        count += 1;
      }
    _confirmations = new address[](count);
    for (i=0; i<count; i++)
      _confirmations[i] = confirmationsTemp[i];
  }

  /// @dev Returns list of transaction IDs in defined range.
  /// @param from Index start position of transaction array.
  /// @param to Index end position of transaction array.
  /// @param pending Include pending transactions.
  /// @param executed Include executed transactions.
  /// @return Returns array of transaction IDs.
  function getTransactionIds(uint from, uint to, bool pending, bool executed)
  public
  view
  returns (uint[] memory _transactionIds)
  {
    uint[] memory transactionIdsTemp = new uint[](transactionCount);
    uint count = 0;
    uint i;
    for (i=0; i<transactionCount; i++)
      if (   pending && !transactions[i].executed
      || executed && transactions[i].executed)
      {
        transactionIdsTemp[count] = i;
        count += 1;
      }
    _transactionIds = new uint[](to - from);
    for (i=from; i<to; i++)
      _transactionIds[i - from] = transactionIdsTemp[i];
  }
}
// File: NameBazaarRescue.sol



pragma solidity ^0.5.0;

import "./Root.sol";

import "./Offering.sol";
import "./OfferingRegistry.sol";
import "./MultiSigWallet.sol";

contract NameBazaarRescue is Ownable {
  bytes32 constant public ETH_NODE = 0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;
  bytes32 constant public ETH_LABEL = 0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0;

  Root public root;
  OfferingRegistry public offeringRegistry;
  address public previousRegistrar;

  event ReclaimSuccess(address offering, uint transactionId);

  constructor(address _root, address _offeringRegistry, address _previousRegistrar) public {
    require(_root != address(0));
    require(_offeringRegistry != address(0));
    require(_previousRegistrar != address(0));

    root = Root(_root);
    offeringRegistry = OfferingRegistry(_offeringRegistry);
    previousRegistrar = _previousRegistrar;
  }

  function reclaimOwnerships(address[] memory offerings) public onlyOwner {
    address originalNodeOwner = root.ens().owner(ETH_NODE);
    MultiSigWallet emergencyMultisig = MultiSigWallet(offeringRegistry.emergencyMultisig());

    root.setSubnodeOwner(ETH_LABEL, previousRegistrar);

    for (uint i = 0; i < offerings.length; i++) {
      require(offeringRegistry.isOffering(offerings[i]));
      bool executed = false;
      uint txId = emergencyMultisig.submitTransaction(offerings[i], 0, abi.encodeWithSignature("reclaimOwnership()"));
      (,,,executed) = emergencyMultisig.transactions(txId);

      if (executed) {
        emit ReclaimSuccess(offerings[i], txId);
      } else {
        revert("reclaimOwnership transaction couldn't be executed");
      }
    }

    root.setSubnodeOwner(ETH_LABEL, originalNodeOwner);
  }

}

// File: Offering.sol



pragma solidity ^0.5.0;

/**
 * @title Offering
 * @dev Contains base logic for an offering and is meant to be extended.
 */

import "./ENS.sol";
import "./HashRegistrar.sol";
import "./OfferingRegistry.sol";
import "./Address.sol";

contract Offering {

    struct Offering {
        // Order here is important for gas optimisations. Must be fitting into uint265 slots.
        bytes32 node;                       // ENS node
        // WARNING: The contract DOES NOT perform ENS name normalisation, which is up to responsibility of each offchain UI!
        string name;                        // full ENS name
        bytes32 labelHash;                  // hash of ENS label
        address originalOwner;              // owner of ENS name, creator of offering
        address newOwner;                   // Address of a new owner of ENS name, buyer
        uint price;                         // Price of the offering, or the highest bid in auction
        uint128 version;                    // version of offering contract
        uint64 createdOn;                   // Time when offering was created
        uint64 finalizedOn;                 // Time when ENS name was transferred to a new owner
    }

    Offering public offering;

    // Hardcoded ENS address. For development will be replaced after compilation. This way we save gas to users deploying offering contracts.
    ENS public ens = ENS(0x314159265dD8dbb310642f98f50C066173C1259b);

    // Hardcoded namehash of "eth"
    bytes32 public constant rootNode = 0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;

    // Placeholder to be replaced after compilation. This way we save gas to users deploying offering contracts.
    OfferingRegistry public offeringRegistry = OfferingRegistry(0xfEEDFEEDfeEDFEedFEEdFEEDFeEdfEEdFeEdFEEd);

    // Placeholder to be replaced after compilation. This way we save gas to users deploying offering contracts.
    address public emergencyMultisig = 0xDeEDdeeDDEeDDEEdDEedDEEdDEeDdEeDDEEDDeed;

    constructor(ENS _ens, OfferingRegistry _offeringRegistry, address _emergencyMultisig) public {
        ens = _ens;
        offeringRegistry = _offeringRegistry;
        emergencyMultisig = _emergencyMultisig;
    }

    /**
     * @dev Modifier to make a function callable only for offering creator
     */
    modifier onlyOriginalOwner() {
        require(isSenderOriginalOwner());
        _;
    }

    /**
     * @dev Modifier to make a function callable only for Namebazaar's Emergency Multisig wallet
     */
    modifier onlyEmergencyMultisig() {
        require(isSenderEmergencyMultisig());
        _;
    }

    /**
     * @dev Modifier to make a function callable only is called by Namebazaar's Emergency Multisig wallet
     */
    modifier onlyWithoutNewOwner() {
        require(offering.newOwner == address(0));
        _;
    }

    /**
     * @dev Modifier to make a function callable only when offering contract has name ownership
     */
    modifier onlyWhenContractIsNodeOwner() {
        require(isContractNodeOwner());
        _;
    }


    /**
     * @dev Modifier to make a function callable only when there's not emergency pause
     */
    modifier onlyWhenNotEmergencyPaused() {
        require(!offeringRegistry.isEmergencyPaused());
        _;
    }

    /**
     * @dev Modifier to make a function callable only when offering contract doesn't have name ownership
     */
    modifier onlyWhenContractIsNotNodeOwner() {
        require(!isContractNodeOwner());
        _;
    }

    /**
     * @dev Constructor of offering
     * Should be callable just once, by factory
     */
    function construct(
        bytes32 _node,
        string memory _name,
        bytes32 _labelHash,
        address _originalOwner,
        uint128 _version,
        uint _price
    )
    public
    onlyWhenNotEmergencyPaused
    {
        require(offering.createdOn == 0);               // Prevent constructing multiple times
        offering.node = _node;
        offering.name = _name;
        offering.labelHash = _labelHash;
        offering.originalOwner = _originalOwner;
        offering.version = _version;
        offering.createdOn = uint64(now);
        offering.price = _price;
    }

    /**
     * @dev Unregisters offering for not displaying it in UI
     * Cannot be run if contract has ownership or it was already transferred to new owner
     */
    function unregister()
    public
    onlyOriginalOwner
    onlyWithoutNewOwner
    onlyWhenContractIsNotNodeOwner
    {
        // New owner is not really this address, but it's the way to recogize if offering
        // was unregistered without having separate var for it, which is costly
        offering.newOwner = address(0xdeaddead);
        fireOnChanged("unregister");
    }

    /**
    * @dev Transfers ENS name ownership back to original owner
    * Can be run only by original owner or emergency multisig
    * Sets newOwner to special address 0xdead
    */
    function reclaimOwnership()
    public
    onlyWithoutNewOwner
    {
        bool isEmergency = isSenderEmergencyMultisig();
        require(isEmergency || isSenderOriginalOwner());

        if (isContractNodeOwner()) {
            doTransferOwnership(offering.originalOwner);
        }
        if (isEmergency) {
            // New owner is not really this address, but it's the way to recogize if
            // was disabled in emergency without having separate var for it, which is costly
            offering.newOwner = address(0xdead);
        }
        fireOnChanged("reclaimOwnership");
    }

    /**
    * @dev Transfers name ownership in context of offering contract
    * Cannot be run if ownership was already transferred to new owner
    * @param _newOwner address New owner of ENS name
    */
    function transferOwnership(address _newOwner)
    internal
    onlyWhenNotEmergencyPaused
    onlyWithoutNewOwner
    {
        offering.newOwner = _newOwner;
        offering.finalizedOn = uint64(now);
        doTransferOwnership(_newOwner);
        fireOnChanged("finalize");
    }

    /**
    * @dev Function to actually do ENS transfer
    * Top level names should be transferred via registrar, so deed is transferred too
    * @param _newOwner address New owner of ENS name
    */
    function doTransferOwnership(address _newOwner)
    private
    {
        address payable newOwner = address(uint160(_newOwner));
        if (isNodeTLDOfRegistrar()) {
            HashRegistrar(ens.owner(rootNode)).transfer(offering.labelHash, newOwner);
        } else {
            ens.setOwner(offering.node, newOwner);
        }
    }

    function doSetSettings(uint _price)
    internal
    {
        offering.price = _price;
    }

    function fireOnChanged(bytes32 eventType, uint[] memory extraData)
    internal
    {
        offeringRegistry.fireOnOfferingChanged(offering.version, eventType, extraData);
    }

    function fireOnChanged(bytes32 eventType) internal {
        fireOnChanged(eventType, new uint[](0));
    }

    /**
    * @dev Returns whether offering contract is owner of ENS name
    * For top level names, offering contract must be also owner of registrar deed
    * @return bool true if contract is ENS node owner
    */
    function isContractNodeOwner() public view returns(bool) {
        if (isNodeTLDOfRegistrar()) {
            address deed;
            (,deed,,,) = HashRegistrar(ens.owner(rootNode)).entries(offering.labelHash);
            return ens.owner(offering.node) == address(this) &&
            Deed(deed).owner() == address(this);
        } else {
            return ens.owner(offering.node) == address(this);
        }
    }

    /**
    * @dev Exchanges funds of new owner for ownership of ENS name owner
    * msg.value must exactly equal to offering price
    */
    function buy()
    public
    payable
    {
        require(msg.value == offering.price);
        address payable origOwner = address(uint160(offering.originalOwner));
        origOwner.transfer(offering.price);
        transferOwnership(msg.sender);
    }

    /**
    * @dev Returns whether offering node is top level name of registrar or subname
    * @return bool true if offering node is top level name of registrar
    */
    function isNodeTLDOfRegistrar() public view returns (bool) {
        return offering.node == keccak256(abi.encodePacked(rootNode, offering.labelHash));
    }

    /**
    * @dev Returns whether msg.sender is original owner of ENS name, offering creator
    * @return bool true if msg.sender is original owner
    */
    function isSenderOriginalOwner() public view returns(bool) {
        return msg.sender == offering.originalOwner;
    }

    /**
    * @dev Returns whether msg.sender is emergency multisig address
    * @return bool true if msg.sender is emergency multisig
    */
    function isSenderEmergencyMultisig() public view returns(bool) {
        return msg.sender == emergencyMultisig;
    }

    /**
    * @dev Returns whether offerring was cancelled in emergency, by emergency multisig
    * @return bool true if offering was cancelled in emergency
    */
    function wasEmergencyCancelled() public view returns(bool) {
        return offering.newOwner == address(0xdead);
    }
}

// File: OfferingFactory.sol



pragma solidity ^0.5.0;

import "./OfferingRegistry.sol";
import "./Offering.sol";
import "./ENS.sol";
import "./HashRegistrar.sol";

/**
 * @title OfferingFactory
 * @dev Base contract factory for creating new offerings
 */

contract OfferingFactory {

    ENS public ens;
    OfferingRegistry public offeringRegistry;

    // Hardcoded namehash of "eth"
    bytes32 public constant rootNode = 0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;

    constructor (
        ENS _ens,
        OfferingRegistry _offeringRegistry
    ) public {
        ens = _ens;
        offeringRegistry = _offeringRegistry;
    }

    /**
    * @dev Deploys new BuyNow offering and registers it to OfferingRegistry
    * @param name string Plaintext ENS name
    * @param price uint The price of the offering
    */
    function createOffering(
        bytes32 node,
        string memory name,
        bytes32 labelHash,
        uint price
    ) public {
        Offering newOffering = new Offering(ens, offeringRegistry, offeringRegistry.emergencyMultisig());
        uint8 version = 1;

        newOffering.construct(
            node,
            name,
            labelHash,
            msg.sender,
            version,
            price
        );

        registerOffering(node, labelHash, address(newOffering), version);
    }

    /**
    * @dev Registers new offering to OfferingRegistry, clears offering requests for this ENS node
    * Must check if creator of offering is actual owner of ENS name and for top level names also deed owner
    * @param node bytes32 ENS node
    * @param labelHash bytes32 ENS labelhash
    * @param newOffering address The address of new offering
    * @param version uint The version of offering contract
    */
    function registerOffering(bytes32 node, bytes32 labelHash, address newOffering, uint version)
        internal
    {
        require(ens.owner(node) == msg.sender);
        if (node == keccak256(abi.encodePacked(rootNode, labelHash))) {
            address deed;
            (,deed,,,) = HashRegistrar(ens.owner(rootNode)).entries(labelHash);
            require(Deed(deed).owner() == msg.sender);
        }

        offeringRegistry.addOffering(newOffering, node, msg.sender, version);
    }
}
// File: OfferingRegistry.sol



pragma solidity ^0.5.0;


import "./UsedByFactories.sol";


/**
 * @title OfferingRegistry
 * @dev Offering registry is responsible to firing event each time offering is created or changed
 * This is mostly for offchain search DB to keep easily in sync
 */

contract OfferingRegistry is UsedByFactories {

  event onOfferingAdded(address indexed offering, bytes32 indexed node, address indexed owner, uint version);
  event onOfferingChanged(address indexed offering, uint version, bytes32 indexed eventType, uint[] extraData);

  address public emergencyMultisig;                           // Emergency Multisig wallet of Namebazaar
  bool public isEmergencyPaused = false;                      // Variable to pause buying activity on all offerings
  mapping (address => bool) public isOffering;                // Stores whether given address of namebazaar offering


  /**
   * @dev Modifier to make a function callable only by Namebazaar Multisig wallet
   */
  modifier onlyEmergencyMultisig() {
    require(msg.sender == emergencyMultisig);
    _;
  }

  constructor(address _emergencyMultisig) public {
    emergencyMultisig = _emergencyMultisig;
  }

  /**
   * @dev Serves as central point for firing event when new offering is created
   * Only offering factory can run this function
   * @param offering address Address of newly created offering
   * @param node bytes32 ENS node associated with new offering
   * @param owner address Owner of the ENS name and creator of the offering
   * @param version uint Version of offering contract
   */
  function addOffering(address offering, bytes32 node, address owner, uint version)
  public
  onlyFactory
  {
    isOffering[offering] = true;
    emit onOfferingAdded(offering, node, owner, version);
  }


  /**
   * @dev Serves as central point for firing event when offering state has been changed in any way
   * Only offering contract can run this function
   * @param version uint Version of offering contract
   * @param eventType base32 Short string identifying offering change
   * @param extraData uint[] Arbitrary data associated with event
   */
  function fireOnOfferingChanged(uint version, bytes32 eventType, uint[] memory extraData) public {
    require(isOffering[msg.sender]);
    emit onOfferingChanged(msg.sender, version, eventType, extraData);
  }

  /**
   * @dev Function to activate emergency pause. This should stop buying activity on all offerings
   * Only Emergency Multisig wallet should be able to call this
   */
  function emergencyPause() onlyEmergencyMultisig public {
    isEmergencyPaused = true;
  }

  /**
   * @dev Function to deactivate emergency pause. This should allow buying activity on all offerings again
   * Only Emergency Multisig wallet should be able to call this
   */
  function emergencyRelease() onlyEmergencyMultisig public {
    isEmergencyPaused = false;
  }
}
// File: Ownable.sol



pragma solidity ^0.5.0;

contract Ownable {

    address public owner;

    modifier onlyOwner {
        require(isOwner(msg.sender));
        _;
    }

    constructor() public {
        owner = msg.sender;
    }

    function transferOwnership(address newOwner) public onlyOwner {
        owner = newOwner;
    }

    function isOwner(address addr) public view returns (bool) {
        return owner == addr;
    }
}

// File: Registrar.sol



pragma solidity >=0.4.24;

import "./Deed.sol";

interface Registrar {

    enum Mode { Open, Auction, Owned, Forbidden, Reveal, NotYetAvailable }

    event AuctionStarted(bytes32 indexed hash, uint registrationDate);
    event NewBid(bytes32 indexed hash, address indexed bidder, uint deposit);
    event BidRevealed(bytes32 indexed hash, address indexed owner, uint value, uint8 status);
    event HashRegistered(bytes32 indexed hash, address indexed owner, uint value, uint registrationDate);
    event HashReleased(bytes32 indexed hash, uint value);
    event HashInvalidated(bytes32 indexed hash, string indexed name, uint value, uint registrationDate);

    function startAuction(bytes32 _hash) external;
    function startAuctions(bytes32[] calldata _hashes) external;
    function newBid(bytes32 sealedBid) external payable;
    function startAuctionsAndBid(bytes32[] calldata hashes, bytes32 sealedBid) external payable;
    function unsealBid(bytes32 _hash, uint _value, bytes32 _salt) external;
    function cancelBid(address bidder, bytes32 seal) external;
    function finalizeAuction(bytes32 _hash) external;
    function transfer(bytes32 _hash, address payable newOwner) external;
    function releaseDeed(bytes32 _hash) external;
    function invalidateName(string calldata unhashedName) external;
    function eraseNode(bytes32[] calldata labels) external;
    function transferRegistrars(bytes32 _hash) external;
    function acceptRegistrarTransfer(bytes32 hash, Deed deed, uint registrationDate) external;
    function entries(bytes32 _hash) external view returns (Mode, address, uint, uint, uint);
}

// File: Root.sol



pragma solidity ^0.5.0;

import "./ENS.sol";
import "./Ownable.sol";
import "./Controllable.sol";

contract Root is Ownable, Controllable {
    bytes32 constant private ROOT_NODE = bytes32(0);

    bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));

    event TLDLocked(bytes32 indexed label);

    ENS public ens;
    mapping(bytes32=>bool) public locked;

    constructor(ENS _ens) public {
        ens = _ens;
    }

    function setSubnodeOwner(bytes32 label, address owner) external onlyController {
        require(!locked[label]);
        ens.setSubnodeOwner(ROOT_NODE, label, owner);
    }

    function setResolver(address resolver) external onlyOwner {
        ens.setResolver(ROOT_NODE, resolver);
    }

    function lock(bytes32 label) external onlyOwner {
        emit TLDLocked(label);
        locked[label] = true;
    }

    function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
        return interfaceID == INTERFACE_META_ID;
    }
}

// File: UsedByFactories.sol



pragma solidity ^0.5.0;

import "./Ownable.sol";

/**
 * @title UsedByFactories
 * @dev Provides modifiers to allow only offering factory contracts to execute method
 */

contract UsedByFactories is Ownable {

    mapping(address => bool) public isFactory;

    modifier onlyFactory() {
        require(isFactory[msg.sender]);
        _;
    }

    function setFactories(address[] memory factories, bool _isFactory)
    public
    onlyOwner
    {
        for(uint i = 0; i < factories.length; i++) {
            isFactory[factories[i]] = _isFactory;
        }
    }
}