Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: high
Invalid

Reentrancy in TokenManager Contract on Tokenmanager.sol:: withdraw()

Summary

https://github.com/Cyfrin/2024-08-tadle/blob/main/src/core/TokenManager.sol

The withdraw function in the TokenManager contract is susceptible to reentrancy attacks, particularly when handling wrapped native tokens. This vulnerability arises due to the sequence of operations involved in transferring and unwrapping tokens, which can potentially be exploited by malicious contracts that can re-enter the withdraw function.

Vulnerability Details

Vulnerable Code

function withdraw(
address _tokenAddress,
TokenBalanceType _tokenBalanceType
) external whenNotPaused {
uint256 claimAbleAmount = userTokenBalanceMap[_msgSender()][
_tokenAddress
][_tokenBalanceType];
if (claimAbleAmount == 0) {
return;
}
address capitalPoolAddr = tadleFactory.relatedContracts(
RelatedContractLibraries.CAPITAL_POOL
);
if (_tokenAddress == wrappedNativeToken) {
// Token is native token
_transfer(
wrappedNativeToken,
capitalPoolAddr,
address(this),
claimAbleAmount,
capitalPoolAddr
);
IWrappedNativeToken(wrappedNativeToken).withdraw(claimAbleAmount);
payable(msg.sender).transfer(claimAbleAmount);
} else {
// Token is ERC20 token
_safe_transfer_from(
_tokenAddress,
capitalPoolAddr,
_msgSender(),
claimAbleAmount
);
}
emit Withdraw(
_msgSender(),
_tokenAddress,
_tokenBalanceType,
claimAbleAmount
);
}

The withdraw function performs the following operations:

  1. For Wrapped Native Tokens:

    • Transfers wrapped native tokens from the capital pool to the TokenManager contract.

    • Unwraps the tokens using IWrappedNativeToken(wrappedNativeToken).withdraw(claimAbleAmount).

    • Transfers the resulting native tokens to the user with payable(msg.sender).transfer(claimAbleAmount).

  2. For ERC20 Tokens:

    • Transfers ERC20 tokens directly to the user using _safe_transfer_from.

Reentrancy Issue:

  • When the function transfers native tokens to msg.sender, if msg.sender is a contract with a fallback or receive function, it can re-enter the withdraw function. This could allow the attacker to withdraw more tokens than they are entitled to before the initial withdrawal completes.

Impact

  • Potential Loss: The attacker could withdraw more than their allowed share, potentially draining the contract of wrapped native tokens.

  • Financial Loss: Excessive withdrawals could lead to significant financial loss for users and the contract owner.

  • Contract Instability: Exploitation could destabilize the contract and impact overall system integrity.

Tools

Manual Review

Recommendations

  1. Implement Reentrancy Guard:

  • Use OpenZeppelin’s ReentrancyGuard to prevent reentrant calls.

Example Implementation.

Implementatio

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract TokenManager is ReentrancyGuard {
// Existing code...
function withdraw(
address _tokenAddress,
TokenBalanceType _tokenBalanceType
) external whenNotPaused nonReentrant {
// Function implementation...
}
}
  1. Review External Contract Interactions:

    • Ensure that interactions with IWrappedNativeToken and other external contracts are secure and handle potential errors properly.

  2. Conduct Comprehensive Testing:

    • Perform thorough testing and security audits to verify that the reentrancy guard is effective and to identify any additional vulnerabilities.

Updates

Lead Judging Commences

0xnevi Lead Judge
about 1 year ago
0xnevi Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

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