Skip to content

Mathematical Reference

Anvil256 — Mathematical Reference

κϵD[n]N\sum \cdot \prod \cdot \int \cdot \partial \cdot \nabla \cdot \kappa \cdot \epsilon \cdot D[n] \cdot \mathbb{N} \cdot \square
The canonical derivation for every non-trivial construction in the Anvil256 protocol. All claims are proven or bounded explicitly. Informal descriptions are never substituted for formal statements.


Notation

The protocol uses standard mathematical notation throughout. A short legend:

SymbolMeaning
WAD101810^{18} (Q60.18 unit scale)
\|concatenation via abi.encode (ABI-padded, prevents type-collision attacks)
H(x)H(x)keccak256(x) — 256-bit output, modelled as a random oracle
κ\kappaCascade challenge H(H(innerν)ϵ[n])H( H(\text{inner} \,\|\, \nu) \,\|\, \epsilon[n])
ϵ[n]\epsilon[n]Epoch entropy H(bn1D[n])H(b_{n-1} \,\|\, D[n])
D[n]D[n]difficulty at epoch nn
R(n)R(n)block reward at epoch nnR02n/HR_0 \cdot 2^{-\lfloor n/H \rfloor}
MLP(n)M_{LP}(n)protocol-owned liquidity reserve mint, 0.1R(n)0.1R(n) before cap truncation
SseedS_{seed}genesis LP seed mint, 11 ANVL
γ(m)\gamma(m)per-miner epoch counter (monotonic, non-transferable)
CuC_uunique miners in the 256-epoch NCT window
\lfloor \cdot \rfloorfloor function
sat(x,a,b)\mathbf{sat}(x,\,a,\,b)max(a,min(b,x))\max(a,\,\min(b,\,x)) — clamp to [a,b][a,b]
Zwad\mathbb{Z}_{\text{wad}}integer representing a real scaled by WAD\text{WAD}
N1\mathbb{N}_{\geq 1}positive integers
H\mathcal{H}the random oracle modelling HH
Pr[]\Pr[\cdot]probability over uniformly random oracle responses
\squareend of proof

1. Keccak-Cascade PoW with Temporal Miner Binding

1.1 Motivation: Formal Statement of the Wallet-Rotation Attack

Definition 1.1 (Naive PoW Challenge). Let M\mathcal{M} be the set of miner addresses and nNn \in \mathbb{N} be the current epoch. The naive challenge for miner mMm \in \mathcal{M} at epoch nn is:

challengenaive(m,n,ν)  =  H(mnν)\text{challenge}_{\text{naive}}(m, n, \nu) \;=\; H(m \,\|\, n \,\|\, \nu)

where ν{0,,2321}\nu \in \{0, \ldots, 2^{32}-1\} is the nonce. A nonce ν\nu^* is valid iff challengenaive(m,n,ν)<D[n]\text{challenge}_{\text{naive}}(m, n, \nu^*) < D[n].

Observation 1.2 (Zero-Cost Address Rotation). Let mMm \in \mathcal{M} be a miner address. Generating a fresh address mMm' \notin \mathcal{M} costs O(1)O(1) key-derivation operations. The challenge function satisfies:

challengenaive(m,n,ν)   and   challengenaive(m,n,ν)\text{challenge}_{\text{naive}}(m, n, \nu) \;\text{ and }\; \text{challenge}_{\text{naive}}(m', n, \nu)

are independent, identically distributed when mmm \neq m' and ν\nu is uniform. Therefore, the adversary can replace mm with mm' at zero marginal cost and receive a statistically equivalent challenge — no difficulty advantage, but also no penalty. The NCT concentration signal (§2) is then trivially gamed: kk physical machines can appear as W=256W = 256 distinct participants with zero additional hashrate cost.

Definition 1.3 (Sybil Cost). The Sybil cost σ(k)\sigma(k) of operating kk distinct miner identities for one 256-epoch window cycle is the minimum total protocol fee expenditure required to occupy kk distinct slots in the NCT window. For naive PoW, σ(k)=0\sigma(k) = 0 for all kWk \leq W.

1.2 Miner Epoch Counter — Formal Definition

Definition 1.4 (Miner Epoch Counter). The contract maintains a total function γ:MN\gamma : \mathcal{M} \to \mathbb{N} defined by:

γ(m)  :=  {jn  :  minej.sender=m}\gamma(m) \;:=\; \bigl|\{j \leq n \;:\; \text{mine}_j.\text{sender} = m\}\bigr|

i.e., the number of successful mine() calls by address mm up to and including epoch n1n-1, read before the increment in the current call.

Solidity representation:

mapping(address => uint64) public minerEpochCount;
// γ(m) = minerEpochCount[m] (pre-increment value at mine() call time)

Lemma 1.5 (γ-Monotonicity). For all mMm \in \mathcal{M} and epochs n1<n2n_1 < n_2: γn1(m)γn2(m)\gamma_{n_1}(m) \leq \gamma_{n_2}(m), with strict inequality iff mm successfully called mine() in the interval (n1,n2](n_1, n_2].

Proof. The counter is incremented by exactly 1 on each successful mine() call (via unchecked { ++minerEpochCount[msg.sender]; }), and is never decremented. The mapping is not transferable. \square

Lemma 1.6 (γ-Non-Transferability). For mmm \neq m': no sequence of contract calls can produce γ(m)γ(m)j\gamma(m) \gets \gamma(m') - j for any jZj \in \mathbb{Z} via internal state transfer. The counter is address-keyed and has no setter, no reset, and no cross-address interaction. \square

1.3 Full Cascade Construction — Formal Definition

Definition 1.7 (Cascade PoW). For epoch nn, nonce ν\nu, and caller m=msg.senderm = \texttt{msg.sender}:

