Assessment reports>Programmable Derivatives>High findings>Lack of handling of auction failures
Category: Business Logic

Lack of handling of auction failures

High Severity
High Impact
Medium Likelihood

Description

The auction is a process where participants bid coupon tokens to acquire underlying pool assets from a pool. Anyone can start an auction through the startAuction function of the pool. This function ensures there is only one auction per period by checking the mapping auctions.

function startAuction() external {
    // [...]

    // Check if auction for current period has already started
    (uint256 currentPeriod, uint256 _sharesPerToken) = bondToken.globalPool();
    require(auctions[currentPeriod] == address(0), AuctionAlreadyStarted());

    auctions[currentPeriod] = Utils.deploy(
      // [...]
    );
}

An auction may end in three possible states: FAILED_UNDERSOLD, FAILED_LIQUIDATION, or SUCCEEDED. If an auction succeeds, the pool can distribute coupon tokens to bond token holders, and bidders can claim tokens for winning bids. However, if an auction ends in state FAILED_UNDERSOLD or FAILED_LIQUIDATION, there is no code to handle it.

Impact

After the auctions starts, the value of auctions[currentPeriod] will no longer be the zero address. The currentPeriod in the state variable globalPool of the bondToken can only be increased through the function increaseIndexedAssetPeriod, which can only be called by addresses with the DISTRIBUTOR_ROLE. Both the contract Pool and the contract Distributor hold the DISTRIBUTOR_ROLE. But only the pool calls the function increaseIndexedAssetPeriod within its distribute function, and the distribute function can only be called if the auction is successful. As a result, the currentPeriod cannot increment, meaning a new auction cannot start.

function distribute() external whenNotPaused auctionSucceeded {
    // [...]
    // Increase the bond token period
    bondToken.increaseIndexedAssetPeriod(sharesPerToken);
    // [...]
}

Additionally, during the auction, each time a bidder places a bid, coupon tokens are transferred from the bidder to the auction contract. If the auction succeeds, the coupon tokens are sent to the pool, and the underlying assets sent by the pool to the auction contract can be claimed by bidders. However, if the auction fails, bidders' coupon tokens will be locked in the auction contract.

Recommendations

Consider adding code logic to handle auction failure.

Remediation

This issue has been acknowledged by Plaza Finance, and a fix was implemented in commit aa0a7d71.

Zellic © 2025Back to top ↑