When a user calls the withdraw function to retrieve their assets from the Tadle Protocol, if they attempt to withdraw a WrappedToken, the approval process is executed on an incorrect token address, which will always result in a revert.
All the user balances are stored in userTokenBalanceMap
with the tokenAddress
and paymentType
. The balance for wrapped token will also be stored in same way.
For withdraw of these balances (the focus of this report is on wrapped token) the user will call withdraw function.
withdraw function will call transfer function to transfer wrapped token from capital pool to tokenManager contract.
Now lets have look at approve function of CapitalPool contract :
Now lets wrap up complete flow :
Bob calls withdraw function to withdraw weth token.
The withdraw function calls _transfer
function @1>
.
The _transfer
function calls approve function of CapitalPool
@2>
and pass the address of address(this)
which is tokenManger
contract address.
@3>
treats tokenManager
address as ERC20
token address and calls the approve function. At this step the execution will revert because tokenManager
does not have approve function and approval will be failed.
The following coded POC will Illustrate the Bug :
Add following test code to PerMarket.t.sol
file :
Run with command : forge test --mt testTokenManager_Wrong_Approval -vvv
The user will never be able to withdraw the wrapped token. if team fix the issue of CapitalPool::approve
only callable by tokenManager
contract.
Manual review
add following changes to the _transfer
function:
If we consider the correct permissioned implementation for the `approve()` function within `CapitalPool.sol`, this would be a critical severity issue, because the withdrawal of funds will be permanently blocked and must be rescued by the admin via the `Rescuable.sol` contract, given it will always revert [here](https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/CapitalPool.sol#L36-L38) when attempting to call a non-existent function selector `approve` within the TokenManager contract. The argument up in the air is since the approval function `approve` was made permisionless, the `if` block within the internal `_transfer()` function will never be invoked if somebody beforehand calls approval for the TokenManager for the required token, so the transfer will infact not revert when a withdrawal is invoked. I will leave open for escalation discussions, but based on my first point, I believe high severity is appropriate.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.