ϵ[n]  =  H ⁣(blockhash(lastMineBlock[n1])    D[n])τ(m,n)  =  H ⁣(m    γ(m)    genesisBlockhash)ι(m,n)  =  H ⁣(τ(m,n)    n)κ(m,ν,n)  =  H ⁣(H ⁣(ι(m,n)    νbe32)    ϵ[n])\boxed{ \begin{aligned} \epsilon[n] \;&=\; H\!\bigl(\texttt{blockhash}(\texttt{lastMineBlock}[n{-}1]) \;\|\; D[n]\bigr) \\[4pt] \tau(m,n) \;&=\; H\!\bigl(m \;\|\; \gamma(m) \;\|\; \texttt{genesisBlockhash}\bigr) \\[4pt] \iota(m,n) \;&=\; H\!\bigl(\tau(m,n) \;\|\; n\bigr) \\[4pt] \kappa(m,\nu,n) \;&=\; H\!\Bigl(H\!\bigl(\iota(m,n) \;\|\; \nu_{\text{be32}}\bigr) \;\|\; \epsilon[n]\Bigr) \end{aligned} }

where D[n]D[n] denotes the difficulty governing epoch nn — i.e. the value of currentDifficulty after the PIController adjustment that fires at the epoch-nn period boundary (if any). The on-chain implementation enforces this by running _maybeAdjustDifficulty() before writing epochEntropy, so ϵ[n]\epsilon[n] always commits to the difficulty that will be used to validate nonces in epoch nn.

The nonce ν\nu^* is valid iff:

κ(m,ν,n)  <  D[n]\kappa(m,\,\nu^*,\,n) \;<\; D[n]

Definition 1.8 (Binding Layers). Each layer binds a distinct security property:

LayerExpressionBound Secret
τ\tauH(mγ(m)g)H(m \,\|\, \gamma(m) \,\|\, g)Temporal identity: address + history + genesis
ι\iotaH(τn)H(\tau \,\|\, n)Epoch uniqueness: separates epochs for same miner
κ\kappaH(H(ιν)ϵ[n])H(H(\iota \,\|\, \nu) \,\|\, \epsilon[n])Anti-precompute: live chain state in outer pass

1.4 Wallet-Rotation Cost — Formal Theorem

Theorem 1.9 (Rotation Cost Lower Bound). Under the random oracle model, the minimum total protocol expenditure for an adversary to maintain kk independently-challenging miner identities for TT consecutive epochs is:

Cost(k,T)    kT/Wfee\text{Cost}(k, T) \;\geq\; k \cdot \lceil T / W \rceil \cdot \texttt{fee}

where W=256W = 256 is the window size and \texttt{fee} = \0.10$ per mine.

Proof. Each address mim_i must appear in the NCT window at least once per WW epochs to maintain a distinct slot (otherwise it is evicted by the circular buffer). Each window entry requires a successful mine() call at cost fee\texttt{fee}. Fresh addresses (with γ=0\gamma = 0) receive no cost reduction — difficulty D[n]D[n] is uniform across all callers. Therefore maintaining kk distinct addresses for T/W\lceil T/W \rceil window cycles costs at least kT/Wfeek \cdot \lceil T/W \rceil \cdot \texttt{fee}. \square

Corollary 1.10. For k=W=256k = W = 256 (full Sybil, appearing as all distinct): \text{Cost}(256, W) \geq 256 \times \0.10 = $25.60$ per window cycle. This equals the cost of genuine mining with 256 independent physical miners. Sybil provides no economic advantage.

1.5 Precomputation Impossibility — Theorem and Proof

Theorem 1.11 (Structural Precomputation Impossibility). No probabilistic polynomial-time adversary A\mathcal{A} can produce a valid nonce for epoch nn before the block at height lastMineBlock[n1]\texttt{lastMineBlock}[n-1] is finalised by the sequencer, except with probability negligible in the security parameter λ\lambda.

Proof. Let b=blockhash(lastMineBlock[n1])b^* = \texttt{blockhash}(\texttt{lastMineBlock}[n-1]) be the target block hash, produced at an unknown future time t>tnowt^* > t_{\text{now}}. A valid nonce ν\nu^* satisfies:

H ⁣(H ⁣(ι(m,n)ν)    ϵ[n])  <  D[n]H\!\Bigl(H\!\bigl(\iota(m,n) \,\|\, \nu^*\bigr) \;\|\; \epsilon[n]\Bigr) \;<\; D[n]

where ϵ[n]=H(bD[n])\epsilon[n] = H(b^* \,\|\, D[n]). In the random oracle model, H(bD[n])H(b^* \,\|\, D[n]) is uniformly distributed over {0,1}256\{0,1\}^{256} and independent of all values known before bb^* is produced. Therefore:

PrA ⁣[κ(m,ν,n)<D[n]]  =  D[n]2256\Pr_{\mathcal{A}}\!\bigl[\kappa(m,\nu^*,n) < D[n]\bigr] \;=\; \frac{D[n]}{2^{256}}

regardless of which ν\nu^* A\mathcal{A} selects before bb^* is known — this is exactly the probability of a random guess. No precomputed intermediate (including H(ιν)H(\iota \,\|\, \nu^*) for all ν\nu^* in the search space) provides any advantage, because the outer HH takes ϵ[n]\epsilon[n] as input, which is uniformly random over the precomputed set.

More precisely: for any function ff computable before time tt^*, and any nonce ν=f(ι,D[n])\nu^* = f(\iota, D[n]):

Pr ⁣[H(H(ιν)H(bD))<D]  =  D2256\Pr\!\Bigl[H\bigl(H(\iota \,\|\, \nu^*) \,\|\, H(b^* \,\|\, D)\bigr) < D\Bigr] \;=\; \frac{D}{2^{256}}

since H(bD)H(b^* \,\|\, D) is an independent uniform 256-bit value. \square

1.6 Gas Accounting

OperationGas
SLOAD minerEpochCount[m] (warm)100
SLOAD lastMineBlock (warm)100
SLOAD currentDifficulty (warm)100
HH for τ\tau (3 packed args, 96 bytes)54
HH for ι\iota (2 args, 64 bytes)36
HH for inner cascade pass (2 args, 64 bytes)36
HH for outer cascade pass (2 args, 64 bytes)36
SSTORE minerEpochCount++ (warm→dirty)2,900
SSTORE lastMineBlock (warm→dirty)2,900
Base ERC-20 mint + event~30,000
Window buffer + uniqueCount update (§2.1)~12,000
Fee forward + stuck-fee fallback~5,500
Estimated total mine() gas≈ 66,500 gas

At Base L2 with basefee=0.05  gwei\texttt{basefee} = 0.05\;\text{gwei}:

gas cost=66,500×0.05×109  ETH=3.325×106  ETH$0.008\text{gas cost} = 66{,}500 \times 0.05 \times 10^{-9}\;\text{ETH} = 3.325 \times 10^{-6}\;\text{ETH} \approx \$0.008

2. Nakamoto Coefficient Throttle (NCT)

2.1 Circular Buffer — Formal Specification

Definition 2.1 (Miner Window). The contract maintains:

  • W=256W = 256: window size (a power of 2)
  • win[0..255]M256\textbf{win}[0..255] \in \mathcal{M}^{256}: circular buffer of recent miners
  • h{0,,255}h \in \{0,\ldots,255\}: write-head pointer (advances mod 256)
  • freq:M{0,,256}\texttt{freq} : \mathcal{M} \to \{0,\ldots,256\}: reference count per address
  • Cu[1,256]C_u \in [1, 256]: count of distinct addresses in the window

Definition 2.2 (Window Update). On successful mine() by mm:

moutwin[h]win[h]mh(h+1)mod256freq[mout]freq[mout]1CuCu1[freq[mout]=0]freq[m]freq[m]+1CuCu+1[freq[m]=1]\begin{aligned} m_{\text{out}} &\gets \textbf{win}[h] \\[2pt] \textbf{win}[h] &\gets m \\[2pt] h &\gets (h + 1) \bmod 256 \\[2pt] \texttt{freq}[m_{\text{out}}] &\gets \texttt{freq}[m_{\text{out}}] - 1 \\[2pt] C_u &\gets C_u - \mathbf{1}[\texttt{freq}[m_{\text{out}}] = 0] \\[2pt] \texttt{freq}[m] &\gets \texttt{freq}[m] + 1 \\[2pt] C_u &\gets C_u + \mathbf{1}[\texttt{freq}[m] = 1] \end{aligned}

where 1[]\mathbf{1}[\cdot] is the indicator function.

Invariant I11. For all reachable states after the first mine:

Cu  =  {mM:freq[m]>0}    [1,256]C_u \;=\; \bigl|\{m \in \mathcal{M} : \texttt{freq}[m] > 0\}\bigr| \;\in\; [1,\,256]

Proof. At genesis: Cu=0C_u = 0. After first mine: one address has freq=1\texttt{freq} = 1, so Cu=1C_u = 1. Each update increments CuC_u iff a new address enters, and decrements iff an address fully exits. Since freq\texttt{freq} is a reference count bounded by [0,256][0, 256], and at most 256 distinct addresses can reside simultaneously in a 256-slot buffer, Cu256C_u \leq 256 always. Cu=0C_u = 0 is impossible after the first mine because the writer adds its own address before decrement can eliminate all entries. \square

2.2 Concentration Factor — Fixed-Point Representation

Definition 2.3. The concentration factor uses filledSlots kk (the number of non-empty entries in the window, which grows from 00 to 256256 over the first 256256 mines and then stays at 256256):

Cwad[n]  =  k×WADCuC_{\text{wad}}[n] \;=\; \left\lfloor \frac{k \times \text{WAD}}{C_u} \right\rfloor

In the steady state (k=256k = 256) this equals 256×1018/Cu\lfloor 256 \times 10^{18} / C_u \rfloor. The real-valued concentration factor is C[n]=Cwad[n]/WAD[1,256]C[n] = C_{\text{wad}}[n] / \text{WAD} \in [1, 256].

Boundary cases (steady state):

  • Cu=256C_u = 256: Cwad=WADC_{\text{wad}} = \text{WAD}, i.e. C=1C = 1 — fully distributed
  • Cu=1C_u = 1: Cwad=256×WADC_{\text{wad}} = 256 \times \text{WAD}, i.e. C=256C = 256 — fully centralised

Bootstrap suppression. During the first 3232 mines (NCT_BOOTSTRAP_SLOTS = 32), nctSignal() returns 00 regardless of window contents. A single miner must dominate the early window by necessity — this is not an attack. The NCT penalty activates only after 3232 fills, at which point the window contains meaningful distribution data. This suppression also ensures k<BNCTk < B_{NCT} does not produce a spurious concentration signal from an under-filled window.

2.3 NCT Control Signal — Derivation

Definition 2.4 (NCT Signal). With parameters α=0.1\alpha = 0.1 and τmax=0.3\tau_{\max} = 0.3, MinerWindow.nctSignal() returns a non-positive raw signal in Q60.18:

taxwad[n]  =  min ⁣(Cwad[n]WAD10,  τmax,wad)\text{tax}_{\text{wad}}[n] \;=\; \min\!\left(\frac{C_{\text{wad}}[n] - \text{WAD}}{10},\; \tau_{\max,\,\text{wad}}\right) snct[n]  =  taxwad[n]    0s_{\text{nct}}[n] \;=\; -\text{tax}_{\text{wad}}[n] \;\leq\; 0

