# Two accumulators, one stake: paying emission and interest with zero cross-subsidy

> Canonical: https://blazephoenix.xyz/learn/the-dual-accumulator
> License: CC BY 4.0 (attribution + link) · © 2026 BlazePhoenix
> Updated: 2026-07-21

BlazePhoenixStaking runs two MasterChef-style accumulators over one stake base: emission (180M BZPX over 7 years) paid on boosted effective stake, and borrower interest paid only to pure savers — separate denominators, so no role subsidises another, all under a single solvency invariant and a quadratic lock boost up to 2.75×.

Most protocols would build three contracts here: a staking vault, a lending market, and a lock-boost incentive layer, each with its own accounting and its own attack surface. BlazePhoenixStaking builds one — a single contract whose reward mathematics is two MasterChef-style accumulators sharing one stake base, every privileged path bounded by a proof rather than a promise. The design rule, stated in the whitepaper: do not build three systems where one suffices.

The two accumulators track two genuinely different cash flows, so they carry two different denominators — and that is the whole trick. No staker earns from a pool they did not fund.

## Two flows, two denominators

accRewardPerShare distributes the protocol’s fixed emission — 180,000,000 BZPX released linearly over seven years — across totalBoostedEffective, the boosted net stake of everyone. accPureYieldPerShare distributes borrower interest across totalBoostedPure, the boosted stake of pure savers only (positions carrying no debt). A borrower earns emission on their effective stake, but earns none of the interest yield — because the money they borrowed is not lending to anyone. A saver dilutes no one’s emission. Each flow is paid strictly from its own base.

```
function _computeBoost(UserInfo storage u) internal view returns (uint256 be, uint256 bp) {
    uint256 boost = boostByDays(u.lockDays);
    uint256 effective = u.staked > u.debt ? u.staked - u.debt : 0;
    be = effective == 0 ? 0 : mulDiv(effective, boost, BOOST_BASE);          // emission base
    bp = (u.debt == 0 && u.staked > 0) ? mulDiv(u.staked, boost, BOOST_BASE) : 0; // pure-yield base
}
```

## The boost is quadratic in commitment

Both bases are weighted by a single boost curve, continuous in the committed lock duration d (in days) and quadratic — so longer locks are rewarded super-linearly, up to 2.75× at the full seven-year horizon:

> equation: boost(d)=10000+750·d365+250(d365)2bps — boostByDays(d): 1 year → 1.10×, 2 years → 1.25×, 5 years → 2.00×, 7 years (2555 days) → 2.75×. Staking is mandatory-locked (90..2555 days); there is no liquid stake.

## The interest curve that feeds the second accumulator

Borrower interest — the fuel for accPureYieldPerShare — follows a kinked rate curve in utilisation u = totalDebt / totalStaked, gentle below 80% and deliberately punishing above it, so near-total utilisation is economically absurd and exit liquidity is protected:

> equation: rate(u)=100+500uif&#160;u≤0.8500+72500(u−0.8)if&#160;u&gt;0.8bps — _interestRate(): 1% APR at zero utilisation, 5% at the 80% kink, ~150% as utilisation approaches 100%. A 3% reserve factor is skimmed to protocolReserve; the rest feeds pure savers.

## One writer, no drift

Two accumulators over one base only stays honest if the two global denominators can never desync from the sum of their parts. So there is exactly one function — _applyBoost — permitted to write totalBoostedEffective and totalBoostedPure, and it does so by plain checked subtraction: the global total is by construction the sum of every tracked contribution, so it is always at least this user’s tracked value, and any drift would underflow and revert. Even the emergency exit routes through it, so leaving can never strand a stale boosted ghost-share. The dual accumulators, the boost, and the interest all live under the single solvency invariant of the Master Conservation Identity — subordinate to one equation that no reachable state can violate.

**Verify it yourself:** cast call 0x3f60C7aa0c36a78D200405feBE143d2Cf3fA0c77 "getGlobalStats()" --rpc-url https://mainnet.base.org — read totalBoostedEffective and totalBoostedPure side by side: two independent denominators over one stake base

Related: https://blazephoenix.xyz/learn/master-conservation-identity · https://blazephoenix.xyz/learn/oracle-free-lending · https://blazephoenix.xyz/learn/autonomous-maintenance · https://blazephoenix.xyz/learn/the-512-bit-multiply
