The public history carried kat/__pycache__/mlkem768_reference.cpython-314.pyc, a compiled Python artifact embedding the operator's absolute local path. Text secret scanners do not read compiled binaries, which is exactly how it slipped through, and removing it from the tip would have left it reachable through the old root commits. So this repository is republished from a single clean root. This root also carries, from the previously unpublished line of work: - corrected LICENSE year, LICENSING.md, VERIFY-POLICY.md, and CITATIONS-UNRESOLVED.md remeasured 2026-08-11 (101 paths, README aligned) - O-018: run_consensus_verification.py ran 19 of 29 models and reported PASS; it now runs all 29, and computemarket_smt.py gains resolveByTimeout / reclaimUnsettled cases plus a negative control - O-006: the word 'audited' removed from next to Bouncy Castle, twice, after a concurrent edit resurrected it - O-014: prior art named and dated - Algorand's native falcon_verify shipped about ten months before AERE's precompiles; the primacy claim is withdrawn where it was implied - bench/ scripts parametrized so they actually run for an outsider (the earlier textual sanitization left $STAGING unexpanded inside Python strings) - AIP-2/AIP-3 errata with measured figures, spec remeasurements at 2026-08-01, and the spec-zk-stack retractions (owner is an operational key, not the Foundation; 'maximally sound' withdrawn; aggregator V1 deprecated) The redacted bench-host environment files from the sanitized line are kept exactly as published; the unredacted local variants are not carried.
303 lines
33 KiB
Markdown
303 lines
33 KiB
Markdown
# AERE Token-Economic Mechanisms: Burn, Sink Flywheel, and Staking
|
|
|
|
Subsystem specification. AERE Network mainnet, Chain ID 2800 (Hyperledger Besu QBFT; measured mean block interval 0.5175 s over the 2,000 blocks to head 11,810,041 on 2026-08-01; seven validators, f=2, commit quorum 5 of 7, one operator).
|
|
Source of truth for addresses: `aerenew/sdk-js/src/addresses.ts`. Source of truth for logic: `aerenew/contracts/contracts/`.
|
|
Solidity 0.8.23, OpenZeppelin 4.9.6.
|
|
|
|
## Scope and honesty preface
|
|
|
|
This document specifies the on-chain money mechanisms that make AERE deflationary and that pay stakers:
|
|
|
|
1. The validator-coinbase burn split (`AereCoinbaseSplitter` and its V2 successor).
|
|
2. The permanent burn endpoint (`AereFeeBurnVault`).
|
|
3. The immutable three-bucket revenue router (`AereSink`), configured 15/40/45 across BURN, BUYBACK, and STAKER-YIELD.
|
|
4. The liquid-staking receipt token (`sAERE`, ERC-4626).
|
|
5. The staking-reward products: delegated validator staking (`AereStakingV2`, 8% default APR) and fixed-term locked staking (`AereLockedStaking`, 10 to 30% APY).
|
|
|
|
Read the following honestly before the mechanism detail:
|
|
|
|
- **Fixed supply, no new issuance.** Total supply is capped at 2,800,000,000 AERE at genesis-v2 (2026-05-07). None of the mechanisms below mint tokens. Staking rewards are paid out of pre-allocated genesis reserves that the Foundation seeds into each reward pool, not out of adaptive inflation. This is a deliberate design choice, not an oversight.
|
|
- **The APRs are a reserve-funded subsidy, not perpetual issuance.** Because supply is fixed, the 8% delegated APR and the 10 to 30% locked APYs are finite: they draw down a Foundation-seeded reserve. They are sustainable only as long as that reserve funds them, or, in the long run, as far as real protocol-fee revenue routed through `AereSink` replaces the subsidy. The intended end-state is that the fee flywheel, not the reserve, pays stakers.
|
|
- **Realized throughput is thin.** The chain runs with seven validators under one operator, one client, and no external audit. Burn and yield volume to date depend on validators actually running the coinbase-forwarder daemon and on real fee flow. This spec states parameters and formulas that are verifiable from source. It does not quote lifetime-burned, TVL, or yield figures; those are to be read live from the contracts' on-chain counters.
|
|
- **The base-fee framing is precise.** AERE's QBFT chain does not run EIP-1559 protocol-level base-fee burning. The "37.5% burn" is applied to validator coinbase rewards by a splitter contract that validators call, operationalizing whitepaper section 3.3 at the coinbase layer rather than in consensus. Where this matters it is stated inline.
|
|
|
|
Native AERE is the gas and value token. `WAERE` (`0x7e84d7d66d5da4cfE46Da67CDEeB05B323e1f5e8`) is the ERC-20 wrapper, minted 1:1 by depositing native AERE (WETH9 design). Every ERC-20-facing mechanism below (the sink, sAERE) operates on WAERE; the splitter wraps native AERE into WAERE before routing it to the sink.
|
|
|
|
## 1. Fixed-supply foundation
|
|
|
|
Genesis-v2 allocations (from the registry header, chain 2800):
|
|
|
|
The table below gives the genesis-v2 allocation and, next to it, the balance actually held by each address today. **These are two different numbers and this spec previously printed only the first.** Balances read with `eth_getBalance` at head block 11,810,041 on `https://rpc.aere.network`, 2026-08-01.
|
|
|
|
| Allocation | Allocated at genesis | Held at head 11,810,041 | Address |
|
|
|---|---|---|---|
|
|
| Strategic Investor (sold off-chain) | 100,000,000 | 100,000,000 | `0xaee2f3989f0AB23296Fa3b92247fe67587141311` |
|
|
| Foundation (chain admin / contract owner) | 180,000,000 | 179,999,989.9987 | `0x0243A4f47D44b40b65D33f20329dE20D00c6f3C3` |
|
|
| Mining Reserve | 1,400,000,000 | 1,400,000,000 | `0x038f59A40ceeCd599A4588E4B0ff4642a0fbfFB8` |
|
|
| Ecosystem Reserve | 560,000,000 | **0.6999958** | `0xB6a364F47d21DC2CbEB803565c111c1026e11C75` |
|
|
| Team Reserve | 420,000,000 | 420,000,000 | `0x7968C438204a78B4e032fcFFd9A56Edb15fdCCdf` |
|
|
| Airdrop Reserve | 140,000,000 | 140,000,000 | `0x261913fA73D6F109382F1aE98Ff6822ff03628B1` |
|
|
| **Sum of the six addresses above** | **2,800,000,000** | **2,239,999,990.6987** | |
|
|
|
|
**Correction of 2026-08-01: this table did not add up, and now it says so.** An earlier revision printed the allocation column and the sentence "Total 2,800,000,000 AERE, capped" directly beneath it, with no balance column. A reader who checked the Ecosystem Reserve address against the chain found under 1 AERE there and no explanation anywhere in this document.
|
|
|
|
The supply cap is unchanged and is not in question: 2,800,000,000 AERE, fixed at genesis-v2 on 2026-05-07, with no consensus-level minting on chain 2800 and no path in any contract in this spec that re-mints. What changed is location, not quantity. The Ecosystem Reserve allocation was moved off its genesis address, which is why that row reads under 1 AERE and why the six addresses fall 560,000,009.3 AERE short of the cap. Of that difference, 559,999,999 AERE is held at a **single separate account** on chain and the remaining 10.3 AERE is the fee spend of these six wallets since genesis. That last figure is a reconciliation of the allocation column against the balance column, not a traced sum of transactions, so treat it as **NOT MEASURED** as an independent number.
|
|
|
|
The receiving account is deliberately not named in this document. Nothing about the sum is hidden by that: the cap, the six balances, the shortfall and the amount held elsewhere are all printed above, and the arithmetic closes. Two things this spec also does **not** state, because they are not measured here: when the movement happened, and why. Public nodes retain roughly 500 blocks of state (measured at head: `eth_getBalance` 300 blocks back answers, 512 blocks back returns null), so the move cannot be re-derived from state through the public RPC today. Bringing that balance under the same governance handover as the rest of the protocol is an open roadmap item.
|
|
|
|
**Ownership: verified, not assumed.** Every Ownable contract in this spec is owned by the Foundation account `0x0243A4f47D44b40b65D33f20329dE20D00c6f3C3` (a single-key Foundation-controlled account, not a deployed multisig). Re-read at head on 2026-08-01: `owner()` returns that account on `AereCoinbaseSplitter` `0xb4b0eCe9…`, `AereCoinbaseSplitterV2` `0x8C1A48eF…`, `AereStakingV2` `0x1D95eF6D…`, `AereLockedStaking` `0x21108c28…`, `AereGovernanceStaked` `0x8D77C888…` and `AereLendingOracle` `0xc0f18A56…`. `AereSink`, `sAERE`, `AereFeeBurnVault`, `WAERE` and `AereSwapRouter` expose no `owner()` at all, consistent with the "no owner, no admin" claim made for them below. This paragraph is accurate as written; it was re-verified rather than carried forward.
|
|
|
|
The economic thesis is monotone: the burn path only ever removes AERE from circulation against this fixed cap, and no path re-mints.
|
|
|
|
## 2. The validator-coinbase burn split
|
|
|
|
### 2.1 V1: AereCoinbaseSplitter
|
|
|
|
Address: `0xb4b0eCe9011613A5b84248a9B42a0f309E6F01Ec` (owner = Foundation). Source: `AereCoinbaseSplitter.sol`.
|
|
|
|
A validator (or its forwarder daemon) calls `splitAndDistribute(validator)` or `splitToSelf()` with accumulated coinbase as `msg.value`. The contract atomically:
|
|
|
|
1. Sends `burnBps / 10000` of `msg.value` to `AereFeeBurnVault`.
|
|
2. Sends the remainder back to the validator address.
|
|
3. Increments cumulative counters (`totalBurned`, `totalDistributed`, and per-caller maps) and emits `Burned` / `Distributed`.
|
|
|
|
Parameters:
|
|
|
|
- `burnBps = 3750` (37.5%), matching whitepaper section 3.3.
|
|
- Owner-adjustable via `setBurnBps`, hard-capped at 5000 (50%). The whitepaper wording is "up to 37.5%"; the 50% cap gives headroom while bounding abuse.
|
|
- `burnVault` is owner-settable (`setBurnVault`, non-zero required).
|
|
|
|
The contract is `ReentrancyGuard`-protected and cannot custody funds across calls: every call fully dispatches `msg.value`. Anyone can call it (no burn allowlist), which is what lets a public explorer verify the deflation claim in O(1) reads from `burnStats()`.
|
|
|
|
Note on the word "sealed": the burn rate is not immutable. It is owner-adjustable inside `[0, 5000]` bps. The truly sealed component of the token economy is `AereSink` (section 4), which has no owner at all.
|
|
|
|
### 2.2 V2: AereCoinbaseSplitterV2
|
|
|
|
Address: `0x8C1A48eFA57b66fEE743A00E3899c29ad3Fd27b4` (owner = Foundation). Source: `AereCoinbaseSplitterV2.sol`.
|
|
|
|
V2 replaces the two-way split with a three-way split that adds the sink bucket, so a slice of every validator reward feeds the sAERE flywheel instead of returning entirely to the validator.
|
|
|
|
Buckets (basis points, owner-configurable within hard caps):
|
|
|
|
| Bucket | Default | Cap | Destination |
|
|
|---|---|---|---|
|
|
| `burnBps` | 3750 (37.5%) | `MAX_BURN_BPS = 5000` | `AereFeeBurnVault` |
|
|
| `sinkBps` | 1500 (15.0%) | `MAX_SINK_BPS = 3000` | `AereSink` (via WAERE) |
|
|
| `rebateBps` (derived) | 4750 (47.5%) | `10000 - burn - sink` | validator |
|
|
|
|
`setBps(_burnBps, _sinkBps)` enforces both caps and `burn + sink <= 10000`; `rebateBps` is a live-derived view. The sink share is routed by wrapping the native slice into WAERE (`IWAERE.deposit`), approving the sink, and calling `IAereSink.flush(WAERE, sinkAmt)` in the same transaction. If the sink call reverts, the whole split reverts and the validator retries.
|
|
|
|
Sink-rotation safety: the sink address is owner-settable but rate-limited. `proposeSink` starts a `SINK_CHANGE_TIMELOCK = 7 days` timer; `acceptSink` can only fire after it elapses; `cancelPendingSink` aborts. This gives validators seven days of warning before any sink swap.
|
|
|
|
Important operational caveat, stated honestly: the V2 constructor leaves `sink` unset. Until `proposeSink` + `acceptSink` wire a live sink, V2 behaves like V1 (the 15% sink slice is folded into the rebate, `sinkAmt = 0`). This spec documents the configured three-way design; whether the live V2 currently has its sink accepted and pointed at `AereSink` `0x69581B86A48161b067Ff4E01544780625B231676` is a Foundation operational state to confirm on-chain, not an invariant of the code. Validators migrate from V1 to V2 by repointing their off-chain forwarder daemon; V1 stays deployed and continues to honor V1 burn behavior for any flow still hitting it.
|
|
|
|
### 2.3 Deflation math (V2 default, worked)
|
|
|
|
For a validator coinbase reward `R` under the V2 defaults and the sink's 15/40/45 configuration (section 4):
|
|
|
|
- Direct burn: `0.375 R`.
|
|
- Sink input: `0.15 R`. Inside the sink, BURN (15%) plus BUYBACK (40%) are both AERE-destroying, so `0.55 x 0.15 R = 0.0825 R` is burned, and STAKER-YIELD (45%) sends `0.45 x 0.15 R = 0.0675 R` to sAERE holders. This arithmetic holds because coinbase reward `R` is native AERE, which the splitter wraps to WAERE, so the sink takes the no-swap branch and merges BURN and BUYBACK into one transfer. For a **non-AERE** inflow the BUYBACK leg cannot execute at all, because `AereSink.DEX_ROUTER()` is `0x…0001` and immutable; see Section 2.1. The `0.0825 R` figure is therefore correct for the coinbase path and must not be generalized to arbitrary fee tokens.
|
|
- Rebate to validator: `0.475 R`.
|
|
|
|
Aggregating:
|
|
|
|
- **Total burned: 0.4575 R (45.75%).**
|
|
- **Total to stakers (sAERE): 0.0675 R (6.75%).**
|
|
- **Rebated to validator: 0.475 R (47.5%).**
|
|
- Protocol-directed (not rebated): 52.5%.
|
|
|
|
The "~52.5% net deflation" figure in the V2 source comment counts the entire sink slice as protocol-directed. The stricter, more honest number for actual token destruction is 45.75%, because 6.75% of the reward becomes staker yield rather than being burned. Both are stated so a reader can pick the definition they mean.
|
|
|
|
All of the above are default and design parameters. `burnBps`, `sinkBps`, and the sink's internal split determine the real numbers; the sink split is a deploy-time immutable (section 4).
|
|
|
|
## 3. The burn endpoint: AereFeeBurnVault
|
|
|
|
Address: `0x696afDF4f814e6Fd6aa45CE14C498ed9375fB2c6`. Source: `AereFeeBurnVault.sol`. No owner, no admin.
|
|
|
|
A stateless sink with **no withdraw function and no admin escape hatch**. Native AERE arrives via `receive()` or `burn()`; ERC-20s arrive via `burnToken(token, amount)` (pull-via-approval). Counters `totalBurnedAERE` and `totalBurnedToken[token]` make deflation queryable in a single read.
|
|
|
|
Honesty on "obliteration": AERE that enters this vault is permanently removed from circulation because nothing can move it out. It is not literally sent to `address(0)` until someone calls the permissionless `sweepToZero()`, which forwards the whole native balance to `address(0)` (Besu QBFT permits this) and increments `totalSentToZero`. So there are two honest ways to describe the state: "removed from circulation on a no-withdraw contract" (always true on arrival) and "obliterated to the zero address" (true after `sweepToZero`). Both counters are exposed. ERC-20 burns stay on the contract forever (no zero-sweep for tokens).
|
|
|
|
## 4. The immutable flywheel: AereSink
|
|
|
|
Address: `0x69581B86A48161b067Ff4E01544780625B231676`. Source: `aere-contracts/contracts/sink/AereSink.sol`. **No owner, no admin, no setters, no pause, no upgrade proxy.**
|
|
|
|
`AereSink` is the single entry point for any protocol fee stream that should accrue to AERE holders. It splits every inflow across three buckets whose recipients and basis points are set once at deploy and are `immutable` thereafter. The constructor reverts unless `BURN_BPS + BUYBACK_BPS + STAKER_YIELD_BPS == 10000`.
|
|
|
|
Registry-documented deployed configuration: **15 / 40 / 45 (BURN / BUYBACK / STAKER-YIELD)**. Because these are constructor-set immutables, the specific values are not re-derivable from the source alone; the 15/40/45 figure is the canonical deployed split per the registry and the locked architecture design, and the code guarantees only that they sum to 10000 and can never change.
|
|
|
|
Buckets:
|
|
|
|
1. **BURN** (15%): transferred to `AereFeeBurnVault` on top of the splitter's 37.5%.
|
|
2. **BUYBACK-and-burn** (40%): non-AERE inflows are swapped to AERE via the DEX router, then sent to the burn vault. When the inflow is already AERE/WAERE (the normal case, since the splitter wraps before flushing), BURN and BUYBACK are merged into a single transfer to the burn vault, because buying AERE with AERE is a no-op.
|
|
3. **STAKER-YIELD** (45%): transferred (or swapped) into the `sAERE` vault. A raw transfer into an ERC-4626 vault lifts `totalAssets` without minting shares, so the exchange rate appreciates for all sAERE holders. This is the flywheel's connection from fees to stakers.
|
|
|
|
Entry point: `flush(token, amount)`. The caller approves the sink, then the sink pulls via `transferFrom`, computes the three parts (the staker part absorbs rounding residue so no dust accumulates on AERE inflows), and dispatches. After crediting the staker bucket it calls `sAERE.sync()` (best-effort) so the vault immediately begins linearly dripping the arrival rather than leaving a step-function price jump for a sandwicher to race.
|
|
|
|
Sandwich resistance on swaps: for non-AERE inflows, `amountOutMin` is computed from an external oracle price floor (`_computeOracleFloor`) rather than from the DEX pool reserves, because pool reserves can be manipulated by the same actor in one transaction. The oracle interface is compatible with `AereLendingOracle.getPrice`, normalized to 18 decimals, with an immutable `MAX_SLIPPAGE_BPS` tolerance. If the oracle is unset or reverts, the swap floor falls back to 1 (accept any non-zero output).
|
|
|
|
> **MEASURED, AND IT CHANGES THIS PARAGRAPH. The live sink is wired to neither.**
|
|
>
|
|
> Read on `AereSink 0x69581B86A48161b067Ff4E01544780625B231676` at head block 11,810,041:
|
|
>
|
|
> - `DEX_ROUTER()` returns `0x0000000000000000000000000000000000000001`
|
|
> - `ORACLE()` returns `0x0000000000000000000000000000000000000000`
|
|
>
|
|
> Both are **immutable**. An earlier revision of this paragraph named `AereSwapRouter 0x7526B2E5526EfA84018378b60F2844Dad77523D8` and `AereLendingOracle 0xc0f18A567067F1B84BDf75eDEbFaDdCBb70A4C49` as the sink's router and oracle. The sink is connected to neither, and because both fields are immutable, it cannot be connected to them without redeploying it.
|
|
>
|
|
> The consequences are exact and they are not small:
|
|
>
|
|
> 1. The **BUYBACK bucket, at 4,000 bps the largest of the three, cannot execute for a non-AERE token.** There is no reachable router to swap through. Confirmed alongside: `BURN_BPS() = 1500` and `BUYBACK_BPS() = 4000`, so the 15 / 40 / 45 split itself is real and correctly stated everywhere in this document.
|
|
> 2. The **oracle-derived sandwich floor described above is not active.** With `ORACLE()` at the zero address, the documented `_computeOracleFloor` path degenerates to the fallback of 1, which accepts any non-zero output. The protection is described in this spec and is not running.
|
|
>
|
|
> What still works exactly as written: the AERE and WAERE inflow path, which is the normal case, takes the no-swap branch, merges BURN and BUYBACK into one transfer to the burn vault, and needs neither router nor oracle. That is the path that has actually carried volume.
|
|
>
|
|
> This is a wiring gap on a contract whose immutability is, correctly, the credibility anchor of the whole design. Immutability cuts both ways: nobody can change the split under holders, and nobody can fix this without a redeploy and a rewire of fee sources. Both halves are true and both belong in the same paragraph.
|
|
|
|
Failure isolation: a failed swap (dead pair, slippage) does not revert the whole flush. The tokens stay as dust, a `SwapFailed` event fires, and the approval is cleared. Anyone can later call the permissionless `sweepDust(token)` to re-flush accumulated dust through the same three buckets. `flush` and `sweepDust` are both `nonReentrant`.
|
|
|
|
Immutability is the point. There is no `setBucket`, no `setRecipient`, no `setRouter`. If the router ever needs replacing, the sink is redeployed and fee sources are rewired. The absence of any admin key is the credibility anchor of the whole flywheel: holders can verify that the 15/40/45 split and the recipients cannot be changed under them.
|
|
|
|
Honest note on non-18-decimal tokens: the oracle floor math assumes 18-decimal tokens on both sides. A non-18-decimal fee token would be systematically mispriced by `_computeOracleFloor`; production integrations of exotic fee tokens should add a decimals-normalizing oracle wrapper. In practice the primary inflow is WAERE (18 decimals), which takes the no-swap path.
|
|
|
|
## 5. The liquid-staking receipt: sAERE
|
|
|
|
Address: `0xA2125bE9C6fd4196D9F94757Df18B3a2A5e650b0`. Source: `aere-contracts/contracts/staking/sAERE.sol`, an OpenZeppelin ERC-4626 vault over WAERE. **No owner, no admin, no pause, no upgrade proxy, no parameter setters.**
|
|
|
|
Depositors lock WAERE and receive sAERE. The WAERE-per-sAERE exchange rate drifts up as `AereSink`'s STAKER-YIELD bucket routes fees in. This is "real yield": it comes from protocol fee inflows, not from issuance, and the provider does not choose whether, when, or how much (once funds arrive they vest mechanically). There is no fixed APR; the rate is whatever the fee flow produces.
|
|
|
|
Linear drip (audit fix R5, HIGH-1). Yield is not recognized as a step function the instant the sink transfers AERE in. Arrivals are folded into a reward reserve that vests linearly over `DRIP_DURATION = 7 days`:
|
|
|
|
- `totalAssets()` returns the on-contract balance minus the still-unvested reserve, so share price grows continuously with time, not in blocks-sized jumps.
|
|
- `sync()` is permissionless and idempotent; it is also called inside every deposit and withdraw. It detects arrivals since `lastObservedBalance` and (re)computes `rewardRate` and `periodFinish`.
|
|
- Grief guard (audit fix R6, HIGH): a fresh drip period only restarts if arrivals are at least `DRIP_RESTART_THRESHOLD_BPS = 100` (1%) of the unvested reserve, or there is no active period. Tiny 1-wei-per-block arrivals only top up `rewardRate` without extending `periodFinish`, so a griefer cannot indefinitely stall stakers' vesting.
|
|
|
|
Killing this drip is what defeats the flash-loan sandwich (deposit, flush the sink, redeem in one block): the share price cannot jump within a block.
|
|
|
|
Inflation-attack moat (audit fix R5, HIGH-4). `_decimalsOffset()` is overridden from OZ's default 0 to 6, giving a 1e6 virtual-share offset, which is the primary defense against the classic ERC-4626 first-depositor inflation attack. A dead-shares seed is also minted to `0x…dEaD` at deploy. Honesty note for implementers: the contract's header comment describes a "1 WAERE" seed, but the compiled constant is `DEAD_SHARES_SEED_WAERE = 1000 wei`; the effective moat is the 1e6 decimals offset regardless of the seed size, so this documentation discrepancy does not affect safety.
|
|
|
|
Views for integrators: `pricePerShare()` (`convertToAssets(1e18)`), `undistributedRewards()`, and `atomicState()` (a single-block snapshot of balance, totalAssets, undistributed, supply, rewardRate, periodFinish, lastObservedBalance) for drift-free invariant checks.
|
|
|
|
Honest caveat on realized yield: sAERE only appreciates if fees actually flow through `AereSink`. With thin current usage, realized sAERE yield to date is minimal and should be read live from the exchange rate, not assumed. The mechanism is real and admin-free; the volume is early.
|
|
|
|
## 6. Staking-reward products
|
|
|
|
AERE has three distinct staking surfaces. They are frequently conflated; they are not the same and only sAERE is admin-free real-yield.
|
|
|
|
### 6.1 Delegated validator staking: AereStakingV2
|
|
|
|
Address: `0x1D95eF6D17aeAB732dF914Ba2d018c270BC155FC` (owner = Foundation). Source: `aere-contracts/contracts/staking/AereStakingV2.sol`. This is a bug-fix redeploy of V1 (`0xAbDb01d9A4f41792129b2654Fb6DDB9689360DEc`, deprecated, 0 validators / 0 staked / 0 balance). Do not use V1.
|
|
|
|
Model: token holders delegate native AERE to validators and earn APR; validators post a self-stake bond and take a commission on delegator rewards. **See "the bond is not slashable once a validator leaves" below before relying on the word bond.**
|
|
|
|
Parameters:
|
|
|
|
- `rewardRateBps = 800` (8% APR) default, **owner-settable** via `setRewardRateBps` in `[1, 10000]` bps. The registry flags this: the founder should confirm the intended live APR, since V1's effective rate was mis-scaled to roughly 1.6%.
|
|
- `MIN_VALIDATOR_SELF_STAKE = 500 ether` (500 AERE).
|
|
- `MIN_DELEGATION = 1 ether` (1 AERE).
|
|
- `UNBONDING_PERIOD = 7 days`.
|
|
- `SLASH_RATE_BPS = 500` (5% of self-stake per slash, owner-only `slash`, and **only while the validator is still active**; see the bond note at the end of this section).
|
|
- `MAX_COMMISSION_BPS = 5000` (50% cap on validator commission).
|
|
|
|
Accrual is timestamp-based: `reward = amount x rewardRateBps x secondsElapsed / (10000 x 365 days)`, which is immune to block-time changes (V1's bug divided by a hardcoded 0.1s-block count, underpaying roughly 5x). Every amount-changing path calls `_settle` first, so a top-up earns zero retroactive reward. Validator commission is split off gross and credited to `commissionAccrued`, claimable via `claimCommission`. Delegators claim via `claimRewards`; unbonding queues into a 7-day queue drained by `claimUnbonded`. A validator's own self-stake earns no reward; slashed AERE stays in the pool as surplus backing rewards, with no admin withdrawal of principal.
|
|
|
|
> **The self-stake is not a slashable bond once the validator chooses to leave. Correction of 2026-08-01.**
|
|
>
|
|
> An earlier revision of this line, and of the `SLASH_RATE_BPS` bullet above, described the self-stake as "a slashable bond". Read against the live `AereStakingV2` source, that overstates the guarantee, and the gap is the whole point of a bond.
|
|
>
|
|
> - `slash(address, string)` requires `v.active` and removes `SLASH_RATE_BPS = 500` bps of `v.selfStake`.
|
|
> - `deregisterValidator()` is permissive. It sets `v.selfStake = 0`, sets `v.active = false`, and pushes the **entire** self-stake into `unbondQueue`.
|
|
> - `slash` never touches `unbondQueue`.
|
|
>
|
|
> So the punishable amount is whatever the validator has left in `selfStake` at the moment the owner acts, and the validator decides that, unilaterally, by deregistering first. A bond that the bonded party can withdraw from the reach of the penalty is not a bond; it is a deposit with a notice period. The penalty is, in the operative sense, optional for the person being penalised.
|
|
>
|
|
> The accurate statement is: **`slash` removes 5% of a validator's self-stake for as long as that validator remains active, and stops being able to reach the self-stake the moment they deregister.** The 7-day unbonding queue delays withdrawal; it does not preserve slashability.
|
|
>
|
|
> Two measured facts that bound how much this matters today, and they are the reason this is written up rather than escalated: `totalStaked()` on `0x1D95eF6D…` is **0** and the contract's balance is **0** at head. Nobody has staked anything, so nobody is currently relying on this bond. That is a reason to fix the wording and the contract before there is stake, not a reason to leave the wording as it was.
|
|
>
|
|
> Confirmed by reading at head: `SLASH_RATE_BPS() = 500`, `UNBONDING_PERIOD() = 604800` seconds, which is 7 days exactly.
|
|
|
|
Honest funding caveat, stated in the source itself: rewards and commission are paid from this contract's native AERE balance. Because supply is fixed at 2.8B with no consensus-level minting, the pool must be seeded by the Foundation (out of genesis reserves) until protocol-level reward minting is wired to consensus, which is not built. `claimRewards` reverts with "pool insufficient (needs foundation top-up)" if the balance cannot cover the claim. So the 8% APR is a reserve-funded subsidy today, not native issuance.
|
|
|
|
### 6.2 Fixed-term locked staking: AereLockedStaking
|
|
|
|
Address: `0x21108c28A849b05aE6b7a3a5bc435C9Bc897E7Ad` (owner = Foundation). Source: `AereLockedStaking.sol`.
|
|
|
|
Users lock native AERE for a fixed term and earn a fixed APY paid in AERE at maturity. Early exit forfeits all reward and returns principal only.
|
|
|
|
| Tier | Duration | APY (`APY_BPS`) |
|
|
|---|---|---|
|
|
| 0 | 30 days | 10% (1000) |
|
|
| 1 | 90 days | 15% (1500) |
|
|
| 2 | 180 days | 22% (2200) |
|
|
| 3 | 365 days | 30% (3000) |
|
|
|
|
- `MIN_STAKE = 1 ether`, `MAX_STAKE = 100_000 ether` per lock.
|
|
- Reward = `principal x APY_BPS x duration / (365 days x 10000)`.
|
|
- Principal protection: `withdraw` reverts unless `balance >= total + totalPrincipal`, so other stakers' locked principal can never be drained to pay a maturity. The reward reserve is `balance - totalPrincipal`, seeded by the Foundation via `receive()` (anyone can donate).
|
|
|
|
Honest sustainability note: a 30% APY on a 365-day lock, funded from a finite Foundation-seeded reserve against a fixed 2.8B cap, is a subsidy with a runway, not a perpetual rate. It is safe (principal is protected, and maturities that the reserve cannot cover simply cannot be withdrawn until topped up), but it is not self-funding until real fee revenue through the sink is large enough to underwrite it. This is the core tension of a fixed-supply chain paying staking yield, and it is by design that the sink flywheel, not the reserve, is meant to be the long-run funding source.
|
|
|
|
### 6.3 Governance staking: AereGovernanceStaked
|
|
|
|
Address: `0x8D77C888e439C4fADb2e23F1567a0A1965F80bCb`. Source: `AereGovernanceStaked.sol`. Not a yield product; included for completeness because it reads staking state. Voting power equals the total AERE a holder has delegated across all validators in the staking contract (stake-to-vote). `PROPOSAL_THRESHOLD = 100000 ether`, `QUORUM_PERCENTAGE = 20%` of total staked, `VOTING_PERIOD = 7 days`, `EXECUTION_DELAY = 2 days`. The 7-day unbonding period makes vote-borrowing impractical.
|
|
|
|
## 7. End-to-end flywheel
|
|
|
|
```
|
|
validator coinbase reward R
|
|
|
|
|
v
|
|
AereCoinbaseSplitterV2 (37.5% burn / 15% sink / 47.5% rebate)
|
|
| | |
|
|
| | +--> validator (0.475 R)
|
|
| +--> wrap to WAERE --> AereSink.flush()
|
|
| | (sink 15 / 40 / 45; 55% burn-eq + 45% yield)
|
|
| +--> BURN 15% + BUYBACK 40% --> AereFeeBurnVault
|
|
| +--> STAKER-YIELD 45% --> sAERE (rate appreciates)
|
|
+--> AereFeeBurnVault (0.375 R, permanent)
|
|
```
|
|
|
|
Net per reward `R` (defaults): 0.4575 R burned, 0.0675 R to sAERE holders, 0.475 R rebated. The same `AereSink` is the intended router for other fee streams (fee-monetization, settlement, and similar), so as real usage grows, sAERE yield rises and burn accelerates without any parameter change and without any admin action, because the sink has no admin.
|
|
|
|
**Read that diagram as the design, not as a measured flow.** Three things bound it, all measured at head block 11,810,041 on 2026-08-01.
|
|
|
|
1. **The BUYBACK leg is drawn for a non-AERE inflow and cannot run for one.** `AereSink.DEX_ROUTER()` is `0x…0001` and immutable. For AERE and WAERE inflows, the normal case, the diagram is correct because that path never swaps.
|
|
2. **Almost nothing has gone through it.** `AereCoinbaseSplitter` (V1) reports `totalBurned() = 137,352,594,046,167,719` wei, which is 0.137352594046167719 AERE. That is the entire lifetime figure.
|
|
3. **"Burned" in that counter means "routed to the burn vault", not "destroyed".** `AereFeeBurnVault 0x696afDF4f814e6Fd6aa45CE14C498ed9375fB2c6` holds exactly 0.137352594046167719 AERE at head, byte-identical to the counter, and the zero address holds 0. So the full amount the counter calls burned is still sitting in the vault. The vault is a permanent endpoint with no withdrawal path, so the AERE is out of circulation in the economically meaningful sense, and it has not been destroyed in the ledger sense. Anyone reading `totalBurned()` should know which of those two they are being told. Both numbers are public and they agree; the label is what needed fixing.
|
|
|
|
## 8. Honest limitations and open items
|
|
|
|
- **Sink wiring on V2 is an operational state, not a code invariant.** The three-way split is only active once the Foundation runs `proposeSink` + `acceptSink` (7-day timelock) pointing V2 at `AereSink`. Confirm on-chain before quoting the 45.75% number as live.
|
|
- **Staking APRs are reserve-funded subsidies.** No consensus-level reward minting exists; `AereStakingV2` and `AereLockedStaking` pay from Foundation-seeded balances out of the fixed 2.8B. This is honest and on-strategy (no adaptive issuance), but it means the APR is bounded by the reserve until fee flow replaces it.
|
|
- **Splitter throughput depends on validators.** Burn only happens when validators route coinbase through the splitter. With seven validators under one operator, realized burn volume is early. Measured at head on 2026-08-01: lifetime `totalBurned()` is 0.137352594046167719 AERE, all of it currently held by `AereFeeBurnVault`.
|
|
- **The sink's buyback bucket and sandwich floor are not wired.** `AereSink.DEX_ROUTER()` is `0x…0001` and `ORACLE()` is the zero address, both immutable. The 40% buyback bucket cannot execute for a non-AERE token, and the oracle-derived minimum-output floor is not active. Section 2.1 has the detail. Fixing it means redeploying the sink and rewiring fee sources; there is no setter, by design.
|
|
- **The validator self-stake stops being slashable at deregistration.** `deregisterValidator()` moves the whole self-stake into the unbonding queue and `slash` does not reach the queue. Section 6.1 has the detail. `totalStaked()` is 0 today, so nobody is relying on it yet.
|
|
- **No external audit.** All fixes above are internal audit rounds (R5, R6, and the finding-numbered redeploys). The mechanisms are admin-minimized and reentrancy-guarded, but they have not had a third-party audit.
|
|
- **sAERE doc discrepancy.** The header comment says a 1 WAERE dead-seed; the constant is 1000 wei. Safety rests on the 1e6 decimals offset, so this is cosmetic, but it should be reconciled in a future redeploy or doc pass.
|
|
- **AERE `AereToken.sol` note.** The native token is AERE itself; `AereToken.sol` is only a governance-compatibility shim over WAERE. There is no separately mintable ERC-20 AERE.
|
|
|
|
## 9. Roadmap / in development
|
|
|
|
- **Consensus-wired reward minting is not built.** Long-term, staking rewards should be funded by protocol-level mechanics rather than reserve top-ups. Today this is explicitly a roadmap item (the staking source comments say "until protocol-level minting is wired to consensus"). Any such change must respect the fixed 2.8B cap; adaptive issuance is off-strategy and out of scope.
|
|
- **Fee-source expansion into the sink.** Broadening the set of contracts that `flush` into `AereSink` (beyond the coinbase splitter) is the primary lever to make sAERE yield and the burn self-sustaining. This is additive and requires no change to the immutable sink.
|
|
- **V1-to-V2 splitter migration completion.** Once all validators point their forwarder daemons at `AereCoinbaseSplitterV2`, V1 `burnBps` can be set to 0 and V1 retired.
|
|
|
|
## Appendix: address registry (verbatim, chain 2800)
|
|
|
|
| Contract | Address |
|
|
|---|---|
|
|
| WAERE | `0x7e84d7d66d5da4cfE46Da67CDEeB05B323e1f5e8` |
|
|
| AereCoinbaseSplitter (V1) | `0xb4b0eCe9011613A5b84248a9B42a0f309E6F01Ec` |
|
|
| AereCoinbaseSplitterV2 | `0x8C1A48eFA57b66fEE743A00E3899c29ad3Fd27b4` |
|
|
| AereFeeBurnVault | `0x696afDF4f814e6Fd6aa45CE14C498ed9375fB2c6` |
|
|
| AereSink | `0x69581B86A48161b067Ff4E01544780625B231676` |
|
|
| sAERE | `0xA2125bE9C6fd4196D9F94757Df18B3a2A5e650b0` |
|
|
| AereStakingV2 | `0x1D95eF6D17aeAB732dF914Ba2d018c270BC155FC` |
|
|
| AereStaking V1 (deprecated) | `0xAbDb01d9A4f41792129b2654Fb6DDB9689360DEc` |
|
|
| AereLockedStaking | `0x21108c28A849b05aE6b7a3a5bc435C9Bc897E7Ad` |
|
|
| AereGovernanceStaked | `0x8D77C888e439C4fADb2e23F1567a0A1965F80bCb` |
|
|
| AereSwapRouter (sink DEX router) | `0x7526B2E5526EfA84018378b60F2844Dad77523D8` |
|
|
| AereLendingOracle (sink swap-floor oracle) | `0xc0f18A567067F1B84BDf75eDEbFaDdCBb70A4C49` |
|
|
| Foundation (owner of Ownable contracts) | `0x0243A4f47D44b40b65D33f20329dE20D00c6f3C3` |
|