YAM Incident: Root Cause Analysis
At 08:01 AM UTC, Aug. 13, 2020, the creator of YAM, @brockjelmore, tweeted about the failure of rescuing the $750,000 yCRV tokens locked in the governance contract. Hours before that tweet, people in the Ethereum community advocated of voting to a bug-fix proposal which could have the chance to SAVE YAM!. Here we will elaborate the technical details in this blog post.
This incident was caused by the wrong calculation of
totalSupply in the first rebase. The system was designed to execute bug-fix proposals to solve the problem. Unfortunately, the proposal having enough votes cannot be executed before the second rebase since the ETA of the proposal is set to a time after the second rebase automatically. When the bug-fix proposal is effective after the second rebase, the
initSupply derived from the abnormal
totalSupply makes the proposal a defeated proposal. That’s why nothing could save YAM except a hard-fork.
totalSupply & initSupply
We started the analysis from the two rebase transactions: first rebase and second rebase. As shown in Figure 2, the screenshot generated by http://oko.palkeo.com/, the
totalSupply became extremely large after the first rebase.
In the second rebase, Figure 3 shows that the wrong calculation of
totalSupply propagated to
As described in the medium post,
totalSupply should be divided by
BASE (10^18). That’s the one-line code which creates the abnormal
totalSupply in the first rebase.
Later on, in the second rebase, the caller of
YAMRebaser::rebase() calculates the
mintAmount based on the wrong
afterRebase() is invoked, which eventually mints a huge amount of YAM tokens to the governor contract and messes up
A short summary here:
totalySupply was messed up in the first rebase;
initSupply was messed up in the second rebase.
Why can’t we execute the bug-fix proposal before the second rebase?
totalySupply was soon identified by the devs such that a bug-fix proposal was proposed and queued. Even after the proposal had enough votes, no one could execute it before the second rebase. The reason is that the ETA of each proposal is set as
current timestamp + 12.5 hours by the governer contract when the proposal is queued. Specifically, the
GovernorAlpha::queue() public function allows anyone to put a proposal indexed by
proposalId into the queue for execution. One line before the underlying function,
_queueOrRevert() is invoked, the
eta of that proposal is derived by the current timestamp and the
timelock.delay() which is
12.5 hours. It means the bug-fix proposal is NOT EFFECTIVE BEFORE THE SECOND REBASE.
Why not executing the proposal after the second rebase?
Whenever someone triggers the governor contract for executing a proposal,
GovernorAlpha::execute() checks the state of that proposal with a view function
As you can see in
state() line 330, when
forVotes is less or equal to
againstVotes, the proposal is set as a defeated proposal. This was definitely NOT THE CASE as people in the community contributed enough votes to the bug-fix proposal with the help of the SAVE YAM! campaign. Actually, the
forVotes was under the
quorumVotes() fails the rescue mission.
When the system was designed, the
quorumVotes() should be 4% of the
initSupply as shown in Figure 9. However, as mentioned earlier, the
initSupply is messed up in the second rebase. This makes
quorumVotes() returns a huge number such that it is impossible to have enough
After the second rebase, new proposal cannot be proposed due to the fact that
GovernorAlpha::propose() checks the
proposalThreshold() which returns 1% of the
initSupply — a huge number you cannot reach in this world.
As @bantg pointed out in this tweet, someone actually
cancel() the bug-fix proposal in this transaction 31 mins after the second rebase. Since the public function
GovernorAlpha::cancel() allows anyone to cancel a proposal if the voting power of the
proposer is less than
proposalThreshold(), the keeper successfully canceled the proposal because of the huge
initSupply (after the second rebase).
PeckShield Inc. is an industry leading blockchain security company with the goal of elevating the security, privacy, and usability of current blockchain ecosystem. For any business or media inquiries (including the need for smart contract auditing), please contact us at telegram, twitter, or email.