Damian Rusinek - Secrets of Uniswap V4: A Deep Dive into Hooks Security

EthereumZuri.ch 2024 · April 2024 · 25:07

Damian Rusinek takes a deep dive into the security of Uniswap v4 hooks, drawing on research supported by a Uniswap Foundation grant. He explains Uniswap v4's architecture and its hooks mechanism, walks through threats specific to the most popular hook use cases with examples, and shares practical strategies and further materials for developing and securing hooks in DeFi.

Speakers

Topics

From EthereumZuri.ch 2024, hosted by EthereumZuri.ch.

Transcript

okay hey thank you for this great introduction I actually didn't know that you're going to read all that uh so hi yeah I'm I'm Daman I'm I simply run composable security company and we have like protected both centralized and decentralized projects for Millions uh now and also we have created the first uh smart contract security uh standard that's on the market and today I'd like to uh talk about Unis swap V4 uh so I'll show you the architecture and also I'll mainly focus on the security threats and try to show you how to protect yourself if if you want to if you consider building a hook so let me start with this equation who

knows this equation raise your hand yeah almost everyone that's that's Unis swab V2 right so the first great project by Unis swap the first big success and it's great because it's simple very simple curve however it is also its downsides so one of them the biggest one is the inefficient liquidity and that that problem was solved by some other projects like for example curve H but Unis swap wanted to do something more like to to have a better approach that is not only for stable coins so they started with uh started working on V3 and the V3 is a bit similar so the curve is the same but the the main thing the

main change that was here was the concentrated liquidity so basically you didn't have to put your liquidity on the whole range but you could specify the price range that you want you put your liquidity in however on the other side of course there is always the other side uh the complexity has risen a lot because of this uh liquidity pool token which was not and fungible anymore like simple erc20 but uh it was nft so made it quite complex to to manage so let's let's look at the architecture of V3 uh you've got this Factory that allows you to deploy New Pools so each pool is actually a separate contract and then uh

you as the uh as the liquidity provider can call some functions directly on the pools but usually you will use the those um contracts that are your helpers helpers so so in this example for a liquidity provider you have that um non-fungible position manager this is contract by Unis swaps that will allow you to add liquidity or remove liquidity so you as the liquidity provider are talking with this contract and this contract calls let's say mint function on the on some specific pool uh contract and then there is a callback uh mechanism here so this Unis swap pool uh makes this callback function to the uh non-fungible position nager uh which

takes care of all the future future flow of this operation and it works similarly for swappers so they also make this uh calls on uh this helper contract which is called swap rter uh which then calls swap on pool uh contract and there is that callback which is called Unis swap V3 swap callback and the swap rter takes care of the rest so you have to use this uh mechanism but due to the concentrated liquidity the those swaps are much more efficient and the and the slippage is much lower however after two and a half or almost 3 years uh when the V3 was

published uh there is still plenty of liquidity into V2 and what's more about 90% of uh pools deployed today are still V2 not V3 right so this doesn't sound like a big success of V3 right so there is V4 coming uh which is uh which is going to solve these issues like the main goals are first gas optimization so you want to make it as as gas optimized as possible have you seen the latest tweet from Hayden who was asking whether it's worth to um remove all events to get

1% uh fee less right so yeah I'm leaving this up to you but the other big change is the customization so V4 is going to be like very new a big amount of possible opportunities for for liquidity providers and and for U builders that will use this and build on top of that and they are also trying to attract LPS to V4 so they started that Grant the that will allow you to like the idea behind the goal of this grant is to make a front end that will make those liquidity providers migrate from V2 to

V4 and there are some changes I'm going to show you uh those on on the architecture on the diagram but the first one is the the train S Storage which is quite um noisy recently right so there was that Denon that introduced this t- store and t- load up codes that are simply very cheap ways of something similar to storage management let's start with this Singleton um architecture like s singon pattern sorry so now in V4 there are no more separated pools each pools are managed in one contract called pool manager so you can like anyone can initialize new pool by calling this

initialized function on the pool manager uh next thing is the pool operator so that that's that's the that's the contract we call it pool operator because it simply operates on the pool manager on behalf of the user and there is no really uh difference between swapper and liquidity Prov provider and I'll show you in a second why so this callback mechanism is still there but it works a little bit different first your pool manager which is like uh your helper contract makes this unlock call to unlock the pool manager and pool manager calls back with unlock callback and from now on the pool operator can make many different calls

on pool manager managing like doing those operations on multiple pools within this one contract within this one pool manager contract and that's what is called flashh accounting right uh and the second well the biggest change are those hooks so hooks are contracts that are called by the pool manager before and after operations being made on the pools so for example as you can see uh there are multiple functions actually you cannot see that much sorry but before initialization um adding liquidity removing liquidity swapping and donating

