Open hats-bug-reporter[bot] opened 8 months ago
All vaults in a pool should be ready before the pool is ready. This is invalid under the common sense clause.
Just like you said:
All vaults in a pool should be ready before the pool is ready.
But the "ready()" function does not check this. It checks just the current vault and reports its boolean result. Hence what you are saying and what the code is doing are in complete contradiction.
If we want to approach it with common sense, what we can expect from our common sense can only be: relying on "ready()" functions return value before using vault. But although this is what common sense tell us, it is not the case. Even if "ready()" function in a vault returns "true", pool can be unsafe to use because of the reasons provided in the issue.
I want to propose the following solution for this:
1- Create a storage variable (boolean) indicating all connected vaults are ready. You can name it "finalized" for example. 2- Create a function that uses a relayer to check other vaults' position (their ready() functions' return). This function will set "finalized" variable to true if all connected vaults and also those vaults' connected vaults (2nd degree connection) are ready. (This can go more far, there might be 3rd degree connections or maybe more). 3- Instead of relying on "ready()" function's return, use "finalized" variable to be sure that vaults are safe to use. 4- Although optional, I also want to strongly suggest creating "isFinalized" modifier and using this modifier in all deposits and swaps.
Regarding 4th point above: If we look at Balancer's implementation we can see that Balancer checks if finalize() called (same as "finishSetup()") in swaps/deposits. So in the 4th point I tried to take inspiration from it to make the protocol even safer because I believe "ready()" is already an inspiration from that. But please don't try to focus on that point in order to invalidate the issue. Of course if you want to continue to use view functions as a check, it is your decision (which I don't think is optimal). But not implementing first 3 steps will make those attack vectors which I mentioned in the main issue easily usable and users won't be safe against them.
Best regards.
We have decided to classify this issue as won’t fix. Our decision is based on the following arguments:
According to these arguments, the issue has been classified as won't fix.
Github username: -- Twitter username: -- Submission hash (on-chain): 0xb400710df222077848b27e5e57f5b13cd189bd8c4debe32dd8e4d54c38515881 Severity: high
Description: Description\ "setupMaster" can call 2 functions: "setConnection()" and "finishSetup()". setConnection() connect vaults to create pools. finishSetup() take away setupMaster role hence no new vaults can be connected to pools. As we can see from ready() function, in order for vault to be assumed safe, setupMaster should call finishSetup():
Why this is so important? Because setupMaster can drain the pool as mentioned by NatSpec. It can create malicious vaults with malicious tokens and connect them to benign vault and steal the funds from users if users use the vault before finishSetup() called.
What I will argue next is that this is not enough.
Attack Scenario
Now let's examine if vault is really ready:
Scenario 1:
Scenario 2:
How to prevent:
ready() function should not return just given vault's setupMaster check. It should also check if connected vaults' setupMaster also called finishSetup() or not.