Core Contracts

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

USDC Not Funded to ZENO Contract

Summary

The Auction contract transfers USDC payments from buyers directly to the businessAddress, bypassing the ZENO contract entirely. The ZENO contract is responsible for redeeming tokens, but it does not hold any USDC balance. As a result:

  • The ZENO contract cannot fulfill redemption requests because it lacks the necessary funds.

  • This breaks the core functionality of the bond system, where users are supposed to be able to redeem their ZENO tokens for USDC after the maturity date.

  • Their is no explicit mechanism in place that allows businessAddress to fund the ZENO contract

Vulnerability Details

function buy(uint256 amount) external whenActive {
require(amount <= state.totalRemaining, "Not enough ZENO remaining");
uint256 price = getPrice();
uint256 cost = price * amount;
require(usdc.transferFrom(msg.sender, businessAddress, cost), "Transfer failed");
bidAmounts[msg.sender] += amount;
state.totalRemaining -= amount;
state.lastBidTime = block.timestamp;
state.lastBidder = msg.sender;
zeno.mint(msg.sender, amount);
emit ZENOPurchased(msg.sender, amount, price);
}

The buy function in the Auction contract sends USDC directly to businessAddress instead of depositing it into the ZENO contract.
The ZENO contract has no mechanism to receive or manage USDC, so even if the business manually deposits USDC into the ZENO contract, there is no guarantee that the deposited amount will match the total supply of ZENO tokens.

To ensure the system works as intended, the following invariant should hold:

ZENO.USDC.balanceOf(address(ZENO)) >= ZENO.totalSupply() * 1e12

This invariant ensures that the ZENO contract holds enough USDC to cover all outstanding ZENO tokens (adjusted for decimals).

Violation :
In the current implementation, the invariant fails because the ZENO contract holds zero USDC, while the businessAddress holds all the collected USDC.

Impact

  • Users cannot redeem their ZENO tokens for USDC because the ZENO contract lacks sufficient funds.

  • If businessAddress doesn’t fund ZENO, redemptions fails, leaving users unable to redeem despite burning ZENO

  • The business must manually fund the ZENO contract with USDC, which introduces operational overhead and potential human error.

Tools Used

Recommendations

  1. Redirect USDC to the ZENO Contract

  • Modify the buy function in the Auction contract to transfer USDC to the ZENO contract instead of businessAddress. The ZENO contract can then use these funds for redemptions.

  1. If the business prefers to keep control over the USDC, you can introduce a funding mechanism in the ZENO contract. The business can deposit USDC into the ZENO contract before redemptions begin.

Add a fund function to the ZENO contract:

function fund(uint256 amount) external onlyOwner {
USDC.safeTransferFrom(msg.sender, address(this), amount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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