Summary
If the NFT owner places a bid on the protocol, their amount will be added to the bid values map.
self.bid_values.entry(sender).write(amount);
Because of this, during the withdrawal process, the NFT owner can transfer not only the highest bid but also the all unsuccessful bid amounts from other clients to their account.
Vulnerability Details
According to the protocol description, the NFT owner can transfer the highest bid. However, it is also possible for them to transfer the amounts from other clients' bids.
fn withdraw(ref self: ContractState) {
assert(self.started.read(), 'Auction is not started');
assert(self.ended.read(), 'Auction is not ended');
let caller = get_caller_address()
let sender = get_contract_address()
let erc20_dispatcher = IERC20Dispatcher { contract_address: self.erc20_token.read() };
let amount = self.bid_values.entry(caller).read();
let amount_owner = self.highest_bid.read();
if caller == self.nft_owner.read() {
self.highest_bid.write(0);
self.bid_values.entry(sender).write(0)
erc20_dispatcher.transfer_from(sender, caller, amount_owner.into());
}
if amount > 0 {
let sender = get_contract_address()
erc20_dispatcher.transfer_from(sender, caller, amount.into());
}
self.emit(Withdraw {amount: amount, caller: caller});
}
Impact
The NFT owner can 'steal' funds from other clients.
Tools Used
manula review
Recommendations
Please modify the `withdraw` function:
fn withdraw(ref self: ContractState) {
assert(self.started.read(), 'Auction is not started');
assert(self.ended.read(), 'Auction is not ended');
let caller = get_caller_address();
let sender = get_contract_address();
let erc20_dispatcher = IERC20Dispatcher { contract_address: self.erc20_token.read() };
let amount_owner = self.highest_bid.read();
if caller == self.nft_owner.read() {
self.highest_bid.write(0);
self.bid_values.entry(caller).write(0)
erc20_dispatcher.transfer_from(sender, caller, amount_owner.into());
}
let amount = self.bid_values.entry(caller).read();
if amount > 0 {
let sender = get_contract_address();
self.bid_values.entry(caller).write(0)
erc20_dispatcher.transfer_from(sender, caller, amount.into());
}
self.emit(Withdraw {amount: amount, caller: caller});
}