YAM Finance rebase totalSupply inflation / governance bricking (2020-08-13)
- Name: YAM Finance rebase
totalSupplyinflation / governance bricking - Date: 2020-08-13
- Protocol: YAM Finance
- Chain: Ethereum
- Category: elastic-supply arithmetic bug / governance-liveness failure / treasury-lock incident / timelock-race rescue failure
- Loss: no attacker treasury sweep was needed, but the protocol became effectively ungovernable and roughly
$750kofyCRVin the reserve/governor path was left stranded; the original YAM v1 system had to be abandoned and migrated - Summary: YAM v1’s rebasing token contract computed post-rebase
totalSupplyasinitSupply * yamsScalingFactorand forgot the final division byBASE (1e18). The first positive rebase therefore published an absurdly largetotalSupply. The next rebase then propagated that bad state into the governor-side reserve mint path, inflatinginitSupplyitself. Because YAM governance thresholds were defined as percentages ofinitSupply, quorum and proposal threshold became unattainably large. The community assembled a bug-fix proposal, but GovernorAlpha’s fixed12.5hour timelock meant it could not execute before the second rebase. After that second rebase, the corruptedinitSupplymade the rescue proposal fail quorum and even allowed it to be canceled, leaving the protocol frozen and the reserve funds stuck. - Trigger / entry point:
- YAM v1 used an elastic-supply token model derived from Ampleforth-style rebasing.
YAMToken.rebase()updatedyamsScalingFactor, then recomputedtotalSupplyfrominitSupplyand the scaling factor.- The live code set
totalSupply = initSupply.mul(yamsScalingFactor);instead of dividing byBASE, so the reported supply after a positive rebase was wrong by1e18. - GovernorAlpha derived
proposalThreshold()andquorumVotes()frominitSupply, not from some separately bounded governance supply.
- Root cause:
- A one-line arithmetic omission in
YAMToken.rebase()left the post-rebasetotalSupplyscaled incorrectly. - YAM’s governance liveness depended on supply variables that the rebase system itself could corrupt, so an accounting bug in monetary policy became a constitutional failure.
- The rescue design also had a timing mismatch: the protocol’s bug-fix proposal still had to survive the standard GovernorAlpha queue-and-delay path even though the next rebase would make governance thresholds unreachable.
- In effect, YAM coupled treasury recovery and governance repair to the same mutable state object that had already been corrupted.
- A one-line arithmetic omission in
- Failure path:
- YAM launched with unaudited elastic-supply logic and reserve/governance mechanics tied to rebases.
- On the first positive rebase,
YAMToken.rebase()updatedyamsScalingFactorand then settotalSupply = initSupply.mul(yamsScalingFactor)without dividing byBASE. - That first rebase published an absurdly large
totalSupply, visible in transaction0x7b9017ec92b0200455e5269380195fbecfbf91c8acda30985cc1dc413d215076. - The community noticed the bug and launched the
SAVE YAMcoordination campaign, which asked holders to delegate roughly1,600,000 YAMby07:00 UTCand keep delegated voting power above400,000 YAMthrough the vote window so a rescue proposal could land before the next rebase. - The proposed emergency patch had two legs: pause rebases and hand control to a temporary governance contract at
0xd87c869f4672363ef2367bb817b086a25735626bwith harder-coded liveness-preserving parameters. - Even with enough social coordination to submit and queue the fix, GovernorAlpha still assigned the proposal an ETA of
currentTimestamp + 12.5 hours, which placed execution after the already-scheduled second rebase. - During the second rebase, transaction
0x32735e9e9aac51739b5725a225be6c7a3851f422be986d0f4f4bc0ec475ee286, the badtotalSupplyfed into the reserve-mint path and corruptedinitSupplyitself. - Because
proposalThreshold()was1%ofinitSupplyandquorumVotes()was4%ofinitSupply, the bug-fix proposal no longer met live governance thresholds after the second rebase. - A keeper later canceled the queued proposal in transaction
0x1b98c761592b54498b9fbd41e6e4755cf6e5a1a6f13658d409081532d89d6bf0, since the proposer’s voting power had fallen below the now-exploded threshold. - YAM v1 was left technically running but practically ungovernable, with the reserve-side
yCRVstranded and the community forced toward migration rather than in-place repair.
- What had to be true for the incident to become unrecoverable:
- The rebase bug had to fire before a corrective proposal could both pass and clear the timelock delay.
- Governance thresholds had to remain functions of mutable supply state that the rebase path itself could distort.
- The reserve mint/rebase path had to propagate the first bad
totalSupplyintoinitSupply, not merely into a cosmetic display variable. - No privileged fast path, guardian override, or pre-committed emergency patch existed that could bypass ordinary governance timing once the bug was public.
- Technical anatomy worth remembering:
- This was not a classical attacker drain. It was a monetary-policy arithmetic bug that escalated into governance self-bricking.
- The decisive missing operation was the final
/ BASEin the line recomputingtotalSupplyafter a rebase. - The first rebase corrupted the displayed/live total supply; the second rebase made that corruption constitutional by poisoning
initSupply, the variable used for proposal threshold and quorum. - The timelock mattered as much as the bug. YAM’s community could coordinate a rescue proposal, but the protocol’s own delay guarantees ensured that the fix became executable only after the second, fatal state transition.
- The attempted rescue path is worth preserving in detail because it was not a vague
someone should have moved fasterstory. The emergency plan was concrete: pause rebases, hand control to a temporary governor, and use hardcoded liveness-friendly parameters (10,000unscaled YAM proposal threshold,35,000unscaled YAM quorum,8hour voting period). The design still lost because that new lane was itself downstream of the old timelock. - The note is a clean reminder that governance thresholds should not depend on mutable accounting state that can be broken by the subsystem governance is supposed to repair.
- Representative artifacts:
- Buggy line in
YAMToken.rebase():totalSupply = initSupply.mul(yamsScalingFactor); - Intended line described in public analysis:
totalSupply = initSupply.mul(yamsScalingFactor).div(BASE); - First bad rebase transaction:
0x7b9017ec92b0200455e5269380195fbecfbf91c8acda30985cc1dc413d215076 - Second rebase transaction:
0x32735e9e9aac51739b5725a225be6c7a3851f422be986d0f4f4bc0ec475ee286 - Proposal-cancel transaction after threshold blowout:
0x1b98c761592b54498b9fbd41e6e4755cf6e5a1a6f13658d409081532d89d6bf0 - Governance timing constant highlighted in public analysis:
timelock.delay() = 12.5 hours - Rescue-governor address proposed during
SAVE YAM:0xd87c869f4672363ef2367bb817b086a25735626b - Rescue-governor parameters proposed during
SAVE YAM: hardcoded proposal threshold10,000unscaled YAM, hardcoded quorum35,000unscaled YAM (1%of initial supply), voting period8 hours - Governance thresholds highlighted in public analysis for the live v1 governor:
proposalThreshold() = 1% of initSupply,quorumVotes() = 4% of initSupply
- Buggy line in
- Response / mitigation:
- YAM publicly disclosed the rebase bug and rallied the community into an emergency
SAVE YAMdelegation campaign aimed at passing a patch before the next rebase. - The concrete rescue plan was to pause rebases and transfer control to a temporary governance contract with lower hardcoded thresholds and a shorter voting period, but the proposal still had to traverse the live GovernorAlpha / timelock path first.
- The community did manage to coordinate a bug-fix proposal, but later analysis concluded that normal GovernorAlpha delay mechanics made in-time execution impossible.
- After the second rebase, the protocol acknowledged that YAM v1 could no longer be modified by governance, noted that roughly
75%of liquidity had been removed from theYAM/yCRVpool before the fatal rebase, and warned that any residual pool liquidity remained unsafe. - The project moved toward a migration / relaunch path (
YAM 2.0) instead of trying to recover v1 in place.
- YAM publicly disclosed the rebase bug and rallied the community into an emergency
Pattern tags
- mutable-threshold-state-self-bricking
- governance-capture
- The fatal transition was not
bad proposal passes; it wasbad supply state becomes the denominator that decides whether any future proposal can still pass. - The first rebase only published absurd supply state, but the second rebase promoted that bad state into constitutional truth by poisoning
initSupply, the variable GovernorAlpha used for proposal threshold and quorum. - The emergency patch path remained downstream of the broken constitution. YAM’s community could coordinate socially, but the queued fix still had to survive the same timelock and threshold machinery that the next rebase was about to make unreachable.
- Proposal-cancel rights also rode the corrupted denominator, so the protocol did not just lose the ability to pass the fix; it also let the queued rescue become cancelable after the second rebase.
Why the exploit worked
- YAM fused monetary-policy accounting and constitutional accounting too tightly. A one-line arithmetic omission in
rebase()did not stay local to supply presentation; it spilled intoinitSupply, which GovernorAlpha treated as the base for proposal threshold and quorum. Once that happened, the bug was no longer merely economic-state corruption; it was electorate corruption. - The protocol needed governance to outrun the next scheduled state transition, but its own timelock guaranteed the opposite. That is the decisive liveness failure here: the community identified the bug quickly enough to coordinate a rescue proposal, yet the canonical repair lane still forced the patch to wait until after the next rebase that would make repair mathematically unreachable.
- The second rebase was the constitutional point of no return. Before it, governance was endangered but still legible; after it, the corrupted supply base had propagated into the exact denominator used for proposer qualification, quorum, and cancelability. The same accounting fault now defined who could still govern at all.
- The rescue path was not independent of the broken object. The emergency plan depended on old GovernorAlpha and the old timelock to authorize a new liveness-preserving governor, so the supposedly safer lane still inherited the timing and denominator fragility of the constitution it was trying to replace.
- This is why YAM is more than a tokenomics bug. The protocol effectively let one nearby accounting object decide both
how many tokens existandwhether the system can still repair itself, so when the object broke, governance stopped being the fix and became another casualty.
Three constitutional-liveness promotions this incident collapsed
-
A rebase-authored supply denominator still existed and could keep moving
- After the first bugged rebase, YAM still had live
totalSupply,initSupply, and another scheduled rebase waiting in the near future. - That only meant
mutable supply state still exists and the next transition is still coming.
- After the first bugged rebase, YAM still had live
-
That corrupted supply state still counted as canonical constitutional threshold truth
- YAM let GovernorAlpha continue deriving
proposalThreshold()andquorumVotes()frominitSupplyeven after the nearby monetary-policy system had already proved it could publish nonsense. - The decisive promotion was not merely
supply is wrong; it wasthis same now-corrupted supply object still defines who can legitimately propose, pass, and cancel rescue governance.
- YAM let GovernorAlpha continue deriving
-
That accepted threshold truth still got to gate the only repair lane and treasury recovery path
- The emergency patch still had to survive the old GovernorAlpha plus
12.5hour timelock path, and later the same exploded denominator even made the queued rescue cancelable. - In other words, YAM let the broken denominator keep deciding whether rebases could be paused, whether a temporary governor could be installed, and whether stranded reserve-side assets could ever be recovered.
- The emergency patch still had to survive the old GovernorAlpha plus
This is why the incident is more precise than rebase bug broke governance: YAM collapsed mutable supply state exists, that state still defines constitutional truth, and that accepted truth still deserves to gate the only rescue lane into one broken object.
Detection and audit pivots
- Inventory every automatic accounting path that can mutate governance denominators. If rebases, reserve mints, share rescalings, or accounting syncs can touch the variables behind proposal threshold, quorum, proposer eligibility, or cancelability, they already belong in constitutional review.
- Ask whether the next scheduled transition makes recovery easier or harder. YAM’s key failure was not only that a bug existed, but that the next ordinary rebase would make the constitution less reachable than it already was.
- Model rescue durability, not only rescue submission. A fix proposal is not a real backstop if later denominator drift can strip proposer qualification, raise quorum out of reach, or make the proposal cancelable before execution.
- Separate
community can coordinatefromprotocol can execute the repair in time. Offchain urgency and onchain liveness are different objects, and YAM shows how a protocol can have the first while already losing the second. - Review timelock delay against adjacent automatic transitions. If the waiting period safely improves review for routine proposals but guarantees fatal delay for a liveness-preserving repair, the design needs a narrower emergency lane.
- Alert on threshold anomalies as first-class incident signals. Implausible jumps in proposal threshold, quorum, or delegated-vote requirements should page operators the same way treasury drains or supply explosions do.
Why this incident matters
- YAM preserves a rare but important failure mode where tokenomics math did not just misprice a pool or mint excess tokens; it destroyed the protocol’s own ability to govern and repair itself.
- It is a sharp case study in how emergency governance is only as fast as its slowest timelock, and why
community can coordinate quicklyis not the same asprotocol can patch quickly. - The note is also useful whenever a protocol lets mutable supply, share, or reserve variables feed directly into constitutional thresholds. Once those state variables are wrong, governance may stop being a repair mechanism and become another casualty.
Failure-prevention checklist
- Derive proposal threshold, quorum, proposer eligibility, and cancellation rights from a bounded constitutional electorate base rather than live rebasing or reserve-accounting state such as
initSupply. - Inventory every non-governance code path that can still mutate governance-critical denominator state, including rebases, reserve-mint paths, share rescalings, accounting syncs, and migration helpers.
- Add a narrow liveness-preserving emergency lane that can pause rebases or reserve-side supply mutation without waiting for the full GovernorAlpha-style queue-and-delay path.
- Ensure an admitted emergency repair cannot become cancelable or non-viable merely because the bug being fixed later explodes the denominator used for threshold and proposer checks.
- Rehearse
bug discovered before next scheduled transitionscenarios until responders can name the exact authority that halts the next rebase, epoch roll, or accounting sweep. - Treat threshold telemetry as incident telemetry: alert on implausible jumps in quorum, proposal threshold, or delegated voting power requirements before defenders discover the problem through a failed rescue.
- Keep treasury recovery and constitutional recovery decoupled enough that the same corrupted accounting object cannot strand reserves and simultaneously arithmetic-away the only legal repair path.
Audit prompts
- Which exact variables determine proposal threshold, quorum, proposer eligibility, and proposal cancelability, and which rebase or reserve paths can still mutate them?
- If the next scheduled rebase or reserve-mint event fires while the protocol is already in a broken state, does governance become more or less able to repair the damage?
- Once an emergency repair is submitted or queued, can later denominator drift cause it to lose proposer qualification, fail quorum, or become cancelable?
- What narrow authority can halt the next liveness-destroying automatic transition without handing operators an open-ended replacement constitution?
- Is timelock delay still buying review safety here, or is it simply guaranteeing the bug another state transition before the patch can land?
- If supply or reserve state jumped by absurd multiples in one block, would operators know which state path caused the change and what fallback threshold semantics apply?
Lessons that should already be standard
- Monetary-policy state and constitutional state are different control surfaces; rebases should not get to redefine who can still govern.
The community coordinated a fixis not a safety story if the protocol’s own timelock guarantees the next fatal transition lands first.- A queued rescue that can be arithmetic-canceled by the same bug it is trying to repair is not a real rescue path.
- Treasury-side asset recovery and governance-side liveness recovery should not depend on the same mutable denominator once that denominator is already suspect.
- Governance thresholds deserve balance-sheet-grade monitoring because they decide whether repair remains possible at all.
- The healthy design question is blunt: if a nearby accounting bug fires right now, what keeps the constitution from becoming mathematically unreachable before the patch executes?
Internal linkages
- Core recurring pattern: mutable-threshold-state-self-bricking.
- Positive-design companion: constitutional-electorate-bounding-and-threshold-independence-discipline — the sharper healthy-side question is what separately bounded constitutional electorate object, threshold freeze semantics, and rescue-proposal durability rules should have kept YAM governable even after rebase accounting broke.
- Adjacent governance-process note: timelock-action-bundle-commitment — not because YAM approved the wrong payload, but because the rescue failed on the more basic question of whether governance’s delayed action path could still land before the fatal next state transition.
- Adjacent backstop / fast-path companion: governance-backstop-scope-and-intervention-latency-discipline — the sharper design question one layer out is what narrower emergency authority should have been able to pause rebases or preserve constitutional liveness before GovernorAlpha became mathematically unreachable.
- Adjacent governance family: governance-capture is mainly a useful contrast: YAM was not captured by hostile voters; it was incapacitated by supply-state corruption that made constitutional thresholds unreachable.
- Adjacent accounting family: reward-index-initialization-failure is another example of how a tiny boundary or scaling mistake can turn an ordinary governance upgrade or accounting path into catastrophic system-wide failure, even though the mechanics differ.
Control surface
-
The leverage sat in the single arithmetic line that recomputed post-rebase supply, in the reserve mint path that later fed corrupted supply back into
initSupply, and in GovernorAlpha’s decision to derive proposal thresholds and quorum directly from that mutable supply base. -
The practical point of no return was not bug discovery. It was the gap between
community noticed the bugandgovernance could execute a fix, combined with a second rebase that mutated the very thresholds governance needed to satisfy. -
Sources:
- https://medium.com/yam-finance/yam-post-rescue-attempt-update-c9c90c05953f
- https://medium.com/yam-finance/save-yam-245598d81cec
- https://peckshield.medium.com/yam-incident-root-cause-analysis-f3fb2213af53
- https://medium.com/certik/2020-08-13-yam-finance-smart-contract-bug-analysis-future-prevention-b4220976ebea
- https://raw.githubusercontent.com/yam-finance/yam-protocol/767e3a4a6918b6fb6100ad6bb356164408f5d82f/contracts/token/YAM.sol
- https://etherscan.io/tx/0x1b98c761592b54498b9fbd41e6e4755cf6e5a1a6f13658d409081532d89d6bf0
-
Last reviewed: 2026-08-01 UTC