Two Seats and a Loan Fee: The Governance Arithmetic Behind the X100 Drain

CryptoAlpha
Academy

The cheapest part of the X100 attack was almost certainly the gas.

No reentrancy. No integer overflow. No compromised deployer key, no zero-day in the AMM curve, no oracle dragged off its peg at 03:00 UTC while the on-call engineer slept through the alert. An outside party borrowed voting power with a flash loan, took two governance seats, and then X100's assets left the building. Two seats. One atomic sequence. A lending fee somewhere between five and nine basis points, returned in the same block it was drawn.

I need to be honest about the evidentiary floor here, because honesty about evidence is the only thing separating forensics from fan fiction. The material I am working from contains four information points: a flash loan, two governance seats, a theft at a project called X100, and an editorial decision to place the first two next to the third. There is no transaction hash. No chain identifier. No attacker address. No dollar figure. No seat count for the DAO. No proof that the governance seizure and the asset drain are even the same event rather than two incidents sharing a headline. The body of the source repeats its own title.

So read what follows as mechanism, not indictment. What I can do β€” what I have done since 2018, when I spent four months inside the 0x v2 exchange protocol and walked out with seven GitHub issues and a two-month mainnet delay β€” is price the pattern. The pattern is not new. It is well documented. And it keeps clearing, which is the part that should bother you.

Governance capture is not a novel exploit class. It is a novel accounting error, and the industry keeps re-learning it because the accounting is invisible on a block explorer and absent from most audit reports.

Walk the timeline, because the timeline is short and repetitive. Build Finance, February 2022: an attacker accumulated governance tokens, passed a proposal granting themselves mint authority, and drained the treasury. Roughly half a million dollars, which sounds trivial until you notice the mechanism β€” a protocol handed its own money printer to whoever could win a vote. Beanstalk Farms, April 2022: the attacker flash-borrowed slightly over a billion dollars in stablecoins, deposited into the protocol's Silo to reach roughly two-thirds of voting power, and executed a previously submitted proposal that moved about $182 million out. The loan was repaid inside the same transaction. The attacker's sunk cost β€” swap fees, slippage, gas β€” is commonly estimated under a million dollars. Then Tornado Cash's governance, May 2023, where a proposal dressed as an emergency safeguard quietly assigned its author 1.2 million votes, sufficient to pass anything thereafter. Different codebases, different chains, identical failure.

Three data points, one invariant: the voting power was measured at the wrong moment in time.

That is the whole trick. Flash loans β€” standardized under EIP-3156, though the practice predates the standard β€” are uncollateralized loans that must be borrowed and repaid within a single transaction. They are not a hack. They are a legitimate primitive, genuinely useful for arbitrage, collateral swaps, and liquidations. What they also do is rent capital that has no time dimension. It exists for one transaction and then it is gone, with no memory and no cost beyond a fee.

Two Seats and a Loan Fee: The Governance Arithmetic Behind the X100 Drain

Governance, correctly designed, is nothing but a time dimension. Voting power should be a function of how long you have held, how long you have locked, what your balance was at a block that has already been mined and can never be rewritten. The entire security model of on-chain governance rests on the assumption that influence is expensive to acquire and slow to move.

Put rented capital against time-weighted influence and the collision is arithmetic, not mysterious. If the snapshot function reads balanceOf(msg.sender) at execution, an attacker can borrow, vote, and repay atomically. If it reads a historical block β€” getPastVotes(account, proposalBlock - 1) in the ERC20Votes pattern β€” the attacker's capital is invisible, because at that block it did not exist. The difference between those two implementations is the difference between a functioning republic and an open treasury.

Here is what most audits miss, and I say this as someone who has written them. A code audit asks whether a function does what its specification says. A well-written contract that measures voting power at execution time passes that test perfectly. It is not buggy. It is faithful. The specification was the vulnerability, and specifications are not usually in scope.

There is a second layer of the problem that the industry has never priced. Governance tokens were sold to the market as two things: a claim on protocol fees, and a claim on direction. Neither of those framings includes a third implicit claim β€” a written put option on the treasury, exercisable by anyone with access to a lending pool. That option has always existed. It was simply never quoted, because quoting it requires admitting that your voting mechanism can be rented for less than the value it controls.

For a flash loan governance attack to work, a specific conjunction must hold. Not a probability β€” a conjunction. Miss any element and the attack fails or becomes unprofitable.

One: voting power is measured at execution time, or at a snapshot that can be influenced within the same transaction. This is non-negotiable. Without it, borrowed capital has no voice. I rate this near-certain in the X100 case β€” not because I have read the code, but because the alternative is that the reported attack did not happen. When a mechanism is the only route to an observed outcome, its presence is inferred rather than assumed.

