Dria

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

BuyerAgent Purchase Function Reverts Entire Batch Instead of Allowing Partial Purchases

BuyerAgent Purchase Function Reverts Entire Batch Instead of Allowing Partial Purchases

Summary

The purchase() function in BuyerAgent reverts the entire transaction if the sum price of the assets in the batch would exceed amountPerRound, even if some assets could have been validly purchased within the limit.

Vulnerability Details

https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/swan/BuyerAgent.sol#L237-L252

The current implementation consist of a for loop of the assets to buy, sum them and compare to the amountPerRound
\
This is inefficient and could lead to missed purchase opportunities:

// Current implementation
for (uint256 i = 0; i < assets.length; i++) {
address asset = assets[i];
uint256 price = swan.getListingPrice(asset);
spendings[round] += price;
@> if (spendings[round] > amountPerRound) {
revert BuyLimitExceeded(spendings[round], amountPerRound);
}
// ... purchase logic
}

Impact

  • Forces multiple transactions where one could suffice

  • Wastes gas on failed transactions

  • Requires additional oracle requests that depends on the input and llm the response may be the same

  • Could cause buyers to miss purchases

  • Makes listers lose potential sales, and also they will have to pay the listing fee (royaltyFee) again if they want to re-list the asset

Recommendation

Modify the purchase function to handle partial purchases:

purchase() external onlyAuthorized {
// ... existing checks ...
uint256 successfulPurchases = 0;
for (uint256 i = 0; i < assets.length; i++) {
address asset = assets[i];
uint256 price = swan.getListingPrice(asset);
// Skip instead of revert if this asset would exceed limit
if (spendings[round] + price > amountPerRound) {
continue;
}
spendings[round] += price;
inventory[round].push(asset);
swan.purchase(asset);
successfulPurchases++;
}
require(successfulPurchases > 0, "No assets purchased");
isOracleRequestProcessed[taskId] = true;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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