In real units: snct[n]=min(0.1(C[n]1),  0.3)0s_{\text{nct}}[n] = -\min(0.1\,(C[n]-1),\;0.3) \leq 0.

Sign convention — implementation detail. PIController.step() receives uNct = s_nct (non-positive) and subtracts it from upiu_{\text{pi}}:

uCombined = uPi - uNctClamped // uNctClamped = s_nct ≤ 0

Because snct0s_{\text{nct}} \leq 0, this is equivalent to adding a non-negative penalty. Defining the penalty magnitude unct:=tax[n]0u_{\text{nct}} := |\text{tax}[n]| \geq 0:

u[n]  =  sat ⁣(upi[n]+unct[n],  Umax,  +Umax),unct[n]=min ⁣(0.1(C[n]1),  0.3)0\boxed{ u[n] \;=\; \mathbf{sat}\!\bigl(u_{\text{pi}}[n] + u_{\text{nct}}[n],\;-U_{\max},\;+U_{\max}\bigr), \quad u_{\text{nct}}[n] = \min\!\bigl(0.1\,(C[n]-1),\;0.3\bigr) \geq 0 }

NCT always raises or holds difficulty — it never lowers it. Centralisation (C>1C > 1) increases u[n]u[n], which increases D[n+1]D[n+1].

Observation 2.5. unctu_{\text{nct}} is monotonically non-decreasing in C[n]C[n], equals 00 at C[n]=1C[n] = 1 (fully distributed), and saturates at 0.30.3 for C[n]4C[n] \geq 4.

2.4 Sybil Cost Analysis — Full Derivation

Setup. Suppose a single adversary controls kk addresses m1,,mkMm_1, \ldots, m_k \in \mathcal{M}, each mining with global difficulty D[n]D[n]. To appear fully distributed (Cu=W=256C_u = W = 256), the adversary needs k=256k = 256 distinct addresses each holding 1\geq 1 slot in the 256-slot window.

Cost per window cycle. Each slot evicts the oldest entry after 256 new mines system-wide. The adversary’s addresses must be topped up at rate 1\geq 1 mine per 256 total mines, per address. In expectation, the adversary pays:

σ(k)  =  k×fee  =  k×$0.10per cycle\sigma(k) \;=\; k \times \texttt{fee} \;=\; k \times \$0.10 \quad \text{per cycle}

Suppressing NCT entirely requires k=W=256k = W = 256:

σ(256)  =  256×$0.10  =  $25.60 per 256-mine cycle\sigma(256) \;=\; 256 \times \$0.10 \;=\; \$25.60 \text{ per 256-mine cycle}

This is identical to the cost of 256 legitimate mines. No economic gain.

Proposition 2.6 (Sybil Equivalence). The per-mine cost of suppressing the NCT signal equals the per-mine cost of legitimate mining:

σ(W)W  =  WfeeW  =  fee\frac{\sigma(W)}{W} \;=\; \frac{W \cdot \texttt{fee}}{W} \;=\; \texttt{fee}

Therefore the NCT Sybil attack is economically dominated by legitimate mining: the attacker incurs identical cost while receiving NCT pressure identical to the distributed case, and gains no additional reward. \square

2.5 Stability of NCT Term — Formal Statement

Proposition 2.7. Let unct[n]=tax[n]0u_{\text{nct}}[n] = |\text{tax}[n]| \geq 0 (the penalty magnitude, as defined in §2.3) with 0unct[n]0.30 \leq u_{\text{nct}}[n] \leq 0.3. The combined control signal:

u[n]  =  sat ⁣(upi[n]+unct[n],  Umax,  Umax)u[n] \;=\; \mathbf{sat}\!\bigl(u_{\text{pi}}[n] + u_{\text{nct}}[n],\; -U_{\max},\; U_{\max}\bigr)

with Umax=0.5U_{\max} = 0.5 remains within [0.5,0.5][-0.5, 0.5] for all values of upi[n][0.5,0.5]u_{\text{pi}}[n] \in [-0.5, 0.5] and unct[n][0,0.3]u_{\text{nct}}[n] \in [0, 0.3].

Proof. Since unct0.3<Umax=0.5u_{\text{nct}} \leq 0.3 < U_{\max} = 0.5, the outer sat\mathbf{sat} clamp is sufficient regardless of their sum. The NCT term shifts the operating point of the PI controller by at most 0.30.3 units in the positive direction (raising DD on centralisation), which is within the Lyapunov-stable regime analysed in §3.3. \square


3. Discrete-Time PI Controller on lnD\ln D

3.1 State Space — Formal Definition

Definition 3.1. The PI controller operates on the discrete-time state space S=R×[Imax,Imax]\mathcal{S} = \mathbb{R} \times [-I_{\max}, I_{\max}], with:

VariableDomainSemantics
e[n]e[n]R\mathbb{R}Fractional timing error for period nn
I[n]I[n][Imax,Imax][-I_{\max}, I_{\max}]Integrator state (anti-windup saturated)
upi[n]u_{\text{pi}}[n][Umax,Umax][-U_{\max}, U_{\max}]Proportional-integral control output
D[n]D[n]N1\mathbb{N}_{\geq 1}Difficulty at the start of period nn

3.2 System Equations — Complete Specification

Definition 3.2. With target window T=241,920  sT = 241{,}920\;\text{s} and observed window Tactual[n]=tend[n]tstart[n]T_{\text{actual}}[n] = t_{\text{end}}[n] - t_{\text{start}}[n]:

