Core Contracts

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

Decimal Mismatch in ZENO and Auction Contracts

01. Relevant GitHub Link

02. Summary

In the current implementation, users who purchase ZENO tokens will incur a loss when redeeming them later.

The ZENO token can be purchased with USDC and redeemed after maturity. However, both the Auction contract and the ZENO contract suffer from decimal mismatches and design flaws, which lead to inaccurate pricing and potential redemption issues.

03. Vulnerability Details

  • Decimal Mismatch in Auction::buy:

The function calculates cost by simply multiplying price (1e6) by amount (1e18), resulting in a significant overcharge for buyers because it applies the price to each 1 wei of ZENO rather than scaling properly.

/**
Bid on the ZENO auction
User will able to buy ZENO tokens in exchange for USDC
*/
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"
);
...
  • Incorrect Redemption Logic in ZENO::redeem:

When redeeming, the contract transfers USDC in a 1:1 ratio to the ZENO amount. If ZENO was bought at a high price due to the decimal mismatch, users will not receive the equivalent value in USDC upon redemption.

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);
}
  • Incorrect Redemption Logic in ZENO::redeem:

Also, ZENO::redeem is transferring USDC for the value of the token being redeemed, i.e. if you buy an amount of ZENO tokens at price, you will only receive USDC for amount when you redeem them later, not amount*price. Also, the capitalization of ZENO tokens and decimal is different, which can be confusing.

Also, since different users purchased ZENO Tokens at different prices, everyone should not transfer USDC just for the value of the ZENO Tokens they are burning.

  • Immediate Redemption Uncertainty:

The documentation implies USDC can be redeemed immediately after maturity, but the ZENO contract itself holds no USDC if the business address retains the tokens. This design can make instant redemption impossible if USDC is not available in the ZENO contract.

Also, the decimal of ZENO Token and USDC Token are different, which can cause problems.

04. Impact

Because of the incorrect price calculation and 1:1 redemption mechanism, buyers may overpay during purchase and under-redeem at maturity, causing direct financial losses for users.

05. Tools Used

Manual Code Review and Foundry

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

ZENO.sol implements fixed 1:1 redemption with USDC regardless of auction purchase price, breaking zero-coupon bond economics and causing user funds to be permanently lost

Decimal precision mismatch between ZENO token (18 decimals) and USDC (6 decimals) not accounted for in redemption, causing calculation errors and incorrect payments

Auction.sol's buy() function multiplies ZENO amount (18 decimals) by price (6 decimals) without normalization, causing users to pay 1 trillion times the intended USDC amount

Support

FAQs

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

Give us feedback!