Burrowsource, exactly what is deployedall files

src/BurrowValuer.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

/*
 * OpenZeppelin Contracts v5.0.2: Context, Ownable and Ownable2Step are
 * included below to make this single-file submission build offline.
 * Only contract identifiers are prefixed with BurrowValuer; imports and
 * duplicate pragma/license headers are removed. The implementation is unchanged.
 * Source: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.0.2/contracts
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2023 zOS Global Limited and contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

// OpenZeppelin Contracts (last updated v5.0.1) (utils/BurrowValuerContext.sol)

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract BurrowValuerContext {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// OpenZeppelin Contracts (last updated v5.0.0) (access/BurrowValuerOwnable.sol)

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract BurrowValuerOwnable is BurrowValuerContext {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// OpenZeppelin Contracts (last updated v5.0.0) (access/BurrowValuerOwnable2Step.sol)

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `BurrowValuerOwnable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (BurrowValuerOwnable).
 */
abstract contract BurrowValuerOwnable2Step is BurrowValuerOwnable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

/// @dev The Squeek NFT's level is one-based; it is not a staking position.
interface IBurrowValuerSqueekNFT {
    function ownerOf(uint256 tokenId) external view returns (address);
    function level(uint256 tokenId) external view returns (uint8);
}
/// @dev Squeekchain staking publishes the mining power of each level. Reading it live keeps
///      valuation equal to what the chain actually pays for the NFT; no table to drift.
interface IBurrowValuerStaking {
    function basePower(address collection, uint8 level) external view returns (uint256);
}