Two: no effective timelock. A 48-hour delay between a passed proposal and its execution converts a heist into a negotiation, because the community gets a window to notice, publish, and exit, or a guardian multisig gets a window to freeze the queue. A timelock does not prevent capture. It converts capture from an event into a conversation. Short timelocks β€” six hours, twelve β€” are theater. Attackers schedule around theater.

Three: proposal economics too cheap. If submitting a proposal costs nothing and requires no deposit, the fixed cost of an attack collapses toward the variable cost, which is the loan fee. Governance systems that charge a meaningful deposit, slashed on malicious proposals, are not bureaucratic friction. They are a price floor on capture.

Four: governance apathy. This is the input nobody models, because it lives in people rather than contracts. An active delegate base watches the proposal queue. A quorum met by real, independent voters makes it vastly harder for borrowed capital to reach a decisive share. Governance apathy is not a cultural observation. It is a security parameter, and it is almost never disclosed in any document a token buyer reads.

An attack has a cost and a payoff, and the two are indexed to different variables. Cost scales with the liquidity depth of the governance token β€” how much of it you can borrow or buy without moving the price against yourself, plus the loan fee, plus AMM slippage, plus gas. Payoff scales with total value locked and treasury holdings. Those two numbers have no structural reason to be related. In most DeFi protocols they are wildly unrelated.

Which produces a clean inequality. When the cost of acquiring decisive voting power is smaller than the value that voting power can move, the attack is not a crime of opportunity. It is a rational trade, and someone will eventually take it.

Beanstalk is the textbook instance. A billion dollars of borrowed capital against a token whose liquidity could never absorb it, aimed at $182 million of depositor funds. The attacker was not brave. They were doing present-value math on a mispriced option.

Run an illustrative version, clearly labeled as illustrative, because I have no X100 numbers. Suppose a mid-cap protocol holds $40 million in TVL and treasury, and its governance token carries $6 million of two-sided DEX liquidity plus a lending market that will rent it to anyone with collateral. To reach a decisive voting share, an attacker might need to control $10 million of the token for one transaction. Borrowing that against a flash loan, paying five to nine basis points plus slippage, costs well under $200,000 in the best case and maybe $400,000 if the liquidity is thin. Against a $40 million payoff. The ratio does the work. Nobody needs to be brilliant. They need to be able to read a liquidity pool.

Now apply it to X100 with the caveat that I have no figures. If the theft was governance-mediated, then at the moment before the attack, X100's movable assets β€” TVL, treasury, upgradeable contract balances, oracle sourcing authority β€” exceeded the cost of assembling decisive voting power. That inequality is the entire finding. Everything else is detail, and the detail is not available to me.

Notice what the inequality implies about incentive design. A protocol that pays liquidity providers in an inflationary governance token deepens that token's liquidity. Deeper liquidity means cheaper borrowing. Cheaper borrowing means lower attack cost. High yield is a warning, not a welcome β€” and in this architecture, high yield paid in your own governance token actively subsidizes the person who will eventually take your treasury. I wrote a fifteen-page version of that argument in 2020 about leveraged staking and oracle fragility during low-liquidity events. The asset class changes. The asymmetry does not.

The detail I keep returning to is the phrase itself: two governance seats.

Seats imply a bench. A legislature. A committee. Token-weighted governance does not typically speak in seats β€” it speaks in percentages and quorum thresholds and delegated voting power. Seats belong to multisig councils: five-of-nine, three-of-five, a foundation-appointed board with a fixed roster and a known names list.

If X100's governance is council-shaped, the security calculus changes in a way that should terrify every protocol with the same architecture. In a token-weighted system, an attacker must acquire a majority of a float, which is expensive and slow. In a council system, an attacker must acquire enough seats to control the threshold. Those are not the same difficulty. Two seats out of nine, in a five-of-nine multisig, is not twenty-two percent of the power β€” it is potentially one hundred percent of the marginal vote needed to pass anything, depending on which two seats and how the remaining signers behave when a proposal looks routine.

The smaller the seat count, the higher the value density per seat, and the better the attacker's return on capital. A nine-seat council is a concentrated position. Concentrated positions are cheap to corner.

This is where the decentralization narrative does its most expensive work. A council is often described as decentralized because the members are independent and geographically distributed. Independence of people is not the same property as distribution of power. If two signatures move the treasury, the treasury has a two-signature security budget regardless of how many time zones the signers occupy.

When I audited 0x v2's maker fee logic in 2018, the vulnerability I found was an integer overflow β€” a place where the arithmetic of the fee calculation could be driven outside its intended range, with the liquidity pool absorbing the error. Seven issues, two months of delay, a patched mainnet. That was a code defect, findable by reading code carefully, which is why the process worked.

