BBERC721.transferFrom(msg.sender, address(this), tokenId);
@> listings[tokenId] = Listing({
seller: msg.sender,
minPrice: _minPrice,
buyNowPrice: _buyNowPrice,
auctionEnd: 0,
listed: true
});
function test_HIGH_H2_ReentrancyInListNFT() public {
vm.prank(OWNER);
uint256 tokenId = nft.mint(address(attacker));
vm.prank(address(attacker));
nft.approve(address(market), tokenId);
attacker.startAttack(tokenId);
vm.prank(address(attacker));
market.listNFT(tokenId, MIN_PRICE, BUY_NOW_PRICE);
assertGt(attacker.attackCount(), 0, "Reentrancy should have been attempted");
assertTrue(market.getListing(tokenId).listed, "NFT should be listed");
}
function listNFT(uint256 tokenId, uint256 _minPrice, uint256 _buyNowPrice) external {
require(BBERC721.ownerOf(tokenId) == msg.sender, "Not the owner");
require(_minPrice >= S_MIN_NFT_PRICE, "Min price too low");
if (_buyNowPrice > 0) {
require(_minPrice <= _buyNowPrice, "Min price cannot exceed buy now price");
}
+ // EFFECTS: Change state before external interactions
+ listings[tokenId] = Listing({
+ seller: msg.sender,
+ minPrice: _minPrice,
+ buyNowPrice: _buyNowPrice,
+ auctionEnd: 0,
+ listed: true
+ });
- BBERC721.transferFrom(msg.sender, address(this), tokenId);
-
- listings[tokenId] = Listing({
- seller: msg.sender,
- minPrice: _minPrice,
- buyNowPrice: _buyNowPrice,
- auctionEnd: 0,
- listed: true
- });
+ // INTERACTIONS: External calls after state changes
+ BBERC721.transferFrom(msg.sender, address(this), tokenId);
emit NftListed(tokenId, msg.sender, _minPrice, _buyNowPrice);
}