Alpha Homora V2 Post Mortem
Dear Alpha community, our partners, and DeFi users, as we have shared earlier, we have closed the loophole that made the exploit possible. We’d like to take this opportunity to thank everyone who has helped us, be it on the technical front and non-technical front. We sincerely appreciate it. We are investigating with the relevant parties and will investigate with the authorities to trace the attacker.
Now, we would like to share a post mortem on the recent Alpha Homora V2 exploit to explain
1. What happened
2. Who is affected
3. What’s next and
4. Walk through of technical analysis of what happened.
This exploit is complicated, involving more than 9 transactions. We hope this thorough post mortem will not only be helpful to the Alpha community and our partners, but also to other projects and builders in DeFi.
This moment shows how important it is to continue helping each other out and building a safer DeFi ecosystem for everyone. Alpha team is committed to building and helping builders in the space to create a stronger and safer DeFi ecosystem.
What happened?
On Feb 13 5:37AM UTC, an attacker exploited Alpha Homora V2 using a series of complex transactions, which involved flashloans.
Here’s what the attacker need to know about the code and the setup in order to execute the attack:
- HomoraBankv2 has an sUSD pool on a contract level in preparation for the upcoming release, which is neither available on the UI nor publicly announced.
- There was no liquidity in sUSD lending pool, so the attacker can fully manipulate and inflate the total debt amount and total debt share.
- There is a rounding miscalculation in borrow function calculation, which only affects when the attacker is the sole borrower.
- resolveReserve function can increase totalDebt without increasing totalDebtShare and the function, intended for collecting revenue to the reserve pool, can indeed be called by anyone.
- HomoraBankv2 accepts any custom spell, as long as the invariant checks out that collateral > borrow (a spell is similar to a strategy in Yearn).
Who is affected?
The debt is not between users and Alpha Homora v2, but between Alpha Homora V2 and Cream V2. This is because Alpha Homora V2 is integrated with Cream V2 (Iron Bank) in a protocol-to-protocol lending way. Thus, the debt is between the two protocols and not the users.
Alpha team will work with Andre and Cream team to find remedial actions to resolve the debt.
Currently, borrowing (new leveraged positions and borrowing more to the existing positions) are now paused. Lenders can still lend. Leveraged yield farmers can still repay their debt, add collateral, and close the positions.
What’s next?
Alpha team will work with Andre and Cream team to find remedial action to resolve the debt.
The team, trusted builders in the space, and security experts will continue to investigate this exploit further, so we will continue to pause borrowing.
We will maintain a constant communication with our community.
Once the recheck and investigation is complete, Alpha Homora V2 and Iron Bank will continue to operate normally with more leveraged pools, more lending assets, more features, and better improvement.
While Alpha Homora V2 has gone through 2 audits by Quantstamp and PeckShield, we will not only work with more audit firms but also work with more trusted builders in the space to help read through the contracts.
This incident has helped us and will continue to help us bond stronger as a community, and we look forward to building a brighter and safer future.
Walk through of technical analysis
- Attacker address: 0x905315602ed9a854e325f692ff82f58799beab57
- Attacker’s txs: https://etherscan.io/txs?a=0x905315602ed9a854e325f692ff82f58799beab57
- Evil spell address:
https://etherscan.io/address/0x560a8e3b79d23b0a525e15c6f3486c6a293ddad2
Exploit Analysis
1.The attacker created an evil spell (can think of this as equivalent to Yearn’s strategy). https://etherscan.io/tx/0x2b419173c1f116e94e43afed15a46e3b3a109e118aba166fcca0ba583f686d23
2. Attacker swaps ETH -> UNI, and supply ETH + UNI to Uniswap pool (obtaining ETH/UNI LP token). In the same tx, swap ETH -> sUSD on Uniswap and deposit sUSD to Cream’s Iron Bank (getting cysUSD)
https://etherscan.io/tx/0x4441eefe434fbef9d9b3acb169e35eb7b3958763b74c5617b39034decd4dd3ad
3. Call execute to HomoraBankV2 using the evil spell (creating position 883), performing:
- Borrow 1000e18 sUSD
- Deposit UNI-WETH LP to WERC20, and use as collateral (to bypass the collateral > borrow check)
- In the process, the attacker has 1000e18 sUSD debt shares (because the attacker is the first borrower)
https://etherscan.io/tx/0xcc57ac77dc3953de7832162ea4cd925970e064ead3f6861ee40076aca8e7e571
4. Call execute to HomoraBankV2 using the evil spell again (to position 883), performing:
- Repay 1000000098548938710983 sUSD (actual debt with interest accrued is 1000000098548938710984 sUSD), resulting in a repay share of 1 less than the total share.
- As a result, the attacker now has 1 minisUSD debt and 1 debt share.
https://etherscan.io/tx/0xf31ee9d9e83db3592601b854fe4f8b872cecd0ea2a3247c475eea8062a20dd41
5. Call resolveReserve on sUSD bank, accruing 19709787742196 debt, while totalShare remains 1.
Current state: totalDebt = 19709787742197, while totalShare = 1
https://etherscan.io/tx/0x98f623af655f1e27e1c04ffe0bc8c9bbdb35d39999913bedfe712d4058c67c0e
6. Call execute to HomoraBankV2 using the evil spell again, performing (repeat 16 times, each time doubling the borrowed amount):
- Borrow 19709787742196 minisUSD and transfer to the attacker (doubling each time, since totalDebt doubles each time the borrow is successful). Each borrow is 1 less than the totalDebt value, causing the corresponding borrow share = 0, so the protocol treats this as no debt borrowing.
At the end of tx, the attacker deposits 19.54 sUSD to Cream’s Iron Bank.
https://etherscan.io/tx/0x2e387620bb31c067efc878346742637d650843210596e770d4e2d601de5409e3
7. Continue the process: call execute to HomoraBankV2 using the evil spell again, performing (repeat 10 times, each time doubling the borrowed amount). At the end of tx, the attacker deposits 1321 sUSD to Cream’s Iron Bank.
https://etherscan.io/tx/0x64de824a7aa339ff41b1487194ca634a9ce35a32c65f4e78eb3893cc183532a4
8.
- Flashloan from aave (borrowing 1,800,000 USDC)
- Swap 1,800,000 USDC to 1,770,757.56254472419047906 sUSD, and deposit to Cream to have enough liquidity for the attacker to borrow using the custom spell
- Continued doubling the sUSD borrow from 1,322.70 sUSD to 677,223.15 sUSD (total of 10 times).
- Swap 1,353,123.59 sUSD to 1,374,960.72 USDC on Curve
- Borrow 426,659.27 USDC from Cream (since the attacker deposited sUSD already in step b.)
https://etherscan.io/tx/0x7eb2436eedd39c8865fcc1e51ae4a245e89765f4c64a13200c623f676b3912f9
9. Repeat step 8, but with ~10M USDC (no USDC borrowing at the end)
https://etherscan.io/tx/0xd7a91172c3fd09acb75a9447189e1178ae70517698f249b84062681f43f0e26e
10. Repeat with 10M USDC (no USDC borrowing at the end)
https://etherscan.io/tx/0xacec6ddb7db4baa66c0fb6289c25a833d93d2d9eb4fbe9a8d8495e5bfa24ba57
11.
- Borrow 13,244.63 WETH + 3.6M USDC + 5.6M USDT + 4.26M DAI
- Supply the stablecoins to Aave (to get aTokens, so USDC & USDT can’t be frozen)
- Supply aDAI, aUSDT, aUSDC to Curve a3Crv pool
https://etherscan.io/tx/0x745ddedf268f60ea4a038991d46b33b7a1d4e5a9ff2767cdba2d3af69f43eb1b
12. Add a3Crv LP token to Curve’s liquidity gauge
https://etherscan.io/tx/0xc60bc6ab561af2a19ebc9e57b44b21774e489bb07f75cb367d69841b372fe896
13. The rest of txs are supplying to Tornade Cash, GitCoin Grants. 1k ETH is sent to each of Cream’s and Alpha’s deployer addresses.
Total Loss
Step 8
- 426,659.27 USDC
Step 11
- 4,263,138.929122643119834654 DAI
- 3,997,921.01617 USDC
- 5,647,242.107646 USDT
- 13,244.630331762545750401 WETH
Approx loss (to attacker): 426,659.27 + 4,263,138.929122643119834654 + 3,997,921.01617 + 5,647,242.107646 + 13,244.630331762545750401 * 1800 = $38,175,295.920111224 (~$38M)
Homora Bank v2 Current Status
- onlyEOA can call `execute` function (this was upgraded prior to the hack)
- Only whitelisted spells can be used
- resolveReserve function can only be called by governor
- Can only borrow & repay 4 tokens (ETH, DAI, USDC, USDT)
Current Status:
- Homora sUSD borrowBalanceStored: 61094028263338943262078587 (~61M)
https://etherscan.io/address/0x4e3a36a633f63aee0ab57b5054ec78867cb3c0b8#readProxyContract - Evil spell holding 609683858105587867 cysUSD (~61M worth of sUSD)
https://etherscan.io/address/0x4e3a36a633f63aee0ab57b5054ec78867cb3c0b8#readProxyContract - Evil spell USDC borrowBalanceStored 4033567496331 (~4M)
- Evil spell DAI borrowBalanceStored 4264342321639551533776128 (~4.26M)
- Evil spell USDT borrowBalanceStored 5649407977291 (~5.65M)
- Evil spell WETH borrowBalanceStored 13250286357580046139857 ( ~13250 WETH)
What’s next?
(Note: this is similar to the above what’s next section, but added here again for those who missed the above section)
Alpha team will work with Andre and Cream team to find remedial action to resolve the debt.
The team, trusted builders in the space, and security experts will continue to investigate this exploit further, so we will continue to pause borrowing.
We will maintain a constant communication with our community.
Once the recheck and investigation is complete, Alpha Homora V2 and Iron Bank will continue to operate normally with more leveraged pools, more lending assets, more features, and better improvement.
While Alpha Homora V2 has gone through 2 audits by Quantstamp and PeckShield, we will not only work with more audit firms but also work with more trusted builders in the space to help read through the contracts.
This incident has helped us and will continue to help us bond stronger as a community, and we look forward to building a brighter and safer future.