Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Valid

Missing Withdrawal Mechanism in RAACNFT Contract - Locked Funds Vulnerability

Summary

The RAACNFT contract allows users to deposit ERC-20 tokens when minting NFTs but lacks a withdrawal function, resulting in permanently locked funds. This issue prevents the contract owner from retrieving deposited tokens, leading to financial loss and operational inefficiency.

Vulnerability Details

Issue: No Withdrawal Mechanism for ERC-20 Tokens

The mint() function transfers ERC-20 tokens from the user to the contract but does not provide any function for the owner to retrieve them. Once deposited, the funds remain locked indefinitely.

Code Location (mint function):

function mint(uint256 _tokenId, uint256 _amount) public override {
uint256 price = raac_hp.tokenToHousePrice(_tokenId);
if(price == 0) { revert RAACNFT__HousePrice(); }
if(price > _amount) { revert RAACNFT__InsufficientFundsMint(); }
// transfer erc20 from user to contract - requires pre-approval from user
token.safeTransferFrom(msg.sender, address(this), _amount);
// mint tokenId to user
_safeMint(msg.sender, _tokenId);
// If user approved more than necessary, refund the difference
if (_amount > price) {
uint256 refundAmount = _amount - price;
token.safeTransfer(msg.sender, refundAmount);
}
emit NFTMinted(msg.sender, _tokenId, price);
}

🔴 Problem: There is no function to allow the contract owner to withdraw the accumulated ERC-20 tokens.

Impact

  • Financial Loss: Tokens inside the contract cannot be accessed, leading to lost funds.

  • Operational Inefficiency: The project cannot reuse or allocate deposited funds effectively.

  • Security Risk: Large, idle balances inside a contract increase the attack surface for potential exploits.

Tools Used

Manuel Review

Recommendations

✅ Fix: Implement a Withdrawal Function

Add a function that allows the owner to safely withdraw ERC-20 tokens from the contract:

function withdraw(address recipient, uint256 amount) external onlyOwner {
require(recipient != address(0), "Invalid recipient");
require(amount > 0, "Amount must be greater than zero");
uint256 contractBalance = token.balanceOf(address(this));
require(amount <= contractBalance, "Insufficient balance");
token.safeTransfer(recipient, amount);
}

Alternatively, provide an option to withdraw all funds:

function withdrawAll(address recipient) external onlyOwner {
require(recipient != address(0), "Invalid recipient");
uint256 contractBalance = token.balanceOf(address(this));
require(contractBalance > 0, "No funds available");
token.safeTransfer(recipient, contractBalance);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

RAACNFT collects payment for NFT minting but lacks withdrawal functionality, permanently locking all tokens in the contract

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

RAACNFT collects payment for NFT minting but lacks withdrawal functionality, permanently locking all tokens in the contract

Support

FAQs

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