and also after all those operations the pool manager is able to call the hook contract and you as the initiator of the pool pool will specify what's the hook contract so you control this contract and what's more is that the hook that is called by pool manager can also be the pool operator so basically you as the user can start your flow on the hook the hook will call uh pool manager pool manager will will call hook functions and that's how it goes right so like the the hook now is quite big a contract I mean it it can like uh cover your whole

interaction with with pool managers with simply simply with all pools sorry can we yeah uh no operator is this helper contract so the user is the swapper liquidity provider so we you call this on this pool operator and pool operator operates on the pool manager on your behalf why you okay can we come back to questions after yeah sorry because the time is quite limited so we can talk later uh so how it works how the flow Works basically each pool has those flags and if the flag like for example for after for before swap we have a flag if this flag is set the pool manager

will call this before swap function on the hook if it's not set it will not call it so now let's let's move to the security threats so the the main thing of this presentation so we have identified uh some uh security threats for this uh architecture however I'm going to focus due to the time limit uh on uh a few of them and the first one would be protecting the hook functions so here's an example of a hook it's a full range Hook from created by Unis swap apps if I remember correctly and here you can see the before initial before initialized function this is the

hook that is so this is the function that is called right before the pool manager initializes new pool okay and it's external because the pool manager has to call it on the hook contract so it has to be external right and here is the flow so anyone can call this initialized function on the manager on the pool manager and pool manager will call this function however as you can see there is no any protection on this function so like anyone can call it so what happens if somebody like some kind of attacker calls this function uh directly if you look in this function it

it does well m one main thing uh whenever you initialize a pool it creates a erc20 token that tracks the balances of the liquidity that was added to this pool so when you try to withdraw your liquidity from the pool it simply tries to burn this contract erc2 contract and give you your liquidity give it back to you right however if I call it again this as you can see on the at the bottom it will create a new pool to new pool liquidity pool token a new erc20 and uh that will lead to the over override of this pool token right so now

there is new erc20 and you as the liquidity provider don't have any tokens of this contract because this is a new one so when you try to withdraw your liquidity it will simply revert because you cannot burn tokens that you don't have right so how to protect from that it's quite simple you have to make sure that all hook functions can be called only by the pool manager right very simple solution but we don't need to uh Focus only on the hook functions but we also have to F check the pool operator because this is the unlock callback function right so this is the function from the pool

operator you as the user let's imagine there is a case where you can withdraw as the as the user so you call this withdraw function on the pool operator pool operator prepares some data that is passed to the pool manager in the unlock function and and this data is uh sent back to the pool operator in the unlock callback function so here you can see that the pool operator takes the message sender so you as the user and forwards this to the uh pool manager and pool man manager bounces it back so now pool operator can do all those operations on behalf of the user that was get from the pool manager and so yeah so this is how it works but what happens if you try to

call this unlock callback function directly as some kind of attacker right and you of course will pass some different um parameters uh user would be the victim but withdraw to address would be your address right so this is this is the case where we can like jump in into this uh business flow and do some kind of malicious uh input valid uh input some malicious parameters so how to protect that very similar to the previous one so so you can simply make sure that the call to unlock callback function comes only from the pool manager right the next one seems a bit similar but stay

with me we again have the we we've got some Dynamic Fe hook but it doesn't really matter there is that before initialize function and of course this hook has to know something about the pool that it operates on so it stores the pool key the last uh last um price and the last block number as you can see it's protected there is that pool manager only so we we're safe the the first threat is covered and then this pool this Hook is also your liquidity manager so it's also your pool operator uh so you can like add liquidity or remove liquidity and as you can see it works on this on this

pool identified by the pool key that you just saved in the initialization right so what happens if we try to initialize another pool but with the same hook we will simply uh call this function sorry call this uh this function again but with different pull so different pool key right so from now on this hook thinks that it works on a different pool right so when it tries to uh withdraw uh tokens from this new pool there's no tokens there right this is

new pool so it's again it reverts so it's a simple token lock how to protect from this one simply use mapping so if you want to make a hook that works only with one pool you have to check that like you can uh revert on the initialization if the pool key is already set but if you want to your hook to work with multiple pools and that's probably the the the most typical case keep all those data that is assigned to the pool in the mapping right and then you're fine next one is the Imp impersonation of the center and again we are talking about this

process but let's look first on on some example of a hook this is a hook that has that after swap hook function and as you can see this after swap hook function has a parameter called cender so you would imagine this is the cender that was trying to swap right and uh this particular hook does some checks on the cender so well in this example it was like the center cannot have uh too much uh tokens after the swap so that you cannot have too many right doesn't really matter that's their business case doesn't matter but if you look at this flow you will see that you Des sender is swapping on the pool operator the pool