/// @title BurrowValuer
/// @notice Values up to 32 distinct Squeek NFTs in SQK base units.
/// @dev Unaudited, testnet only. Power is Squeekchain staking's basePower for the
///      NFT's level (1000, 2200, 4840, ... on Sepolia), and pricePerPower is SQK base
///      units (18 decimals) per one power. Consequently
///      creditLine = floor(sum(power) * pricePerPower * ltvBps / 10_000).
///      The collection, staking source, LTV and price band cannot be changed.
///      The owner may only govern price within the band and rate limit, through
///      a two-day delay. This contract never holds or moves collateral.
contract BurrowValuer is BurrowValuerOwnable2Step {
    uint256 public constant BPS = 10_000;
    uint256 public constant MAX_LTV_BPS = 6_000;
    uint256 public constant MAX_PRICE_CHANGE_BPS = 2_000;
    uint256 public constant PRICE_TIMELOCK = 2 days;
    uint256 public constant MAX_TOKEN_IDS = 32;
    /// @dev Power per NFT is bounded so 32 NFTs at maxPricePerPower never overflow.
    uint256 public constant MAX_POWER = 1e24;

    IBurrowValuerSqueekNFT public immutable squeekNFT;
    IBurrowValuerStaking public immutable staking;
    uint256 public immutable minPricePerPower;
    uint256 public immutable maxPricePerPower;
    uint256 public immutable ltvBps;

    uint256 public pricePerPower;
    uint256 public pendingPricePerPower;
    uint256 public priceChangeReadyAt;

    /// @notice Timestamp of the last EXECUTED price change; zero before any change.
    /// @dev The vault must reject liquidation until lastPriceChange + 1 hours
    ///      after an execution. A proposal or cancellation does not change this.
    uint256 public lastPriceChange;

    error InvalidCollection(address collection);
    error InvalidLtvBps(uint256 supplied);
    error InvalidPriceBand(uint256 minimum, uint256 maximum);
    error InvalidStaking(address staking);
    error PowerTooLarge(uint256 level, uint256 power);
    error TooManyTokenIds(uint256 supplied);
    error TokenIdsNotStrictlyAscending(uint256 previous, uint256 current);
    error InvalidToken(uint256 tokenId);
    error LevelReadFailed(uint256 tokenId);
    error UnsupportedLevel(uint256 level);
    error PriceOutsideBand(uint256 supplied);
    error PriceUnchanged();
    error PriceChangeTooLarge(uint256 oldPrice, uint256 newPrice);
    error NoPendingPriceChange();
    error PriceChangeNotReady(uint256 readyAt);

    event PriceProposed(uint256 oldPrice, uint256 newPrice, uint256 readyAt);
    event PriceExecuted(uint256 oldPrice, uint256 newPrice);
    event PriceProposalCancelled(uint256 proposedPrice);

    /// @param initialOwner Explicit governance address; ownership transfers take two steps.
    /// @param collection The live Squeek ERC721, supplied by the deployer.
    /// @param staking_ Squeekchain staking, read for basePower(collection, level).
    /// @param initialPrice Initial SQK base units per power, within the immutable band.
    /// @param minimumPrice Nonzero inclusive floor for pricePerPower.
    /// @param maximumPrice Inclusive ceiling; bounded so 32 NFTs of MAX_POWER fit uint256.
    /// @param initialLtvBps Fixed loan-to-value ratio, at most 6000 basis points.
    constructor(
        address initialOwner,
        address collection,
        address staking_,
        uint256 initialPrice,
        uint256 minimumPrice,
        uint256 maximumPrice,
        uint256 initialLtvBps
    ) BurrowValuerOwnable(initialOwner) {
        if (collection.code.length == 0) revert InvalidCollection(collection);
        if (staking_.code.length == 0) revert InvalidStaking(staking_);
        if (initialLtvBps == 0 || initialLtvBps > MAX_LTV_BPS) revert InvalidLtvBps(initialLtvBps);
        if (minimumPrice == 0 || minimumPrice > maximumPrice) {
            revert InvalidPriceBand(minimumPrice, maximumPrice);
        }
        if (initialPrice < minimumPrice || initialPrice > maximumPrice) {
            revert PriceOutsideBand(initialPrice);
        }
        if (maximumPrice > type(uint256).max / (MAX_POWER * MAX_TOKEN_IDS)) {
            revert InvalidPriceBand(minimumPrice, maximumPrice);
        }
        // Level one must be priced by the staking contract, or nothing can ever be valued.
        if (IBurrowValuerStaking(staking_).basePower(collection, 1) == 0) revert InvalidStaking(staking_);

        squeekNFT = IBurrowValuerSqueekNFT(collection);
        staking = IBurrowValuerStaking(staking_);
        minPricePerPower = minimumPrice;
        maxPricePerPower = maximumPrice;
        pricePerPower = initialPrice;
        ltvBps = initialLtvBps;
    }

    /// @notice Maximum debt, rounded down once after summing collateral power.
    /// @dev Empty collateral has a zero line. IDs must be strictly ascending.
    function creditLine(uint256[] calldata tokenIds) external view returns (uint256) {
        uint256 value = collateralValue(tokenIds);
        // Quotient/remainder decomposition is exactly floor(value * LTV / BPS)
        // without overflowing the intermediate product for large valid bands.
        return (value / BPS) * ltvBps + (value % BPS) * ltvBps / BPS;
    }

    /// @notice Undiscounted SQK value, before LTV, also usable for NFT bonds.
    function collateralValue(uint256[] calldata tokenIds) public view returns (uint256) {
        return totalPower(tokenIds) * pricePerPower;
    }

    /// @notice Sum of the immutable table powers for the NFTs' current levels.
    /// @dev The caller (vault) is responsible for escrow and ownership checks for
    ///      its borrower; valuation remains valid while staking owns the NFTs.
    function totalPower(uint256[] calldata tokenIds) public view returns (uint256 power) {
        uint256 count = tokenIds.length;
        if (count > MAX_TOKEN_IDS) revert TooManyTokenIds(count);
        for (uint256 i; i < count; ++i) {
            if (i != 0 && tokenIds[i] <= tokenIds[i - 1]) {
                revert TokenIdsNotStrictlyAscending(tokenIds[i - 1], tokenIds[i]);
            }
            power += powerOf(tokenIds[i]);
        }
    }

    /// @notice Power of one existing NFT, independent of its current custodian.
    function powerOf(uint256 tokenId) public view returns (uint256) {
        // Check existence independently: a mapping-backed level getter might
        // retain a burned NFT's level. Never credit that stale collateral.
        try squeekNFT.ownerOf(tokenId) returns (address tokenOwner) {
            if (tokenOwner == address(0)) revert InvalidToken(tokenId);
        } catch {
            revert InvalidToken(tokenId);
        }
        try squeekNFT.level(tokenId) returns (uint8 nftLevel) {
            return powerForLevel(nftLevel);
        } catch {
            revert LevelReadFailed(tokenId);
        }
    }

    /// @notice Squeekchain's own mining power for a one-based NFT level. Fails closed
    ///         on levels the chain does not price (returns zero) or prices absurdly.
    function powerForLevel(uint256 nftLevel) public view returns (uint256 power) {
        if (nftLevel == 0 || nftLevel > type(uint8).max) revert UnsupportedLevel(nftLevel);
        power = staking.basePower(address(squeekNFT), uint8(nftLevel));
        if (power == 0) revert UnsupportedLevel(nftLevel);
        if (power > MAX_POWER) revert PowerTooLarge(nftLevel, power);
    }

    /// @notice Propose a price. Replacing a pending proposal restarts the full delay.
    function proposePricePerPower(uint256 newPrice) external onlyOwner {
        _validatePriceChange(newPrice);
        pendingPricePerPower = newPrice;
        priceChangeReadyAt = block.timestamp + PRICE_TIMELOCK;
        emit PriceProposed(pricePerPower, newPrice, priceChangeReadyAt);
    }

    /// @notice Apply the sole pending proposal after two days, consuming it once.
    function executePricePerPower() external onlyOwner {
        uint256 newPrice = pendingPricePerPower;
        if (newPrice == 0) revert NoPendingPriceChange();
        if (block.timestamp < priceChangeReadyAt) revert PriceChangeNotReady(priceChangeReadyAt);
        _validatePriceChange(newPrice);

        uint256 oldPrice = pricePerPower;
        delete pendingPricePerPower;
        delete priceChangeReadyAt;
        pricePerPower = newPrice;
        lastPriceChange = block.timestamp;
        emit PriceExecuted(oldPrice, newPrice);
    }

    /// @notice Discard a proposal without moving the price or liquidation timestamp.
    function cancelPriceProposal() external onlyOwner {
        uint256 proposed = pendingPricePerPower;
        if (proposed == 0) revert NoPendingPriceChange();
        delete pendingPricePerPower;
        delete priceChangeReadyAt;
        emit PriceProposalCancelled(proposed);
    }

    function _validatePriceChange(uint256 newPrice) private view {
        if (newPrice < minPricePerPower || newPrice > maxPricePerPower) revert PriceOutsideBand(newPrice);
        uint256 current = pricePerPower;
        if (newPrice == current) revert PriceUnchanged();
        uint256 difference = newPrice > current ? newPrice - current : current - newPrice;
        // 20% = 1/5. Rounding the allowed change DOWN rejects even one wei over
        // the exact limit, in either direction, without current * BPS overflow.
        if (difference > current / (BPS / MAX_PRICE_CHANGE_BPS)) {
            revert PriceChangeTooLarge(current, newPrice);
        }
    }
}