LPDA sale works like a Dutch Auction, where early buyers will get refund after the sale ended.
In addition, in buy() function, when last NFT is saled, it is automatically ending the LPDA sale and send payments to sale receiver, fee to fee receiver. And there are some funds left in the contract for early buyers calling refund() to get back.
However, malicious actor can abuse this by calling buy() with amount = 0 after the sale is ended. Logic in contract is still counted this as last buy and execute ending process. It will use funds reserved for early users to send to sale receiver and fee receiver.
The impact is obviously loss of funds for early buyers.
Function LPDA.buy() did not check amount != 0
function buy(uint256 _amount) external payable {
uint48 amount = uint48(_amount);
Sale memory temp = sale;
IEscher721 nft = IEscher721(temp.edition);
require(block.timestamp >= temp.startTime, "TOO SOON");
uint256 price = getPrice();
require(msg.value >= amount * price, "WRONG PRICE");
amountSold += amount;
uint48 newId = amount + temp.currentId;
require(newId <= temp.finalId, "TOO MANY");
receipts[msg.sender].amount += amount;
receipts[msg.sender].balance += uint80(msg.value);
for (uint256 x = temp.currentId + 1; x <= newId; x++) {
nft.mint(msg.sender, x);
}
sale.currentId = newId;
emit Buy(msg.sender, amount, msg.value, temp);
if (newId == temp.finalId) { // @audit can be called multiple times
sale.finalPrice = uint80(price);
uint256 totalSale = price * amountSold;
uint256 fee = totalSale / 20;
ISaleFactory(factory).feeReceiver().transfer(fee);
temp.saleReceiver.transfer(totalSale - fee);
_end();
}
}
Manual Review
Adding check for amount != 0 in function buy() for all sales contract.
The text was updated successfully, but these errors were encountered:
All reactions