Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: high
Invalid

Fund Lockup in `BuyerAgent` upon `Swan.sol` Upgrade with Token Change

Summary

The upgradeable Swan.sol contract, which utilizes the UUPS (Universal Upgradeable Proxy Standard) pattern, introduces a risk of funds becoming locked in BuyerAgent contracts if the token used for transactions in Swan.sol is changed during an upgrade. This vulnerability arises because the withdraw function in BuyerAgent is restricted to a specific token address (the one used by Swan.sol at the time), preventing buyers from accessing their funds if a different token is later set in Swan.sol.

Vulnerability Details

The withdraw function in BuyerAgent allows authorized buyers to withdraw funds only under specific conditions tied to the token initially specified by Swan.sol. This dependency is illustrated as follows:

function withdraw(uint96 _amount) public onlyAuthorized {
(, Phase phase,) = getRoundPhase();
// Restrict full withdrawal to the Withdraw phase only
if (phase != Phase.Withdraw) {
// Ensure a minimum fund amount remains
if (treasury() < minFundAmount() + _amount) {
revert MinFundSubceeded(_amount);
}
}
// Transfer the token to the owner's account
swan.token().transfer(owner(), _amount);
}
function treasury() public view returns (uint256) {
return swan.token().balanceOf(address(this));
}

Since BuyerAgent relies on swan.token() to identify and withdraw the asset, an upgrade in Swan.sol that changes the token address without an update mechanism in BuyerAgent will effectively lock all funds if a withdrawal is attempted after the token change. This issue is further exacerbated if the withdraw phase has not yet been reached for the buyer, as only partial withdrawals are permitted outside of this phase.

Scenario

  1. Multiple BuyerAgent contracts contain funds allocated in the original token specified by Swan.sol.

  2. Swan.sol undergoes an upgrade, changing the token address via swan.token().

  3. Buyers attempting to withdraw funds after this upgrade are restricted to withdrawing only the new token, leaving the original token funds locked in the BuyerAgent contract.

Impact

Buyers who have not reached the full withdrawal phase in BuyerAgent will be unable to access their locked funds if the token changes upon an upgrade. This can lead to significant loss of funds and disrupt the withdrawal process, as there is no mechanism in place to handle a token change.

Tools Used

Manual review

Recommendations

To prevent fund lockups due to token changes in Swan.sol, implement the following fix:

  1. Add a Fallback Withdrawal Function: Introduce an additional withdrawal function in BuyerAgent that allows authorized withdrawals of the initially held token, regardless of the current token address in swan.token(). This fallback function should check if the token address used for the initial deposits differs from the current swan.token() address, and allow withdrawal of the originally deposited token in this case.

Suggested Code Addition

function emergencyWithdrawOldToken(address oldTokenAddress, uint96 _amount) public onlyAuthorized {
require(oldTokenAddress != address(swan.token()), "Use standard withdraw for current token");
IERC20(oldTokenAddress).transfer(owner(), _amount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 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.