State Variables & Price Anchors
The Treasury maintains a minimal but sufficient state surface. This page covers the state that matters for understanding behaviour, then the price-anchor system: the handful of computed reference prices that every engine decision keys on.
Immutable references
The market a launch operates in is fixed at deployment: the token, the WETH contract, the Uniswap factory, the canonical pair, and the addresses of every peer contract (teamDistribution, supporterDistribution, supporterVault, governanceModule, and, for third-party launches, the ecosystemReceiver). The committed launch capital (poolSeedingETH, accumulationETH), the distribution shares, and most engine parameters are immutables alongside them. The one exception is the six market-making dials described under the parameter model below, which are team-tunable state confined within immutable ranges; everything else can never change after deployment.
Lifecycle state
Three values define where a launch is in its life: launched (set true by launch(), never unset), launchPhaseEndTime (when the finite launch-phase sell program ends), and shutdownInitiated (set true by shutdown(), never unset). Everything else the engine does is gated on this spine: nothing trades before launch or after shutdown.
Execution accounting
Each side of the engine keeps the counters its caps need:
- Buy side —
lastBuyTime(spacing between buys),buyPeriodStart/buyPeriodSpent(the rolling daily budget window), anddeployPeriodStart/deployPeriodBuysETH(the global daily deploy cap, which counts buys only; sells never consume or refill it). - Sell side (steady-state) —
lastPoolETHSnapshotandlastPoolSnapshotTime, the pool-delta sampling state described in Liquidation Logic, plussellPeriodStart/sellPeriodVolumefor the per-period pool cap. - Launch phase —
launchPhaseSold(progress toward the hard supply cap) andlastLaunchSellTime(chunk spacing). - Realised sales —
totalTokensSoldandtotalETHReceived, updated only in the liquidation paths. These two accumulators defineavgSell, and their isolation from the buy path is a hard requirement: Treasury buying can never influence the realised-sale average. - Shutdown —
shutdownTimestamp,abandonmentMode,tokenHolderClaimPool, andremainingUnclaimedSupply, which drive post-shutdown claims.
The price-anchor system
All anchors use the P_* notation, and all are computed on demand from live state: no anchor is stored, cached, or updated incrementally. "Max" in a name means the point of maximum behavioural output, not a maximum price.
P_floor: the dynamic floor
P_floor = ethReserve / (totalSupply − treasuryTokenBalance)
The price that would prevail if every token not held by the Treasury sat in the pool at once: the most conservative valuation derivable purely from on-chain state, with no oracle. It is a live reference, not an enforced floor: it rises as the Treasury accumulates (the denominator shrinks), and falls when external holders sell into the pool or the Treasury liquidates. A zero base-asset reserve reverts (DeadPool) rather than producing a degenerate zero floor.
avgSell: the realised exit average
avgSell = totalETHReceived / totalTokensSold
The average price at which the Treasury has actually sold: realised behaviour, not valuation. Computed on demand from the two raw accumulators; returns zero before any sale. Because only liquidation updates the accumulators, and liquidation only executes into demonstrated strength, avgSell cannot be dragged around by Treasury buying or by external traders.
The accumulation anchors
P_accMax = P_floor × accMaxMult ($PURE at deployment: 1.2×)
P_accStart = min( max( P_floor × accStartMult, α × avgSell ), P_liqStart − 1 )
P_accStart is the activation threshold: at or below it, the engine will buy. P_accMax is the full-intensity point: at or below it, buying runs at maximum intensity. Between them, intensity ramps quadratically (see Accumulation Logic). Both multipliers (accMaxMultE18, accStartMultE18) are direct multiples of the live floor, and both are among the team-tunable dials; there is no derived start band, so the anchors are exactly what the current dial values say they are.
The P_accStart formula is doing three jobs at once. The floor branch keeps the anchor meaningful when sell history is thin: early on, the engine accumulates relative to the structural floor. The α × avgSell branch takes over once real exits have accrued: the engine then accumulates only at a meaningful discount (α, e.g. 0.50) to its own realised exit prices. And the clamp at P_liqStart − 1 guarantees the accumulation range can never overlap the liquidation range, however high avgSell climbs.
Note that P_accStart is not monotonic: it can fall, because P_floor can fall. That is accepted, correct behaviour: the anchors reflect market reality rather than defending a historical level.
The liquidation anchors
P_liqStart = P_floor × liqStartMult ($PURE at deployment: 3.0×)
P_liqMax = P_floor × liqMaxMult ($PURE at deployment: 6.0×)
Selling begins only above P_liqStart and reaches maximum fraction at P_liqMax; both expressed as multiples of the live floor, so "strength" always means strength relative to current structural value, not to any stored price.
The ordering invariant
P_floor < P_accMax < P_accStart < P_liqStart < P_liqMax
This ordering holds at all times. It is enforced through three explicit cross-parameter invariants, checked in the constructor and re-checked whenever the dials are tuned: the liquidation multipliers must sit at least 0.5× apart, the accumulation start must sit at least 0.1× above the accumulation max (which also keeps the intensity ramp's denominator away from zero), and the accumulation start must sit at least 0.5× below the liquidation start (a guaranteed neutral zone between the buy and sell bands). On top of that, the P_liqStart − 1 clamp on P_accStart re-enforces the separation dynamically at runtime. Band inversion is structurally impossible under any permitted dial setting: the engine can never be simultaneously in its buy zone and its sell zone.
Public getters
The Treasury exposes the band on-chain (getFloor(), getPLiqStart(), getPLiqMax(), plus getPAccStart() and getAvgSell()) so external readers consume the anchors from the contract's own math. The spot-price marker is the pair's reserve ratio, read from the pair itself.
The parameter model
Most engine parameters are plain immutables: fixed at deployment, validated once against the protocol's enforced ranges in the Treasury constructor, with no setter of any kind afterward. This covers every rate cap and budget on both sides (the per-transaction, per-period, and global-deploy limits), every timing window, the buy and sell size bounds, the distribution shares, and the committed launch capital.
The exception is the market-making band: six dials that shape where and how aggressively the engine acts, without touching how much it is permitted to move. They are liqStartMultE18 and liqMaxMultE18 (the liquidation band), qMaxBps (the sell-fraction ramp's peak), accMaxMultE18 and accStartMultE18 (the accumulation band), and alphaE18 (the discount to avgSell). These are team-tunable state, each confined within an immutable [lo, hi] range hardcoded into the contract at the source level. A single atomic setter (setMMBand), callable only by the team address, takes the whole six-dial tuple; it reverts unless every dial is inside its immutable range and the three band-ordering invariants above hold across the supplied tuple, and every successful change emits an MMBandUpdated event, so the current band is always on-chain and every adjustment is publicly observable the moment it happens.
The tuning authority is deliberately narrow: it can reposition the bands within their committed envelopes, and nothing else. It confers no power to mint, move funds, change the distribution splits, or raise any rate cap; the caps, which bound the worst outcome any in-range band setting could produce, remain immutable. GovernanceModule governs treasury releases and shutdown authorisation only; it has no reach into engine parameters in either direction.
A handful of values are hardcoded constants, not configurable even at deployment: the minimum intensity gate (5%), the launch-sell chunk size (0.10% of supply) and strength threshold (3.0×), the minimum sell fraction at P_liqStart (zero), the 6-month vesting period, the 1-year claim window, the third-party ecosystem share (500 bps), the ecosystem receiver's 50/50 split, and the governance release caps (20% of MM WETH / 2% of token supply).
The full parameter tables ($PURE's confirmed values and the constructor-enforced ranges every launch must satisfy) are collected in Reference.