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

import "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title AereNavOracleAdapter — owner-attested per-asset RWA NAV price feed
 * @notice Fixes audit finding F12. AereLendingOracle's FeedType.NavOracle path
 *         calls `IAereNavOracleAdapter(source).latestForAsset(bytes32)` and
 *         expects back a per-asset (nav, timestamp) pair it can normalise to an
 *         18-decimal collateral price. The deployed AereNavOracle
 *         (0xC8D12E44f10b03477330b35115b432750831fEBD) does NOT and CANNOT
 *         satisfy that interface:
 *
 *           - It stores Merkle ROOTS of per-epoch reserve snapshots, not
 *             per-asset values. Given only a bytes32 asset key you cannot
 *             recover a value from a root; you would need the full leaf
 *             preimage (asset, chainId, reserveAmount, decimals) PLUS a Merkle
 *             proof, and even then `verifyReserve` only returns a boolean.
 *           - Its leaf field is a total RESERVE AMOUNT (proof-of-backing, e.g.
 *             "5,000,000 USDC locked on mainnet"), which is a quantity, not a
 *             per-unit price. It does not map to a lending collateral price.
 *
 *         So a passthrough adapter that "reads" the NavOracle is impossible.
 *         The honest fix (audit option (a)) is a PURPOSE-BUILT RWA-NAV price
 *         adapter with an OWNER-SET per-asset value feed — exactly the
 *         "Foundation-attested NAV pulled ... for RWAs that don't have a live
 *         market price" that AereLendingOracle's own NatSpec describes.
 *
 *         DESIGN / SAFETY:
 *           - `setNav` is owner-only (Foundation). The adapter is the upstream
 *             FEED SOURCE for a NavOracle-type feed. The AereLendingOracle
 *             layered on top still enforces its own staleness window and
 *             deviation cap on every read, so a single attested value cannot
 *             jump the lending price beyond `maxDeviationBps`.
 *           - `latestForAsset` returns (0,0) for an un-attested asset, which
 *             AereLendingOracle already treats as InvalidFeedResponse. It never
 *             returns a future-dated timestamp.
 *           - NAV values are stored in the adapter's native decimals; the
 *             consuming feed's `sourceDecimals` handles normalisation. The
 *             Foundation convention is 18-decimal NAVs (sourceDecimals = 18).
 *
 *         PROVENANCE:
 *           - `NAV_ORACLE` records the associated AereNavOracle whose public
 *             Merkle reserve attestations back these assets. It is stored for
 *             transparency ONLY and is NEVER read to derive a price (see above).
 */
contract AereNavOracleAdapter is Ownable {

    /// @notice The associated reserve-attestation oracle (AereNavOracle).
    ///         Recorded for provenance; NOT read to derive prices (its data is
    ///         Merkle-rooted reserve totals, not per-asset prices).
    address public immutable NAV_ORACLE;

    struct Reading {
        uint256 nav;        // per-asset value in the adapter's native decimals (18 by convention)
        uint64 timestamp;   // block.timestamp at attestation
        bool set;
    }

    /// @notice assetKey -> latest attested reading.
    mapping(bytes32 => Reading) public readings;

    /* --------------------------------- events ------------------------------- */

    event NavSet(bytes32 indexed assetKey, uint256 nav, uint64 timestamp);

    /* --------------------------------- errors ------------------------------- */

    error ZeroNav();

    /* ------------------------------- constructor ---------------------------- */

    /// @param navOracle The associated AereNavOracle (provenance only; may be
    ///        address(0) if none). Not read for prices.
    constructor(address navOracle) {
        NAV_ORACLE = navOracle;
    }

    /* --------------------------------- admin -------------------------------- */

    /// @notice Foundation attests the current per-asset NAV for `assetKey`.
    ///         Stamps `block.timestamp` so downstream staleness checks work.
    function setNav(bytes32 assetKey, uint256 nav) external onlyOwner {
        if (nav == 0) revert ZeroNav();
        readings[assetKey] = Reading({ nav: nav, timestamp: uint64(block.timestamp), set: true });
        emit NavSet(assetKey, nav, uint64(block.timestamp));
    }

    /* --------------------------------- view --------------------------------- */

    /// @notice Matches AereLendingOracle's IAereNavOracleAdapter. Returns the
    ///         latest attested (nav, timestamp) for `assetKey`, or (0,0) if the
    ///         asset has never been attested (LendingOracle treats that as
    ///         InvalidFeedResponse).
    function latestForAsset(bytes32 assetKey) external view returns (uint256 nav, uint64 timestamp) {
        Reading storage r = readings[assetKey];
        return (r.nav, r.timestamp);
    }
}
