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

/**
 * @title AereFeeBurnVault
 * @notice Permanent, on-chain burn destination for protocol fees.
 *
 * Whitepaper §3.3 promises that "up to 37.5% of all transaction fees are
 * permanently obliterated." This contract is the burn endpoint that makes
 * that claim measurable and publicly auditable.
 *
 * 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 — funds that enter are permanently removed
 *     from circulation.
 *   - Counters: tracks `totalBurnedAERE` and per-token `totalBurnedToken[token]`
 *     so the chain's deflation can be queried in a single read.
 *   - Sources: protocol contracts that earn fees (AereSwapRouter, the NFT
 *     marketplace, future card-fee router, etc.) can route a configurable
 *     share to this address — but the vault doesn't 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 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 "obliteration" step — until called, AERE sits on this contract.
    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;
    }
}