e[n]  =  Tactual[n]TTI[n]  =  sat ⁣(I[n1]+e[n],  Imax,  +Imax)upi[n]  =  sat ⁣((Kpe[n]+KiI[n]),  Umax,  +Umax)u[n]  =  sat ⁣(upi[n]+unct[n],  Umax,  +Umax)D[n+1]  =  sat ⁣(D[n]exp(u[n]),  D[n]4,  4D[n])\boxed{ \begin{aligned} e[n] \;&=\; \frac{T_{\text{actual}}[n] - T}{T} \\[8pt] I[n] \;&=\; \mathbf{sat}\!\bigl(I[n-1] + e[n],\;{-}I_{\max},\;{+}I_{\max}\bigr) \\[8pt] u_{\text{pi}}[n] \;&=\; \mathbf{sat}\!\bigl(-(K_p\,e[n] + K_i\,I[n]),\;{-}U_{\max},\;{+}U_{\max}\bigr) \\[8pt] u[n] \;&=\; \mathbf{sat}\!\bigl(u_{\text{pi}}[n] + u_{\text{nct}}[n],\;{-}U_{\max},\;{+}U_{\max}\bigr) \\[8pt] D[n+1] \;&=\; \mathbf{sat}\!\bigl(D[n]\cdot\exp(u[n]),\;\tfrac{D[n]}{4},\;4D[n]\bigr) \end{aligned} }

with parameters:

SymbolValueRationale
TT241,920  s241{,}920\;\text{s}2,016×120  s2{,}016 \times 120\;\text{s} target window
KpK_p0.50.5Proportional gain
KiK_i0.050.05Integral gain; critical damping \approx 10 periods
ImaxI_{\max}4.04.0Anti-windup saturation bound
UmaxU_{\max}0.50.5Control output saturation
Max step×4/÷4\times 4\,/\,\div 4Outer difficulty envelope

3.3 Lyapunov Stability Certificate

Theorem 3.3 (Asymptotic Stability at Origin). Consider the unsaturated linearised system (i.e., upi[n]<Umax|u_{\text{pi}}[n]| < U_{\max} and I[n]<Imax|I[n]| < I_{\max}). The origin (e,I)=(0,0)(e, I) = (0, 0) is globally asymptotically stable with Lyapunov function:

V(e,I)  =  e22+KiKpI22V(e, I) \;=\; \frac{e^2}{2} + \frac{K_i}{K_p}\cdot\frac{I^2}{2}

Proof. Positive definiteness. V(e,I)>0V(e,I) > 0 for (e,I)(0,0)(e,I) \neq (0,0), and V(0,0)=0V(0,0) = 0. VV is radially unbounded (VV \to \infty as (e,I)|(e,I)| \to \infty).

One-step decrement. At period nn, assuming e[n+1]upi[n]e[n+1] \approx -u_{\text{pi}}[n] (from the plant dynamics) and I[n]=I[n1]+e[n]I[n] = I[n-1] + e[n]:

ΔV  =  V(e[n+1],I[n+1])V(e[n],I[n])\Delta V \;=\; V(e[n+1], I[n+1]) - V(e[n], I[n])

In the unsaturated regime, the PI law gives:

e[n+1]    (Kpe[n]+KiI[n])e[n+1] \;\approx\; -(K_p\,e[n] + K_i\,I[n])

and ΔI=e[n]\Delta I = e[n]. Therefore:

ΔV  =  e[n]Δe+KiKpI[n]ΔI\Delta V \;=\; e[n]\,\Delta e + \frac{K_i}{K_p}\,I[n]\,\Delta I Δe  =  e[n+1]e[n]    Kpe[n]KiI[n]e[n]\Delta e \;=\; e[n+1] - e[n] \;\approx\; -K_p\,e[n] - K_i\,I[n] - e[n] ΔV  =  e[n](Kpe[n]KiI[n]e[n])+KiKpI[n]e[n]\Delta V \;=\; e[n]\bigl(-K_p\,e[n] - K_i\,I[n] - e[n]\bigr) + \frac{K_i}{K_p}\,I[n]\,e[n] =Kpe[n]2Kie[n]I[n]e[n]2+KiKpKpe[n]I[n]= -K_p\,e[n]^2 - K_i\,e[n]\,I[n] - e[n]^2 + \frac{K_i}{K_p}\cdot K_p\,e[n]\,I[n] =Kpe[n]2e[n]2    Kpe[n]2    0= -K_p\,e[n]^2 - e[n]^2 \;\leq\; -K_p\,e[n]^2 \;\leq\; 0

Cross-terms in e[n]I[n]e[n]\,I[n] cancel exactly. ΔV=0\Delta V = 0 only when e[n]=0e[n] = 0. By LaSalle’s invariance principle (applied to the set {(e,I):ΔV=0}={e=0}\{(e,I) : \Delta V = 0\} = \{e=0\}): the largest invariant subset in this set satisfies I[n]0I[n] \to 0 as well (since e=0e=0 implies II is constant, and then upi=KiIu_{\text{pi}} = -K_i\,I, driving ee away from 0 unless I=0I=0 too). Therefore the unique invariant set is {(0,0)}\{(0,0)\}, confirming global asymptotic stability. \square

3.4 Justification for exp(u)\exp(u) vs. Linear Approximation

Proposition 3.4. The multiplicative update D[n+1]=D[n]exp(u[n])D[n+1] = D[n] \cdot \exp(u[n]) is the unique composition law consistent with operating the controller in log-difficulty space.

Proof. Define [n]=lnD[n]\ell[n] = \ln D[n]. The natural additive update in log-space is [n+1]=[n]+u[n]\ell[n+1] = \ell[n] + u[n], i.e.:

D[n+1]=e[n+1]=e[n]+u[n]=D[n]eu[n]D[n+1] = e^{\ell[n+1]} = e^{\ell[n] + u[n]} = D[n] \cdot e^{u[n]}

