D2Q
Writeup · · 3 min read

A live read into a frozen tally: an honest negative on DeXe governance

DeXe governance reads live NFT power into a vote tally that is never recomputed at execution, and pays delegator rewards from a snapshot over a total. Two clean theses for an over-claim or a reversible vote. We wrote the exploits. Custody and lock gates close both.

By doom2quake, a human builder collective.

A frozen translucent glass snapshot pane suspended over a live flowing luminous data stream with a locked token behind the glass, on a dark zinc field

Not every serious review ends in a finding. A lot of them end in a passing proof of concept that shows the attack does not work, plus the reason it does not. Those negatives are the deliverable. Here is one with two shots at the same target, both of which looked live and both of which held.

Two theses

The target is DeXe’s on-chain governance, and it presents two clean smells.

First, delegator rewards. In the micropool, each delegator’s reward is their snapshotted power over the delegatee’s total captured at vote time. The numerator is frozen at delegation, the denominator at the delegatee’s vote. If you could steer the sum of delegator claims above the reward pool, you would get a payout shortfall or a reward-token over-mint. That is insolvency.

Second, vote power. A personal vote reads live NFT power into the tally and never recomputes it at execution. So a flash of collateral to pump the NFT’s power right before the vote, then a reclaim right after, would be a cheap, reversible vote that crosses quorum and then unwinds. A marginal reversible vote is a governance takeover primitive.

Both are real behaviors in the code. The question is whether either terminates in a loss.

The refutation

On the rewards, the numerator and the denominator move in lockstep. Every delegate and undelegate updates both the acting delegator’s snapshotted power and the delegatee’s live total in the same event, and the NFT component is a stored snapshot that does not decay or drift between events. The reward index selects each delegator’s power as of the quorum-reached instant, so anyone who delegates after quorum selects index zero and earns nothing, which the project’s own test confirms. We ran four adversarial sequences: undelegate mid-vote, three-delegator churn, same-block multicall churn against the same-block dedup, and a post-quorum full-capital withdrawal where every delegator pulls everything right after the delegatee votes. All four report the sum of claims equal to the reward pool exactly. Solvent. The fourth shows delegators can withdraw all their capital immediately after quorum and still collect full rewards, but that is a design property, rewards accrue to whoever was delegated at the quorum instant, and it produces no shortfall.

On the vote power, the flash reclaim is impossible. To vote with an NFT you must first deposit it into the user keeper, and the keeper becomes its owner, so you can no longer add or remove its collateral: both operations require the caller to own the token, and after deposit the caller does not. On top of that, the vote locks the NFT, and it cannot be withdrawn until the proposal is inactive. The proof of concept hits both gates and both revert.

The lesson

“Reads live state into a frozen tally” is a genuine smell, and it was true here. It only becomes a bug if the actor can still move the underlying state after the read is taken. The custody transfer into the keeper and the vote lock closed that window, and the only honest way to know was to attempt the add, the remove, and the withdrawal in the attacking sequence and watch each one revert.

Two theses, aimed straight at insolvency and a governance takeover, both defeated by gates you only see when you try to walk through them. We filed nothing, and we kept the exploit tests.

← All posts Browse the hackathon knowledge graph →