-
Notifications
You must be signed in to change notification settings - Fork 157
AccessList based token balance override #3346
Description
Background
When a user requests a quote from the API we want to verify all quotes coming from solvers in order to avoid displaying prices that are too good to be true. For the quote verification simulation to work the trader address should have the required sell tokens. To provide a good UX where we show verified prices even if no wallet is connected or only one with insufficient sell token balance we already have some logic to figure out in which storage slot of a token contract the balances get stored. That information gets then used to override these storage slots to give the trader address the necessary fake token balance.
This currently uses a relatively simple but crude mechanism which is not able to detect the correct storage slots for somewhat unusual token implementations.
Details
In addition to our simple mechanism we should also implement a mechanism that utilizes access lists. The idea is relatively simple:
- use
eth_createAccessListfor the callsellToken.balanceOf(trader) - this will return all the storage slots that will get read during the call
- use our current mechanism with all the storage slots from
2to identify which storage slot holds the balances of our target trader
Advantages
That way we should be able to find the correct storage slots for all but very weird and exotic tokens (e.g. balances stored in multiple slots, balances stored in an unusual bit pattern, etc.) without requiring the storage slot to be at a range of previously investigated storage slots.
Downsides
While our current approach is able to find the position of the balances mapping(address => uint256) in the token contract the new approach will only be able to figure out where the balance value for a specific address will get stored.
For reference the storage inside a contract is basically a huge array and at which index (i.e. storage slot) values actually get stored depends on a few things. For a mapping commonly used for balances the storage slot of individual values is computed like this:owner_balance_storage_slot = keccak(mapping_storage_slot || owner_address). So specifically our current solution is able to find mapping_storage_slot which always constant for the same token contract and can be used to compute owner_balance_storage_slot with a given owner_address (for many token implementations).
The new approach is only able to find owner_balance_storage_slot but most likely for the vast majority of all token implementations. This also means that for the new approach we'd have to do 2 extra RPC calls for every token and owner pair.
Since RPC calls are pretty cheap this still seem like a good deal, though.
Acceptance criteria
new approach gets implemented
unit test for overriding balances with the new approach (1 for a token where current approach does not work and 1 for a token where currrent approach is sufficient)
new approach either gets used exclusively since it should be strictly more powerful than the current approach or only when the current approach doesn't work (if the added latencty is too problematic).