// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/**
 * @title AereFeeBurnVault
 * @notice Permanent, on-chain burn destination for protocol revenue. Read the
 *         two sections below before quoting any burn number from this contract:
 *         what is burned is not what the whitepaper wording suggests, and the
 *         amount burned to date is effectively zero.
 *
 * WHAT IS BURNED, STATED PRECISELY. The Aere burn is a cut of the VALIDATOR
 * (coinbase) block reward. It is NOT a base-fee burn and NOT a share of
 * transaction fees. The default rate is 37.5% (burnBps = 3750) and it is hard
 * capped at 50%: AereCoinbaseSplitterV2 enforces the cap with the named
 * constant MAX_BURN_BPS = 5000, and AereCoinbaseSplitter (V1) enforces the same
 * ceiling with an unnamed `require(_bps <= 5000)` inside `setBurnBps`. Whitepaper
 * section 3.3 words the burn as a share of all transaction fees; that wording
 * predates the implemented mechanism and is superseded by this paragraph, which
 * matches AERE-PROTOCOL-SPECIFICATION.md, AERE-EIP-COMPATIBILITY-MATRIX.md and
 * AERE-ENGINEERING-SECURITY-SPEC.md, all three of which state in terms that the
 * Aere burn must not be described as a base-fee burn.
 *
 * REALIZED BURN TO DATE, MEASURED. Chain 2800, deployment
 * 0x696afDF4f814e6Fd6aa45CE14C498ed9375fB2c6, measured at block 11,967,981 on
 * 2026-08-02 with `eth_getProof` (not with a nonce read, which can return a
 * false zero outside the public RPC state window):
 *
 *     balance            = 137352594046167719 wei = 0.13735 AERE
 *     totalBurnedAERE()  = 137352594046167719 wei  (identical)
 *     totalSentToZero()  = 0                       (`sweepToZero` has NEVER run)
 *
 * Against a fixed supply of 2,800,000,000 AERE that is about 0.0000000049
 * percent of supply. The reason is arithmetic, not malfunction: validator
 * coinbase revenue on this chain is currently zero, and a percentage of zero is
 * zero. Every burn percentage stated anywhere in this repository is therefore a
 * CONDITIONAL RATE that would apply to future validator revenue, not a
 * description of tokens destroyed to date. AERE is NOT deflationary today.
 * Anyone can recheck both numbers with one `eth_getProof` and one `eth_call`
 * against the address above, and is encouraged to.
 *
 * BYTECODE IDENTITY AFTER THIS CORRECTION, MEASURED. The two sections above are
 * a comment-only change, and a comment-only change still moves the appended CBOR
 * metadata hash, because that hash covers the source text. Recompiled with the
 * profile the deployed contract was built under (solc 0.8.19, optimizer enabled
 * with runs = 200, viaIR = true) and compared byte for byte against the live code
 * at 0x696afDF4f814e6Fd6aa45CE14C498ed9375fB2c6, this file yields the same 1313
 * bytes with ZERO differing bytes outside the metadata trailer. Every difference
 * falls inside that trailer, which is the fingerprint of the source text itself.
 * The executable contract is unchanged; only its fingerprint moved. In Sourcify
 * terms the older text was a full (exact) match and this text is a partial match.
 * The previous, misleading text is what produced the deployed fingerprint; that is
 * a reason to record the fact here, not a reason to keep publishing a false claim.
 *
 * Design:
 *   - Stateless sink: anyone can send native AERE here via `burn()`, or any
 *     ERC-20 via `burnToken()`. The contract has NO withdraw function and
 *     NO admin escape hatch, so funds that enter are permanently removed
 *     from circulation.
 *   - Counters: tracks `totalBurnedAERE` and per-token `totalBurnedToken[token]`
 *     so realized burn can be queried in a single read. `totalBurnedAERE` is a
 *     cumulative arrival counter, not a supply-destruction figure; see the
 *     `sweepToZero` note below for the difference.
 *   - Sources: protocol contracts that earn revenue (AereSwapRouter, the NFT
 *     marketplace, future card-fee router, etc.) can route a configurable
 *     share to this address. The vault does not care WHO sends; any value
 *     arriving here is burned.
 *
 *   This contract holds no privilege over any other system. Ownable is not
 *   needed because there are no admin operations.
 */

interface IERC20 {
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
}

contract AereFeeBurnVault {
    /// Total native AERE that has flowed into this contract.
    /// Equal to address(this).balance EXCEPT after the eventual
    /// "send to zero-address" sweep. See the `sweepToZero` note below.
    uint256 public totalBurnedAERE;

    /// Cumulative native AERE actually forwarded to address(0).
    uint256 public totalSentToZero;

    /// Per-ERC20 lifetime burn counter.
    mapping(address => uint256) public totalBurnedToken;

    event AereBurned(address indexed from, uint256 amount, uint256 newTotal);
    event TokenBurned(address indexed token, address indexed from, uint256 amount, uint256 newTotal);
    event AereSentToZero(uint256 amount, uint256 newTotalSentToZero);

    /// Plain ETH transfer = burn.
    receive() external payable {
        totalBurnedAERE += msg.value;
        emit AereBurned(msg.sender, msg.value, totalBurnedAERE);
    }

    /// Explicit native-AERE burn (same as `receive`, but lets callers attach a tag in the event log).
    function burn() external payable {
        totalBurnedAERE += msg.value;
        emit AereBurned(msg.sender, msg.value, totalBurnedAERE);
    }

    /// Burn an ERC-20 by pulling it from `msg.sender` via prior approval.
    /// Tokens are accepted but never sent anywhere; they stay on this contract
    /// forever. Counters reflect cumulative arrivals.
    function burnToken(address token, uint256 amount) external {
        require(token != address(0), "BurnVault: zero token");
        require(amount > 0, "BurnVault: zero amount");
        require(IERC20(token).transferFrom(msg.sender, address(this), amount), "BurnVault: transferFrom failed");
        totalBurnedToken[token] += amount;
        emit TokenBurned(token, msg.sender, amount, totalBurnedToken[token]);
    }

    /// Optional: forward accumulated native AERE to address(0).
    /// QBFT Besu permits sending to address(0); the AERE is then unreachable.
    /// Anyone can call this; it has no parameters and no admin gate. This is
    /// the final removal step. Until it is called, AERE sits on this contract,
    /// which is unreachable for any other reason but is still a live account.
    /// MEASURED at block 11,967,981 on 2026-08-02: `totalSentToZero` is 0, so
    /// this function has NEVER been called on chain 2800 and no AERE has been
    /// sent to address(0) by this vault.
    function sweepToZero() external {
        uint256 bal = address(this).balance;
        require(bal > 0, "BurnVault: nothing to sweep");
        totalSentToZero += bal;
        (bool ok, ) = address(0).call{ value: bal }("");
        require(ok, "BurnVault: zero-send failed");
        emit AereSentToZero(bal, totalSentToZero);
    }

    /// Convenience read.
    function currentAEREBalance() external view returns (uint256) {
        return address(this).balance;
    }
}
