Summary
The RAACNFT contract accepts ERC20 tokens as payment during the NFT minting process but lacks any withdrawal mechanism. Without a withdrawal function, tokens accumulated in the contract remain locked, preventing the owner or protocol from reclaiming or reallocating these funds.
Vulnerability Details
In the mint function, the contract transfers ERC20 tokens from the user to itself:
```solidity
token.safeTransferFrom(msg.sender, address(this), _amount);
```
However, there is no function provided to withdraw or transfer these tokens out of the contract. This omission means that any funds collected via NFT minting or accidentally sent to the contract cannot be retrieved, potentially leading to locked assets.
### Proof of Concept
Consider a scenario where multiple users mint NFTs, causing the contract to accumulate a significant token balance. Without a withdrawal function, even if the owner attempts to manage the collected funds, they remain inaccessible. A simple call to check the token balance would confirm the accumulation, but no function exists to transfer these tokens out.
Impact
Locked Funds: Tokens collected as payment remain permanently trapped within the contract.
Operational Limitations: The protocol owner or administrators lose flexibility to manage, distribute, or reinvest collected funds.
Tools Used
Manual Review
Recommendations
Implement a Withdrawal Function:
Add a function (restricted to the owner) to transfer out the ERC20 tokens held by the contract. For example:
```solidity
function withdrawTokens(uint256 amount) external onlyOwner {
uint256 contractBalance = token.balanceOf(address(this));
require(amount <= contractBalance, "Insufficient balance");
token.safeTransfer(msg.sender, amount);
}
```
Update Documentation:
Clearly document the withdrawal process so that users and administrators understand how collected funds can be reclaimed.
Implement Unit Tests:
Create tests to verify that tokens can be withdrawn correctly and that the function adheres to security best practices.