hey! i finally took a step further and finished my first audit, it was a wild ride for 2 weeks. this article will talk about how i felt during the audit, what i found, what i missed (and most importantly why) and what are the next steps for me.
AlchemixV3 was my first audit https://cantina.xyz/competitions/e68909e6-3491-4a94-a707-ecf0c89cf72a. Live between 1/05 and 15/05
# An overview
here are all of the notes i took during each day (*if some days are not specified i didn't feel like writing anything*)
```markdown
#### 1/05
**spent**: around 3 hours
**what did I do?** read about the protocol and glanced over the code for a bit
**any findings?**
- one interesting thing (possible DoS if token decimals are < USDC_DECIMALS) but it's not used within the contract. Still a bug to fix if it's going to be used.
- a bunch of informational stuff all around the codebase (random natspec from functions that don't exist, natspec mismatches that differ from the actual functionality, missing OZ's Safe functions alternatives...)
- a bug in a test file inside the function ```_randomMinter()``` this could be interesting to explore further
**how do I feel?** pretty good, not really overwhelmed it seems easy but i haven't looked at the main functionality besides reading the theory
**what to do next?** i have no clue. i should keep exploring
#### 2/05
**spent**: around 7 hours
**what did I do?**
- spent most of the time wandering around the contract i don't recall what i really did but I do understand a bit more about the protocol. I should probably read the concept paper again.
- i installed an extension that's going to help me map some notes with visible colors instead of writing comments
**any findings?**
- i think i found the first issue: it's a divide by zero that causes a DoS if ITokenAdapter.price() returns 0 due to oracle failure/misconfiguration. it affects most of the protocol's functions because they all use the faulty function
- more informational stuff and nothing special throughout the contracts
**how do i feel?** a bit overwhelmed but it's getting easier to understand the overall idea of the project and the main file. The maths part is still a bit of an enigma to be honest but I have the study material ready for it
**what to do next?** i guess that i should explore the main functionality that's related to the key areas of focus. for example the withdraw function on ```AlchemixV3.sol``` uses a lot of the new functionality so I should probably battletest it. Also, i could read the insights I got from the first read and check if the miswritten test that has ```_randomMinter()``` caused any bugs because the developers thought everything was right
**insights:** i noticed that most of the things I'm finding are related to bad written code and not really logic errors which are the ones that are important. i should probably get going with that as well but for that I need to understand more of the protocol
#### 3/05
**spent**: around 7 hours
**what did i do?** spent a lot of time testing StakingGraph.sol and the Transmuter.sol
**any findings?** setTransmuted needs a check for 0 otherwise it can break the transmuter completely until something changes it
**how do I feel?** very overwhelmed specially cause a lot of the things I found were out of scope but i‘m still happy that I got something
**what to do next?** keep exploring and reading the previous reports on Alchemix, will eventually find something
#### 4/05 and 5/05
**spent**: around 2 hour combined
**what did I do?** i spent some time solidifying my knowledge about the protocol. I feel like I can find more stuff on Tuesday
**any findings?** setTransmuted needs a check for 0 otherwise it can break the transmuter completely until something changes it
**how do i feel?** very overwhelmed specially cause a lot of the things I found were out of scope but i‘m happy that I got something
**what to do next?** keep exploring and reading the previous reports on Alchemix, will eventually find something
#### 6/05
**spent**: around 4 hours
**what did I do?** explored the burn() function in alchemistV3.sol and everything related to it which led to find a bunch of bugs
**any findings?**
- protocol fees deducted but not transferred to the protocol wallet in AlchemistV3:burn()
- incorrect fee amount transferred to the protocol wallet in AlchemistV3.repay()
**how do i feel?** very good actually I think these findings are valid and they're not just simple logic errors it's actually critical stuff. Still a long way to go now, i think i got a little boost of confidence from these
**what to do next?** keep exploring and reading the previous reports on Alchemix, will eventually find more issues. Tommorrow I'll analyze in depth what these functions are doing
**insights:** that was a good day and I didn't spend a lot of time. I think it was the rest days that led to this. I came a bit refreshed took a look and spotted something i didn't find for a couple of days. but I know there's still more bugs in the contracts let's hope that these are not invalid
#### 7/05, 8/05
**spent**: around 9 hours
**what did I do?** spent the whole morning auditing both days
**any findings?** desynchronization of a variable and missing freeCollateral change in _sync()_
**how do I feel?** i feel tired and slowly starting to be out of ideas but I'm going to continue
**what to do next?** keep exploring and reading the previous reports on Alchemix, will eventually find something more
#### 9/05
**spent**: around 4 hours
**notes**: there's still about 6 days left to the end of the protocol and I honestly have no idea what to check next; until now I've had good progress but I want to find more but it's getting much harder. i know that there're more bugs in here.
#### 11/05
**spent**: around 2 hours
**notes**: started to write a couple of invariant tests.
#### 13/05
**notes**: lumbar flare-up debuffed me. Nothing was done after this point.
```
the approach i took was pretty simple: start from the file with the lowest nSLOC and keep building further - something similar to tincho's methodology. i built this little table and also used a plugin to build a report with all the files and their respective lines of code. i was pretty surprised to find a bunch of issues right on the first 2/3 files, that probably meant that the protocol was full of bugs but i had to investigate further... these files didn't really seem to be used anywhere but i immediately submitted some findings which for my surprise (not really) were consideres to be OOS on the next day. i was a bit mad because i thought i found something cool but it was something really trivial... it couldn't be that easy and it really wasn't after this point.
i found out that we had code walkthroughs! i completely forgot about these so I essentially analyzed what the developers wanted to build and it gave me some nice clues about where to start looking.
honestly, after this point i have no idea what happened. I read code, created some hypothesis and tested it over and over again.
i spent around 40 hours on this contest and i was feeling pretty good until around day 9: i started to get out of ideas so i started writing a couple of invariant tests. this approach doesn't seem too bad and i think i might keep this methodology because after some time of reading code and docs, getting the invariants right is easier.
juggling auditing and learning about zkp is very hard specially because i'm usually more active during the morning and if the morning doesn't go as planned i find myself a bit lost during the rest of the day, unless there's a really clear objective in my mind which usually originates during the morning studies. sometimes i felt too overwhelmed to do anything else during the afternoon because i spent the whole morning looking at code and testing stuff.. when nothing was found i had this intense feeling of wanting to find something which didn't even exist (yet).
another thing to note is: i barely know anything about lending protocol economics in general. i do know the basic economy 101 concepts... i borrow 100 ETH w 110 stETH collateral (110% overcollateralized) whatever, you get the idea; but in general i don't feel comfortable at all with some of these ideas which gets me a bit behind in terms of finding unusual bugs.
i feel an unsustainable madness at myself for not knowing everything about everything. i want to find all the bugs. hence why the next topic (what did I miss?)
# What did I miss?
after the contest ended i started looking at some of the issues that were found by other people and i decided to stick with T1MOH's https://cantina.xyz/u/T1MOH findings. i was honestly amazed! and here is where i understood that i missed some critical parts of the system and my strict knowledge about lending protocols didn't help at all.
https://cantina.xyz/code/e68909e6-3491-4a94-a707-ecf0c89cf72a/findings/1377
**Why did I miss this?** I overlooked this part of the code and completely ignored how bad debt was calculated, each time I glanced this part of the code I never really thought of trying to understand what bad debt ratio was doing I was too focused on an overview of the protocol. Next time I gotta pay attention to ```how bad debt is calculated``` in the system. ``` totalSyntheticsIssued != totalDebt ```
https://cantina.xyz/code/e68909e6-3491-4a94-a707-ecf0c89cf72a/findings/1376
**Why did I miss this?** Again, I overlooked this critical part of the system even after the devs talked about how the Vaults were a recommended area of focus. I need to start looking at the critical parts of the code, input some values in and understand if there's something I can do for my advantage just like I did for some other parts of the code. I completely assumed calculateLiquidation() was right and didn't even bother to check how it worked. This is a beaufitul finding i love it. Next time I should ```pay more attention to the liquidation component``` specially if the protocol is giving it's own funds as a fee. Start imagining absurd scenarios like this one: ```what if I liquidate myself?```. ```getting liquidated must always be worse than avoiding liquidation.```
https://cantina.xyz/code/e68909e6-3491-4a94-a707-ecf0c89cf72a/findings/1363
**Why did I miss this?** I overlooked it again. I think I didn't understand the protocol as well as I thought initially. I think I also spotted this error but I just skipped it because I didn't understand the consequences/or why my fuzzer was reverting. ```Be patient and understand everything thoroughly, it's better to "lose" a couple of hours trying to understand why the fuzzer reverts than to skip it immediately to jump to another conclusion and miss bugs like this```. ```you can deposit tokens and not have any debt in the system until we mint some debt tokens... be careful with this separation (collateral that backs debt and just collateral which isn't backing anything if the user decides to not mint debt tokens```)
```
// Normal scenario:
1. System has: 100 collateral backing 80 debt
2. badDebtRatio = 80/100 = 0.8 < 1 (healthy)
3. Users get full redemption value
// When system becomes stressed:
1. System has: 70 collateral backing 80 debt
2. badDebtRatio = 80/70 = 1.14 > 1 (unhealthy)
3. Redemptions reduced by 14% (haircut)
// EXPLOIT:
1. Attacker deposits 30 collateral (but doesn't mint debt)
2. Now system has: 70+30=100 collateral, still 80 debt
3. badDebtRatio = 80/100 = 0.8 < 1 (appears healthy!)
4. Everyone gets full redemption with no haircut
5. Attacker withdraws their 30 collateral
6. System back to 70 collateral, 80 debt, insolvent
```
https://cantina.xyz/code/e68909e6-3491-4a94-a707-ecf0c89cf72a/findings/1357
**Why did I miss this?** Again, I don't think there was sufficient protocol understanding and/or patterns from previous audits. This was an easy catch if I knew a bit more about lending protocols but I wasn't thinking with that mindset. A couple of audits deep about CDPs I think I could get this one easily that was stupid but we are learning a lot!
```
// Attack loop:
1. Deposit 100 eUSDC collateral
2. Mint 80 alUSDC debt
- totalSyntheticsIssued += 80
3. Swap 80 alUSDC → ~80 eUSDC on market
4. Repay debt with 80 eUSDC
- Debt zeroed
- totalSyntheticsIssued still includes the 80
5. Withdraw collateral
6. Repeat from step 1
// Healthy state:
- Actual debt: 1,000,000 alUSDC
- totalSyntheticsIssued: 1,000,000
- Collateral value: 1,100,000 USD
- badDebtRatio = 1,000,000/1,100,000 = 0.91 (no haircut)
// After exploit:
- Actual debt: 1,000,000 alUSDC
- totalSyntheticsIssued: 10,000,000 (after repeated repay loops)
- Collateral value: 1,100,000 USD
- badDebtRatio = 10,000,000/1,100,000 = 9.09
- Redemption haircut: 90.9%!
```
https://cantina.xyz/code/e68909e6-3491-4a94-a707-ecf0c89cf72a/findings/1355
**Why did I miss this?** One thing to take into consideration in future audits are these constant literal values like adding 1 for example. This should be something to look out for.
https://cantina.xyz/code/e68909e6-3491-4a94-a707-ecf0c89cf72a/findings/1350
**Why did I miss this?** I thought bugs like this were informational since it's admin error. I guess that this one is an exception to the rule because it actually breaks shit i don't know honestly.