The linear approximation D[n+1]D[n](1+u[n])D[n+1] \approx D[n](1 + u[n]) introduces a compounding error. Over NN periods:

i=1N(1+ui)    exp ⁣(i=1Nui)\prod_{i=1}^{N}(1+u_i) \;\neq\; \exp\!\Bigl(\sum_{i=1}^{N} u_i\Bigr)

The relative error at the boundary u=0.5|u| = 0.5:

e0.5(1+0.5)e0.5  =  1.64871.51.6487    9.0%\frac{e^{0.5} - (1 + 0.5)}{e^{0.5}} \;=\; \frac{1.6487 - 1.5}{1.6487} \;\approx\; 9.0\%

Over N=10N = 10 periods this compounds to (1.09)101137%\approx (1.09)^{10} - 1 \approx 137\% error in the aggregate adjustment factor. Exact exp is mandatory for fidelity. \square

3.5 Fourth-Order Maclaurin Approximation

Definition 3.5. The on-chain exp implementation uses the Taylor polynomial:

exp(u)    1+u+u22!+u33!+u44!\exp(u) \;\approx\; 1 + u + \frac{u^2}{2!} + \frac{u^3}{3!} + \frac{u^4}{4!}

Proposition 3.6 (Error Bound). For uUmax=0.5|u| \leq U_{\max} = 0.5:

exp(u)k=04ukk!    u55!11u/6    0.55120111/12    2.84×104\left|\exp(u) - \sum_{k=0}^{4}\frac{u^k}{k!}\right| \;\leq\; \frac{|u|^5}{5!} \cdot \frac{1}{1 - |u|/6} \;\leq\; \frac{0.5^5}{120} \cdot \frac{1}{1 - 1/12} \;\approx\; 2.84 \times 10^{-4}

More conservatively, using the Lagrange remainder with ξ(0,u)\xi \in (0, u):

R4(u)  =  eξ5!u5    e0.51200.55    1.6487×0.03125120    4.3×104\left|R_4(u)\right| \;=\; \frac{e^\xi}{5!}|u|^5 \;\leq\; \frac{e^{0.5}}{120} \cdot 0.5^5 \;\approx\; \frac{1.6487 \times 0.03125}{120} \;\approx\; 4.3 \times 10^{-4}

Both bounds are below 0.044%0.044\% — negligible relative to the 25%25\% step resolution implied by Umax=0.5U_{\max} = 0.5.

Fixed-point implementation. All multiplications are in Q60.18:

(a×b)wad  =  a×b1018(a \times b)_{\text{wad}} \;=\; \left\lfloor \frac{a \times b}{10^{18}} \right\rfloor

Overflow condition: a,b10×WAD|a|, |b| \leq 10 \times \text{WAD} ensures a×b100×WAD22255|a \times b| \leq 100 \times \text{WAD}^2 \ll 2^{255}. At u0.5×WAD|u| \leq 0.5 \times \text{WAD}: u4/24(0.5)4/240.026×WADu^4 / 24 \leq (0.5)^4/24 \approx 0.026 \times \text{WAD}, well within int256 bounds.


4. Q60.18 Fixed-Point Arithmetic

4.1 Representation

Definition 4.1. Q60.18 represents a real number rRr \in \mathbb{R} as the integer rwad=r×WADr_{\text{wad}} = \lfloor r \times \text{WAD} \rfloor where WAD=1018\text{WAD} = 10^{18}. The usable real range is:

r    (2255WAD,  22551WAD)    (5.79×1058,  5.79×1058)r \;\in\; \left(-\frac{2^{255}}{\text{WAD}},\; \frac{2^{255}-1}{\text{WAD}}\right) \;\approx\; (-5.79 \times 10^{58},\; 5.79 \times 10^{58})

All protocol parameters satisfy r1010|r| \ll 10^{10}, so overflow is impossible in the normal operating regime.

4.2 Operation Correctness

OperationWAD formulaExact iff
add(a,b)\text{add}(a,b)a+ba + balways (mod 22562^{256} wrapping excluded by bounds)
sub(a,b)\text{sub}(a,b)aba - balways
mul(a,b)\text{mul}(a,b)(a×b)/WAD\lfloor(a \times b) / \text{WAD}\rfloorintermediate a×b2255a \times b \leq 2^{255}
exp4(u)\text{exp4}(u)Maclaurin, 4 termserror <4.3×104< 4.3 \times 10^{-4} (§3.5)
log2Floor(x)\text{log2Floor}(x)7-step binary searchexact for all xN1x \in \mathbb{N}_{\geq 1}

4.3 log2Floor — Correctness and Complexity

Algorithm 4.2. For xN1x \in \mathbb{N}_{\geq 1}, compute log2x\lfloor\log_2 x\rfloor:

bits ← 0
for s in [128, 64, 32, 16, 8, 4, 2, 1]:
if x >> s > 0:
bits += s
x >>= s
return bits

Proposition 4.3 (Correctness). Algorithm 4.2 returns log2x\lfloor\log_2 x\rfloor for all x1x \geq 1.

Proof. Binary search on the bit-length \ell of xx: at each step, the remaining value of xx is reduced to x/2s\lfloor x / 2^s \rfloor. After 7 steps (exhausting the sequence 128+64+32+16+8+4+2+1=255128+64+32+16+8+4+2+1 = 255), bits accumulates the positions of all set bits from the MSB downward. The result equals the position of the highest set bit = log2x\lfloor\log_2 x\rfloor. \square

Complexity. Exactly 7 conditional branches; O(1)O(1) gas independent of input.


5. Protocol Fee Oracle

5.1 Dimensional Derivation

