// 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; } }