Boost _ Folks Finance 34074 - [Smart Contract - Critical] Hub missing check for available liquidity could lead to locked fund and utilization ratio exceeding
Submitted on Mon Aug 05 2024 08:09:42 GMT-0400 (Atlantic Standard Time) by @A2Security for Boost | Folks Finance
Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)
Smart contract unable to operate due to lack of token funds
Permanent freezing of funds
Description
Impact
The Hub doesn't check for available liquidity, leading to borrow/withdraw operation on the hub succeeding eventhough the spokeToken doesn't have enough liquidity. In the case of race conditions, e.g user A borrows 5000 ETH, and Whale B borrows/withdraws remaining liquidity from the ethHubPool. The borrow operation for user A will succeed, but the second part of the operation will revert. => This will lead to:
Utilization ratio surpassing 100% -> interest Rates becomes unbelievable high
User A wouldn't be able to withdraw his borrowed funds (locked) and will be forced to pay really high interest
User A wouldn't be able to reverse the action from spoke, because all operations from Hub -> spoke Chain can't be reversed
The higher the borrow amount, the bigger the chance that the user funds will be stuck (possibly forever, if the liquidity in the spoketoken, never reaches the wanted amount to borrow)
Please note that, such a scenario is highly likeable considering that Folks Finance is cross chain by design, and operations like borrow/withdraw from spoke chains != Avalanche , will require 2 cross-chain actions that requires bridging through wormhole/ccip (which will take considerable time to be executed, and make predicting available liquidity not an easy task for protocol users)
Description
In HubPool.getSendTokenMessage() which is used to build the message to send through the bridgeRouter to the spoke contracts (mostly cross-chains)
As we can see in the message returnAdapterId is set to 0 meaning messages can't be reversed
Recomendation
An easy fix for this is to add a check for available liquidity to each a user actions that removes liquidity from a hubpool
if (pool.depositData.totalAmout < pool.variableData.totalAmount + pool.stableData.totalAmount + amount_to_remove){revert NotEnoughLiquidityAvailable;}
(a side note we know that totaldebt here only includes principal and can in certain condition not be accurate, so we would also recommend adding a margin of safety (e.g 5%))
Proof of concept
Proof Of Concept
Test Result:
Ran 1 test for test/pocs/test_poc.sol:Pocs[PASS] test_poc06() (gas: 1632608)Logs: variable Interest Rate 1 % stable Interest Rate 8 %depositData.totalAmount avax 248 avax total debt hubpool avax 17 avax Alice borrows 258 avax Avax Alice Recieved 0 variable Interest Rate 271 % stable Interest Rate 272 %depositData.totalAmount avax 248 avax total debt hubpool avax 276 avaxSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 684.53ms (9.27ms CPU time)Ran 1 test suite in 687.47ms (684.53ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
To run the test please add test/pocs/base_test.sol