operator calls pool manager so the the swap function and pool manager gets the sender sets the sets the message sender as the sender parameter right in this after swap hook so in this case you would imagine that you as the hook would imagine that the user is the center but actually the pool operator is the center so they are checking whether the pool operator has uh more than like 30% of tokens in their case so this is wrong so simply their their hook doesn't work correctly but how to how to make it work well um the pool operator can send

some um I sorry uh so pool operator can send some hook data so this is simply a parameter that you can send to the uh pool manager and pool manager will pass it to the hook right okay so let's do it pool operator takes the message sender which is the user H sends it to the pool manager and pool manager passes this passes it to the hook so hook can see who is the real sender but what if uh what if we are calling this um we we are using different pool operator and we we can control this

different pool operators it's code so we can make it set the hook data as the victim right so uh the the pool manager will pass it to the hook and if the hook doesn't verify whether this data comes from The Trusted Source they will simply make all those operations on the on behalf of the victim right so we can make operations on behalf of anyone who uses this uh hook like for example you can make the hook call some uh transfer from function and if it's approved by anyone you can simply steal their token right so this is this is a typical scenario

here uh number five is uh our Dynamic fees this is a new thing that came to V4 and it's quite interesting but also it has some security implications because uh in the P4 swap hook you can update the fee on the pool so actually there is one limitation uh and the limitation is that the fee cannot be more than 100% so what happens when it's 100% well basically whatever you're are trying to swap will be taken from you because that's the fee right so you as the user should watch out for those hooks but there is there is even more because uh

some hooks have real business cases that needs that right so there there might be correct hooks that have 1% uh fee 100% fee but what happens if the fee gets higher than 100% let's say you have some calculations you calculate the fee and there is a there is an edge case where it goes to 100% what happens then it simply reverse so if you cannot reverse it your pull is now dusted right nobody can swap on it because each try on to to do some swap will end with revert because of this too high

fee and last but not least is a quite easy uh so upgradeable hooks so you can imagine what can happen if you have an upgradeable contract like you can change its logic in any way there are some protections but still you can do a lot like if if your hook is also a pool operator you can simply withdraw the money so watch out if you are a builder don't use upgradeability uh if you are user watch out for upgradable hooks for pools with upgradeable hooks so to sum up here are some ideas how you can protect yourself and uh yeah I'm not going to read

because you can you can read that or you can simply take a picture uh and I'll also encourage you to check out our uh serious yeah yeah it will be back in a second okay our serious on our blog about the security of Unis swap hooks so we can check check it out on our blog and U yeah here it is again and if you have like any questions re regarding Unis swab V before Hooks and its security or Security in general of smart contracts or or web tree projects uh you can find me on on Twitter or on telegram that's my handle you can scan it h and yeah and actually that's it from me thank you thank you very much Daman

any questions we can have one question uh very insightful presentation thank you very much uh do you have a special program on bug bounties uh for your version four or any of the for well actually I'm not from Unis swap okay we've been working with Unis swap foundation on the security research but uh it's it's not yet because it's simply not yet published so now they're working on actually I think they they've already Frozen the code and it's going to be uh published within like two or three months I guess because now they have to go through all those rounds of uh audits Etc but well the question is whether there is back Bounty already for V3 to

be honest I'm not sure does anyone know if there is BU bounty on Unis swap yes there is so for sure for sure there will be as well for V before yeah thank you any more questions yeah okay sorry wait s question thank you uh I have I guess a b of a more of a general question about un SW before and sorry can you can you can you say a bit louder and so I have a more of a general question about Unis before and how these uh how the protocol is going to

work with these Cooks because these are additional functionality that the user has to um want to interact with right so is there also like a universal route that can also route through pools and is this possible because you need you need the users um approve it right in a way okay so let me rephrase if I to make sure if I get you your question correctly so you're asking whether the simple user can feel safe using V4 without all those like sophisticated hooks right yes without without knowing if if they're there right so uh now the answer is no but it's it's because it's not life yet

but uh we also did some and it's on our blog some uh research on possible future uh security like measures that they can they can do they can uh Implement and one of them was that um uh let's say a dashboard of pools that Unis swap would like confirm would say that they are safe uh because uh you can simply write uh like a universal hook sorry Universal rotor can be also a hook like it would be a pool operator so it can also be a hook so uh I'm pretty sure that Unis swap will create their own pool operator which is going to be this router and then they can like only

allow you to make operations on selected pools right because in the end it's the pool that you choose that is associated to some hook so uh you don't you don't select the hook you select the pool and it may or may not have some hook with it right so if you have a list of pools that are let's say blessed and uh considered safe then then yeah then you can feel like safe if you trust those who say that it's safe thank you okay thank you thank you I see last question uh but we can talk later okay cuz yeah yeah we can talk

outside thank you