The X100 class of defect is not that. There is no line to point at. The contract behaves exactly as specified. The defect lives in the specification's implicit assumptions about the adversary's capital structure. Code does not lie; people do β€” and the people who wrote this specification almost certainly believed that acquiring voting power required conviction, patience, and capital genuinely at risk. A flash loan provides none of the three.

This is why I have argued for years that economic audits and code audits are different products sold under the same word. A code audit asks whether the contract is internally consistent. An economic audit asks whether the contract's invariants survive an adversary with unlimited, instantaneous, recallable capital. Most protocols buy the first and assume they have purchased the second. The market has not priced the difference, because the difference only appears on the day it appears.

Then there is the legal layer, which is where this class of attack becomes genuinely strange.

The attacker did not break the contract. They used it. In most jurisdictions that makes the criminal characterization non-obvious β€” a defense of "I followed the published rules" is not frivolous, even if the intent was plainly to take assets that were not theirs. Fraud statutes may still apply, because intent to deprive is intent to deprive regardless of which interface you used. But enforcement is close to fictional: funds route through mixers and bridges within hours, project teams are often anonymous or offshore, cross-border assistance runs on a calendar measured in years, and by the time a subpoena lands the trace is cold.

That combination β€” technically compliant, intentionally predatory, practically unenforceable β€” is not a gap in the law. It is a stable equilibrium, and stable equilibria attract capital.

There is one more casualty worth naming. The phrase "sufficiently decentralized" is a legal defense, not just a marketing line. A protocol that argues it is decentralized enough to escape securities classification is arguing that no small group can control it. A protocol that can be captured by two seats in a single transaction has just disproven its own defense, on-chain, in public, with receipts. Technical facts have a way of becoming legal facts, and this one cuts against the project, not the attacker.

There is also the aftermath, which almost nobody models and which is worse than the loss itself. Post-capture, the token collapses, which destroys the value that motivated governance participation in the first place. Delegates leave. Quorum becomes unreachable. And now the protocol must pass a remediation proposal β€” freeze, migrate, reimburse β€” using the very governance mechanism that was just proven compromised. The escape hatch has to be outside that loop or it does not exist. Historically it does not exist, and the protocol settles into what I would call zombie governance: a contract still accepting votes from nobody, over a treasury that is already gone.

Now the part the bulls got right, because a teardown that only tears down is just venting.

The contract worked. If X100's code was audited β€” and I suspect it was, because almost everything is β€” the auditors were not necessarily negligent. They reviewed what they were engaged to review. Functions executed. State transitions were valid. No invariant inside the bytecode was violated. The failure sat one level up, at the interface between the contract and the market for its governance token, and that interface is usually out of scope because it is not code.

Decentralization also worked, in the narrow sense. No admin key overrode the vote. No foundation stepped in to reverse it. The mechanism did exactly what it was designed to permit, and the design permitted theft. That is not a bug in decentralization. That is decentralization carrying an unpriced assumption β€” the assumption that participation is voluntary, and therefore benign.

And here is the contrarian point that will annoy people: the attacker was the most efficient auditor X100 ever retained. They did the work β€” mapped the snapshot logic, measured liquidity depth, timed the proposal queue, sized the position. They were paid for it in full, out of the treasury, and they did not have to write a report. The lesson is not that the attacker was clever. The lesson is that the risk was priced by someone with real capital at stake, and the price came back as: trivially exploitable.

What the market is getting wrong is the scope of the repricing. X100's token is finished; that is a local event and it is already understood by everyone who needs to understand it. The interesting question is what happens to every governance token whose protocol carries a TVL larger than its own liquidity depth. Those tokens were valued as claims on fee streams and voting rights. They should be valued as claims on fee streams, voting rights, and a written put option on the treasury that any sufficiently capitalized party can exercise for the price of a loan fee. That put is currently being given away. It will not be given away forever, and the repricing will not announce itself when it arrives.

If you hold governance tokens, or provide liquidity to a protocol that issues them, ask one question: at what block is my voting power measured?

If the answer is "at the time of the vote," your protocol has sold the treasury to whoever reads the documentation first. If the answer is "a snapshot taken before the proposal was created," you are dealing with a system that has thought about time, which is the only dimension that matters here. If the answer is a shrug, a link to a Discord thread, or a promise that the team is looking into it, treat the position as unsecured lending and size it accordingly.

Audit the promise, not the poster. The poster said decentralized. The promise was that influence costs something. For one transaction, at five basis points, it did not.

Forensics don't care that the code was clean. That is precisely the problem.