Skip to content

Instantly share code, notes, and snippets.

@rossgalloway
Last active July 17, 2022 16:10
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rossgalloway/e7d28830b66ea0fcf9bbd4bb9cd6f46b to your computer and use it in GitHub Desktop.
Save rossgalloway/e7d28830b66ea0fcf9bbd4bb9cd6f46b to your computer and use it in GitHub Desktop.
Summary of events of the governance attack on the YAM Treasury on July 9th, 2022

July 9th 2022 Governance Attack Postmortem

Original Gist published shortly after the attack: https://gist.github.com/ethedev/248f931dbb29d054a9366fe43f37d42e

This document expands upon and cleans up that document to make it easier to follow.

Important Wallets and Actors

Attacker

YAM Governance

Background

The Yam Treasury is controlled directly by the Yam governor contract. Successful votes allow access to the treasury via the timelock contract. The governor contracts reads voting power from both the YAM token address and the Yam incentivizer contract. The governance system is based on the Compound Bravo governor contracts.

Events

July 7th 2022

  1. Attacker wallet A was funded with 200 ETH via tornado cash in 2 transactions [17:54 & 18:42 UTC]. It then proceeded to send 135 ETH to Attacker wallet B in the 3 transactions [18:48 - 20:41 UTC]:

  2. Attacker Wallet B then sold 57 ETH for YAM and deposited 57 ETH and an equal amount of YAM into the Sushiswap pool [19:01 - 20:53 UTC]. It then deposited the returned SLP tokens into the Yam Incentivizer [21:12 - 21:28 UTC].

July 8th 2022

Attacker wallet B traded some ShibDAO tokens. This seems totally unrelated and it seems to be the only transactions that didn't have something to do with YAM across the wallets studied.

July 9th 2022

  1. Attacker wallet A sends 11 ETH and then another 6 ETH to Attacker wallet C. It also sends 1 ETH to Attacker Wallet D [7:41 ` 8:30 UTC].

  2. Attacker Wallet C trades half the 17 ETH for YAM in a 2 trades and deposits the ETH and YAM into the ETH/YAM Sushiswap LP pool [7:46 - 8:49 UTC].

  3. Attacker Wallet D creates the Attacker Contract that is used to interact with the Yam Governor. Its contents are not verified [8:36 UTC].

  4. Attacker Wallet B and Attacker Wallet C send their LP tokens to the Attacker Contract [8:49 & 8:50 UTC].

  5. Attacker Contract Deposits LP tokens into the YAM incentivizer contract [9:06 UTC].

  6. Attacker Wallet D uses the Attacker Contract to create a new governor proposal and votes with 224739 BoU* YAM (equal to ~561,847 YAM) for the proposal. This reached quorum, which is 200,000 BoU YAM. The attacker was able to create the proposal and vote on it without these actions showing up as typical transactions on Etherscan, requiring a user to look at the internal transactions to see what was happening [9:08 and 9:09 UTC].

  7. After voting, the Attacker Contract removes its SLP tokens from the contract and sends them to Attacker Wallet B. [9:15 - 9:21 UTC]

  8. Attacker Wallet B unwinds the SLP tokens and sells the YAM for ~50.7 ETH. [9:22 - 9:28]

  9. Members of the YAM Guardian multi-sig were alerted to some suspicious activity with the YAM governance contracts by members of the Ethereum Security community on the morning of July 9th (EST time). The both that announces governance proposals on discord also recorded the proposal. Because the proposal contained unverified and unknown code, it was deemed potentially malicious and the options to stop the proposal were reviewed. Because the proposer had removed their LP token (see step 7 above) before the conclusion of the vote, it was now possible to cancel the proposal. Proposers must maintain the proposal threshold amount of voting power (50k BoU YAM) throughout the entire voting process. You can see the code for this here: https://github.com/yam-finance/yamV3/blob/0f61c94230bf6c44d4d06188a53c45832f84cae7/contracts/governance/YamGovernorAlpha.sol#L346. The proposal was cancelled at 12:41 UTC in the following transaction:

At this point the governance attack was over. Over the next few hours the attacker proceeded to sell all their YAM for ETH, which they then send to Tornado Cash from Attacker Wallet B.

Conclusion

This attack was successfully thwarted with the help of the Ethereum Security community, the existing YAM infrastructure, quick work from the YAM Guardians, and with help from mistakes by the attacker. The Guardian Multi-sig has still never needed to be used, but it is ready to protect the YAM treasury if needed.

These attacks are an unfortunate consequence of an open, permissionless, and decentralized system and we should continue to be vigilant and consider all the attack vectors that the DAO faces. This is another datapoint that supports the value of a robust on-chain governance system and as we evolve the system in the future we can use these lessons to make sure the DAO treasury remains safe.

Many thanks to everyone who helped fend off this attack.

❤️ 🚀 🍠


footnote: BoU stands for Balance of Underlying and was used in rebasing. It is no longer used, but many functions in the contracts still use this number. The ratio of BoU YAM to normal YAM is very close to 1:2.5.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment