Core Contracts

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

ZENO Token Redemption Mechanism Broken Due to Missing USDC Reserves

Summary

The ZENO token's redemption mechanism is fundamentally broken due to an flaw in the protocol's USDC handling. During the auction, all USDC payments are sent to a business address instead of being held in escrow by the ZENO contract, resulting in the ZENO contract having no USDC reserves to fulfill redemptions. This makes all ZENO tokens permanently unredeemable, leading to a complete loss of user funds at maturity.

Finding Description

The issue stems from a design flaw in how the protocol handles USDC payments during the ZENO token auction process. In the Auction.sol contract, when users purchase ZENO tokens, their USDC payments are directly transferred to a business address instead of being held in escrow by the ZENO contract. This can be seen in the buy() function:

function buy(uint256 amount) external whenActive {
uint256 price = getPrice();
uint256 cost = price * amount;
require(usdc.transferFrom(msg.sender, businessAddress, cost), "Transfer failed");
zeno.mint(msg.sender, amount);
}

The ZENO contract, which is responsible for token redemption at maturity, implements a redemption mechanism in its redeem() function that attempts to transfer USDC from its own balance to users:

function redeem(uint amount) external nonReentrant {
if (!isRedeemable()) {
revert BondNotRedeemable();
}
if (amount == 0) {
revert ZeroAmount();
}
uint256 totalAmount = balanceOf(msg.sender);
if (amount > totalAmount) {
revert InsufficientBalance();
}
totalZENORedeemed += amount;
_burn(msg.sender, amount);
USDC.safeTransfer(msg.sender, amount);
}

The fundamental problem is that while the ZENO contract is designed to transfer USDC to users during redemption, it never actually receives any USDC to fulfill these redemptions. All USDC from token purchases is sent directly to the businessAddress, leaving the ZENO contract with zero USDC balance. This means that when users attempt to redeem their ZENO tokens after maturity, the USDC.safeTransfer() call will always fail due to insufficient balance, making the tokens permanently unredeemable.

This creates a situation where users can purchase ZENO tokens, but can never redeem them for their underlying USDC value, effectively trapping user funds in the protocol.

Impact

The impact is severe as it renders the entire ZENO token system non-functional. All users who purchase ZENO tokens will be unable to redeem them at maturity, resulting in a 100% loss of invested funds. This affects every single ZENO token holder and completely breaks the core functionality of the protocol.

Proof of Concept

  1. Alice buys 1000 ZENO tokens for 1000 USDC

    • USDC is transferred to businessAddress

    • ZENO contract's USDC balance remains 0

    • Alice receives 1000 ZENO tokens

  2. Maturity date arrives

    • Alice attempts to redeem 1000 ZENO tokens

    • ZENO contract has 0 USDC balance

    • redeem() call reverts due to insufficient USDC balance

    • Alice's funds are permanently locked

Mitigation

The protocol should modify the auction mechanism to ensure USDC payments are held in escrow by the ZENO contract instead of being sent to the business address. This can be achieved by updating the buy() function in Auction.sol

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.