Goal. Express a USD target fee f = \0.10asanamountinwei,givenChainlinkansweras an amount in wei, given Chainlink answerp(ETH/USDwith(ETH/USD withd = 8decimalplaces,i.e.decimal places, i.e.p = p_{$} \times 10^8$).

Step-by-step:

feeETH  =  fp$  =  0.10p/108  =  0.10×108p\text{fee}_{\text{ETH}} \;=\; \frac{f}{p_{\$}} \;=\; \frac{0.10}{p / 10^8} \;=\; \frac{0.10 \times 10^8}{p} feewei  =  feeETH×1018  =  0.10×108×1018p  =  101×1026p  =  1025p\text{fee}_{\text{wei}} \;=\; \text{fee}_{\text{ETH}} \times 10^{18} \;=\; \frac{0.10 \times 10^8 \times 10^{18}}{p} \;=\; \frac{10^{-1} \times 10^{26}}{p} \;=\; \frac{10^{25}}{p}

Equivalently, expressing f=100,000  μUSDf = 100{,}000\;\mu\text{USD}:

feewei  =  100,000×1020p\boxed{ \text{fee}_{\text{wei}} \;=\; \frac{100{,}000 \times 10^{20}}{p} }

Sanity check at p_{\} = $2{,}500( (p = 2{,}500 \times 10^8 = 2.5 \times 10^{11}$):

feewei  =  10252.5×1011  =  4×1013  wei  =  4×105  ETH  =  $0.10\text{fee}_{\text{wei}} \;=\; \frac{10^{25}}{2.5 \times 10^{11}} \;=\; 4 \times 10^{13}\;\text{wei} \;=\; 4 \times 10^{-5}\;\text{ETH} \;=\; \$0.10 \quad \checkmark

Integer arithmetic in Solidity. The numerator 102510^{25} fits within uint256 (1025<22561.16×107710^{25} < 2^{256} \approx 1.16 \times 10^{77}). Division is integer floor-division, introducing a rounding error of at most 1  wei=1018  ETH1\;\text{wei} = 10^{-18}\;\text{ETH}, which is negligible.

5.2 Oracle Validity — Formal Invariants

Invariant O1 (Positive Answer):

p>0or revert  InvalidOraclep > 0 \quad\text{or revert}\;\texttt{InvalidOracle}

Invariant O2 (Non-Future Timestamp):

updatedAtblock.timestampor revert  OracleClockSkew\texttt{updatedAt} \leq \texttt{block.timestamp} \quad\text{or revert}\;\texttt{OracleClockSkew}

Invariant O3 (Freshness):

block.timestampupdatedAt24hoursor revert  StaleOracle\texttt{block.timestamp} - \texttt{updatedAt} \leq 24\,\text{hours} \quad\text{or revert}\;\texttt{StaleOracle}

(ORACLE_MAX_STALENESS = 24 hours in Anvil256.sol.)

Invariant O4 (Decimal Bound):

d24or revert  OracleDecimalsTooLarged \leq 24 \quad\text{or revert}\;\texttt{OracleDecimalsTooLarge}

Invariant O5 (Answered-In-Round Guard):

answeredInRoundroundIdor revert  StaleOracle\texttt{answeredInRound} \geq \texttt{roundId} \quad\text{or revert}\;\texttt{StaleOracle}

If answeredInRound < roundId the aggregator is returning a cached answer from a prior round that has not yet been superseded — treated as stale.

Note on Round ID gaps. Chainlink OCR2 aggregators do not guarantee contiguous round IDs across phase boundaries. A gap in the sequence of roundId values (e.g. roundId jumps from 1 to 10 after a phase upgrade) is not checked — checking it would produce false positives during normal aggregator upgrades. The answeredInRound < roundId guard (O5) is narrower: it only rejects rounds where the oracle explicitly signals the answer came from a prior round, which is a reliable indicator of a stale response.


6. Supply Curve — Complete Verification

6.1 Reward Function — Formal Definition

Definition 6.1. The block reward at epoch nNn \in \mathbb{N} is:

R(n)  =  {R0n/Hif n/H<640if n/H64R(n) \;=\; \begin{cases} R_0 \gg \lfloor n/H \rfloor & \text{if } \lfloor n/H \rfloor < 64 \\ 0 & \text{if } \lfloor n/H \rfloor \geq 64 \end{cases}

where R0=50×1018R_0 = 50 \times 10^{18} (50 ANVL in wei) and H=210,000H = 210{,}000. The operator \gg is the arithmetic right-shift, i.e.:

R(n)  =  R02n/Hfor halvings 063R(n) \;=\; R_0 \cdot 2^{-\lfloor n/H\rfloor} \quad\text{for halvings } 0\ldots63

6.2 Miner-Only Schedule and Actual Supply Cap

Theorem 6.2 (Miner-Only Baseline). The idealized sum of miner rewards over all halving bands approaches 21,000,00021{,}000{,}000 ANVL:

k=063HR02k  =  HR0k=0632k  =  HR01264112  =  2HR0(1264)\sum_{k=0}^{63} H \cdot R_0 \cdot 2^{-k} \;=\; H \cdot R_0 \cdot \sum_{k=0}^{63} 2^{-k} \;=\; H \cdot R_0 \cdot \frac{1 - 2^{-64}}{1 - \frac{1}{2}} \;=\; 2 \cdot H \cdot R_0 \cdot (1 - 2^{-64})

Taking the negligible 2642^{-64} tail as zero for the idealized series:

lim    2×210,000×50  =  21,000,000  ANVL\lim \;\approx\; 2 \times 210{,}000 \times 50 \;=\; 21{,}000{,}000\;\text{ANVL}

Integer right-shift truncation (implementation note). The Solidity implementation uses R(n) = INITIAL_REWARD >> halvings (integer bit-shift). Due to floor truncation at each shift, the actual total mintable supply across all 64 halving bands is approximately 20,999,99120{,}999{,}991 ANVL — roughly 99 ANVL below MAX_SUPPLY in the miner-only schedule.

The deployed contract also mints protocol-owned liquidity inside the same cap:

Sseed=1  ANVL,MLP(n)=0.1R(n)S_{seed}=1\;\text{ANVL},\qquad M_{LP}(n)=0.1R(n)

For a non-boundary mine:

ΔS(n)=R(n)+MLP(n)=1.1R(n)\Delta S(n)=R(n)+M_{LP}(n)=1.1R(n)

At cap boundaries, mine() first truncates R(n)R(n) to remaining supply and then truncates MLP(n)M_{LP}(n) to the remaining headroom after the miner reward. Thus the actual invariant is:

Sseed+n(Rpaid(n)+MLP,paid(n))21,000,000  ANVLS_{seed}+\sum_n\bigl(R_{paid}(n)+M_{LP,paid}(n)\bigr)\leq 21{,}000{,}000\;\text{ANVL}

The 10% POL reserve is not inflation outside the cap; it consumes the same cap and therefore causes the cap to be reached earlier than the miner-only terminus.

Residual from finite truncation (idealized):

δ  =  HR0263  =  210,000×50263    1.14×1012  ANVL\delta \;=\; H \cdot R_0 \cdot 2^{-63} \;=\; \frac{210{,}000 \times 50}{2^{63}} \;\approx\; 1.14 \times 10^{-12}\;\text{ANVL}

Moreover, the reward schedule returns zero and mine() reverts with MiningEnded() at n13,440,000n \geq 13{,}440{,}000 if MAX_SUPPLY has not already stopped minting earlier.

6.3 Halving Table (Miner-Only Reference)

Halving kkEpoch start kHkHR(kH)R(kH) (miner ANVL)Miner-only cumulative% of 21 M
0050.00000010,500,00050.0000%
1210,00025.00000015,750,00075.0000%
2420,00012.50000018,375,00087.5000%
3630,0006.25000019,687,50093.7500%
4840,0003.12500020,343,75096.8750%
51,050,0001.56250020,671,87598.4375%
71,470,0000.39062520,917,96999.6094%
102,100,0000.04882820,989,74699.9512%
142,940,0000.00305120,999,35999.9969%
326,720,000<108< 10^{-8}21,000,000\approx 21{,}000{,}000100%\approx 100\%
6413,440,0000 (terminus)21,000,000100.0000%

Computation rule: miner-only cumulative supply after halving kk is: j=0k1HR02j=2HR0(12k)\sum_{j=0}^{k-1} H \cdot R_0 \cdot 2^{-j} = 2HR_0(1 - 2^{-k}).

Actual totalSupply includes the 1 ANVL genesis LP seed and 10% POL reserve mints, then applies MAX_SUPPLY truncation.

No calendar projections are provided. The protocol does not compute wall-clock time. Epoch duration is an emergent quantity; multiply epoch count by the observed mean epoch time for any estimate.


7. Controller Interaction — Unified Signal Flow

The three subsystems interact only through D[n]D[n]:

Each mine():
γ(m)++ [Temporal binding — §1.2]
win[h] ← m; h ← (h+1) mod 256 [NCT buffer — §2.1]
uniqueCount ← maintained count [NCT signal input — §2.2]
Every 2,016 mines (one period boundary):
e[n] ← (T_actual − T) / T [Timing error — §3.2]
I[n] ← sat(I[n−1] + e[n], ±I_MAX) [Integrator — §3.2]
u_pi ← sat(−(Kp·e + Ki·I), ±0.5) [PI signal — §3.2]
k ← filledSlots (grows 0→256) [Bootstrap guard — §2.2]
C_wad ← (k × WAD) / uniqueCount [Concentration — §2.2]
s_nct ← −min(0.1·(C−1), 0.3) [≤ 0] [Raw NCT from MinerWindow — §2.3]
u_nct ← |s_nct| = min(0.1·(C−1), 0.3) [≥ 0] [Penalty magnitude — §2.3]
u ← sat(u_pi + u_nct, ±0.5) [Combined — §2.5]
D[n+1] ← sat(D[n]·exp4(u), D/4, 4D) [Difficulty update — §3.2]
Note: PIController receives s_nct and computes: u = uPi − s_nct = uPi + u_nct
After every mine() (using post-adjustment D[n+1] at period boundaries):
ε[n+1] ← H(blockhash(block) ‖ currentDifficulty)
[Epoch entropy — §1.3]

Critical ordering note. The difficulty adjustment (PIController.step) occurs before epochEntropy is written. This ensures ε[n+1] commits to the post-adjustment difficulty D[n+1], not the stale D[n]. This is the only ordering consistent with Definition 1.7:

ϵ[n+1]  =  H ⁣(blockhash(lastMineBlock[n])D[n+1])\epsilon[n+1] \;=\; H\!\bigl(\texttt{blockhash}(\texttt{lastMineBlock}[n]) \,\|\, D[n+1]\bigr)

where D[n+1]D[n+1] is the difficulty that will govern epoch n+1n+1.


8. References

  • Nakamoto, S. Bitcoin: A Peer-to-Peer Electronic Cash System. 2008.
  • Åström, K.J. & Murray, R.M. Feedback Systems. Princeton University Press, 2nd ed. 2021.
  • Khalil, H.K. Nonlinear Systems. Prentice Hall, 3rd ed. 2002.
  • LaSalle, J.P. The Stability of Dynamical Systems. SIAM, 1976.
  • NIST FIPS 202. SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions. 2015.
  • EIP-2929. Gas Cost Increases for State Access Opcodes. 2021.
  • Chainlink Labs. OCR2 Aggregator Architecture. docs.chain.link.