User can withdraw all N free NFT from Locker for 1 token + txes instead of N token just in one tx.
Summary
The Locker stores all NFTs that interact with the protocol. NFTs can enter the locker in the following ways:
The user lists their NFT for sale in Listings / ProtectedListings (these NFTs are locked until the end of the listing). It's worth noting that this method immediately returns 1 Collection Token to the user.
The user exchanges an NFT for 1 Collection Token using the Locker::deposit functions (NFTs that enter the contract this way are available for withdrawal from the Locker using Locker::redeem, which in turn burns 1 Collection Token from the user, returning them an NFT (any free NFT that is on the contract))
Thus, the normal behavior of the protocol assumes the following invariants:
Free NFTs should be in the Locker so that the user can use the redeem function
1 FLOOR PRICE NFT = 1 Collection Token (this is especially clear from the logic of the listing, where the user specifies floorMultiple - how many tokens above the floor they should be paid for their NFT, however, they are guaranteed to receive 1 collection token when sold)
The attack, the essence of which will be described below, allows an attacker to take all free NFTs from the locker for just 1 NFT and a relatively small number of tokens to cover the commission, putting them up for sale. Thus, as a result of this attack, the following will happen.
n - number of free NFTs on the Locker contract
The attacker, using 1 + n * listing_tax collection tokens, can earn n + 1 tokens in one transaction
All free NFTs of the Locker contract will be withdrawn and put up for sale, which means the redeem functionality allowing to quickly exchange their NFT for 1 Collection Token will be unavailable.
Vulnerability Detail
So, let's describe the attack scenario.
Let's say there are n free NFTs currently on the Locker contract.
Let's say the attacker has one NFT and n * listing_tax collection tokens.
Then the attacker only needs to do the following:
List their NFT for sale in Listings by calling CreateListings, paying listing_tax (user NFTs = 0, free NFTs = n)
As mentioned above, CreateListings returns 1 Collection Token to the user in the same transaction
In the same transaction, the user withdraws 1 free NFT from Locker, exchanging it for the token received from CreateListings (user NFTs = 1, free NFTs = n - 1)
Go back to step 1.
At the end, the state will be as follows. (user NFTs on sell = n + 1, free NFTs = 0)
If in
If in the normal behavior of the protocol, 1 free NFT would be exchanged for 1 Collection token which would be burned, then in the case of an attack, this is simply an easy way for the attacker to enrich themselves (tokens that in a normal scenario would simply be burned, reducing totalSupply and driving up the price of tokens, as a result of the attack are simply redistributed to the attacker's wallet from other users). Moreover, this also breaks one of the protocol's functionalities - Locker::redeem
Impact
The possibility of this attack in the Flayer protocol is in many ways similar to the possibility of a Sandwich attack in Uniswap. (It also harms the protocol's economy, moreover, it blocks the functionality of quickly exchanging NFT for 1 token).
However, the Sandwich attack is possible due to the structure of the EVM, while this attack is due to shortcomings in the current economic model/implementation.
Cuddly Ocean Gibbon
High
User can withdraw all N free NFT from Locker for 1 token + txes instead of N token just in one tx.
Summary
The Locker stores all NFTs that interact with the protocol. NFTs can enter the locker in the following ways:
Listings / ProtectedListings
(these NFTs are locked until the end of the listing). It's worth noting that this method immediately returns1 Collection Token
to the user.1 Collection Token
using theLocker::deposit
functions (NFTs that enter the contract this way are available for withdrawal from the Locker usingLocker::redeem
, which in turn burns1 Collection Token
from the user, returning them an NFT (any free NFT that is on the contract))Thus, the normal behavior of the protocol assumes the following invariants:
1 collection token
when sold)The attack, the essence of which will be described below, allows an attacker to take all free NFTs from the locker for just 1 NFT and a relatively small number of tokens to cover the commission, putting them up for sale. Thus, as a result of this attack, the following will happen.
n - number of free NFTs on the
Locker
contractLocker
contract will be withdrawn and put up for sale, which means theredeem
functionality allowing to quickly exchange their NFT for1 Collection Token
will be unavailable.Vulnerability Detail
So, let's describe the attack scenario.
Let's say there are
n
free NFTs currently on theLocker
contract.Let's say the attacker has one NFT and
n * listing_tax collection tokens
.Then the attacker only needs to do the following:
Listings
by callingCreateListings
, payinglisting_tax
(user NFTs = 0, free NFTs = n)CreateListings
returns1 Collection Token
to the user in the same transactionLocker
, exchanging it for the token received fromCreateListings
(user NFTs = 1, free NFTs = n - 1)At the end, the state will be as follows. (user NFTs on sell = n + 1, free NFTs = 0)
If in
If in the normal behavior of the protocol,
1 free NFT
would be exchanged for1 Collection token
which would be burned, then in the case of an attack, this is simply an easy way for the attacker to enrich themselves (tokens that in a normal scenario would simply be burned, reducing totalSupply and driving up the price of tokens, as a result of the attack are simply redistributed to the attacker's wallet from other users). Moreover, this also breaks one of the protocol's functionalities -Locker::redeem
Impact
The possibility of this attack in the Flayer protocol is in many ways similar to the possibility of a Sandwich attack in Uniswap. (It also harms the protocol's economy, moreover, it blocks the functionality of quickly exchanging NFT for 1 token).
However, the Sandwich attack is possible due to the structure of the EVM, while this attack is due to shortcomings in the current economic model/implementation.
Severity: High
Code Snippet
https://github.com/sherlock-audit/2024-08-flayer/blob/main/flayer/src/contracts/Listings.sol#L130
Tool used
Manual Review
Recommendation
Perhaps the simplest way to avoid this problem is to not return 1 token to the user during createListings, but only when the listing is realized.