Tadle

Tadle
DeFi
30,000 USDC
View results
Submission Details
Severity: high
Valid

Users will be unable to withdraw deposited tokens due to inconsistent balance tracking (`TokenManager::tillIn` and `TokenManager::withdraw`)

Summary

Vulnerability Detail

The TokenManager contract implements two crucial functions: tillIn() for depositing tokens and withdraw() for withdrawing tokens. These functions are designed to manage user balances and facilitate token transfers between users and a capital pool. However, there is a critical logical inconsistency in how these functions interact with the user's balance tracking.

The tillIn() function is responsible for accepting token deposits from users:

function tillIn(
address _accountAddress,
address _tokenAddress,
uint256 _amount,
bool _isPointToken
) external payable {
// ... input validation ...
if (_tokenAddress == wrappedNativeToken) {
// ... handle ETH deposit ...
} else {
_transfer(
_tokenAddress,
_accountAddress,
capitalPoolAddr,
_amount,
capitalPoolAddr
);
}
emit TillIn(_accountAddress, _tokenAddress, _amount, _isPointToken);
}

The withdraw() function allows users to withdraw their tokens:

function withdraw(
address _tokenAddress,
TokenBalanceType _tokenBalanceType
) external whenNotPaused {
uint256 claimAbleAmount = userTokenBalanceMap[_msgSender()][
_tokenAddress
][_tokenBalanceType];
if (claimAbleAmount == 0) {
return;
}
// ... perform withdrawal ...
}

The critical issue lies in the fact that tillIn() does not update the userTokenBalanceMap, which is the data structure that withdraw() relies on to determine a user's withdrawable balance. This creates a situation where users can deposit tokens, but these deposits are not reflected in their withdrawable balance, effectively locking their funds in the contract.

Impact

  • Users who deposit tokens using tillIn() will be unable to withdraw their funds using withdraw(), as their balance in userTokenBalanceMap remains unchanged.

  • The contract will accumulate user deposits without providing a mechanism for users to retrieve their funds, potentially leading to significant financial losses for users.

The severity of this issue is critical, as it directly impacts the ability of users to access their funds and compromises the fundamental operations of the contract.

Proof of Concept

  1. Alice deposits 100 tokens using the tillIn() function.

  2. The tokens are successfully transferred to the capital pool, and the TillIn event is emitted.

  3. Alice checks her balance in the contract by calling userTokenBalanceMap[alice][tokenAddress][TokenBalanceType.Available], which returns 0.

  4. Alice attempts to withdraw her 100 tokens using the withdraw() function.

  5. The withdrawal fails because claimAbleAmount is 0, as userTokenBalanceMap was never updated during the deposit.

  6. Alice's 100 tokens are now locked in the contract with no mechanism to withdraw them.

Tools Used

Manual review

Recommended Mitigation Steps

To resolve this critical issue, the tillIn() function should be updated to properly track user balances in the userTokenBalanceMap. Here's the recommended fix:

function tillIn(
address _accountAddress,
address _tokenAddress,
uint256 _amount,
bool _isPointToken
) external payable {
// ... existing validation and transfer logic ...
+ // Update user's balance in the contract
+ userTokenBalanceMap[_accountAddress][_tokenAddress][TokenBalanceType.Available] += _amount;
emit TillIn(_accountAddress, _tokenAddress, _amount, _isPointToken);
}

This change ensures that when a user deposits tokens, their balance in userTokenBalanceMap is updated accordingly. This will allow the withdraw() function to correctly determine the user's withdrawable balance, enabling users to access their deposited funds.

Updates

Lead Judging Commences

0xnevi Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-TokenManager-withdraw-userTokenBalanceMap-not-reset

Valid critical severity finding, the lack of clearance of the `userTokenBalanceMap` mapping allows complete draining of the CapitalPool contract. Note: This would require the approval issues highlighted in other issues to be fixed first (i.e. wrong approval address within `_transfer` and lack of approvals within `_safe_transfer_from` during ERC20 withdrawals)

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.