-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support faking balances for more tokens (#3238)
# Description To verify more quotes we introduced some logic to figure out which storage slots need to be overwritten to fake a token balance for a given owner. That way our quote verification simulation will not revert when a user currently doesn't hold the necessary amounts of token which improves UX a lot. While looking into some quote we couldn't verify ([simulation](https://dashboard.tenderly.co/cow-protocol/production/simulator/e3456eaf-90e6-4212-9758-deef4b80948f?trace=0.3.0.3.0.0.0.5.0.0.1.0.0.0.0)) it became apparent that our current strategy to detect which storage slot needs to get overwritten doesn't work for some tokens. The current logic assumes a "normal" contract where member variables are laid out using the default solidity logic. This is not sufficient to detect proxy contracts which store their state at a hardcoded address since we can't predict where the author decided to put their member variables in their custom memory layout. However, most of the time people use libraries to handle that logic for them. These libraries hardcode the necessary information to find the member variable storing the balances in the token so we can just add support by probing for these known hardcoded values too. Kudos to @fedgiac for helping me debug the problem with the original proxy contract. # Changes This PR adds support for 2 libraries: OpenZeppelin and Solady. The OpenZeppeline implementation simply puts the `balances` member variable at a hardcoded position so we can use the existing encoding logic with the hardcoded address we found the in their source code. Solady is a bit different since it doesn't hash 64 bytes but instead only hashes 48 bytes to compute the storage slot of an addresses balance. For this I introduced another enum variant. This PR also fixes a bug with the original implementation. The original implementation works by calling `token.balanceOf(address)` with 25 storage slots. Each slot gets overwritten with a specific value. When `balanceOf()` returns that value we recover which storage slot we originally overwrote. This idea makes a lot of sense but had a problem with the very first override. The amount we override was computed with `U256::from(u64::from_be_bytes([i; 8]))` where `i` is an index variable. That means the first override always tried to set the balance to `0`. If you call `token.balanceOf(random_address)` it will return 0 because the address doesn't have any balances. The original logic interpreted this `0` as the sentinel `0` value it originally overwrote and therefore returned that the `balances` mapping lives in the `0th` storage slot. To fix that we now compute the sentinel values with `U256::from(u64::from_be_bytes([i + 1; 8]))` to ensure that we always search for non-zero values to detect the correct storage override. Note that this error only surfaced when none of the storage slots we tried to override was the correct one. If we were able to override the storage slot `balanceOf()` would no longer return `0` to cause the false positive. ## How to test added an ignored unit test detecting 1 storage slot of each variant: 1. standard solidity mapping + standard solidity layout 2. standard solidity mapping + hardcoded OpenZeppelin storage slot 3. custom Solady mapping Also there was already 1 e2e test that already tested the original logic.
- Loading branch information
1 parent
50f7c9a
commit 395d605
Showing
2 changed files
with
206 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters