Starknet Auction

First Flight #26
Beginner FriendlyNFT
100 EXP
View results
Submission Details
Severity: high
Valid

earlier bids of highest_bidder are lost

Summary

The auction contract can only store the last bid of any user. If the bidder is not the highest bidder, his earlier bids will be lost but he can get his last bid back but for the highest_bidder he should not get this last bid since it is highest bid but he should be able to get his earlier bids back but he will not be able to withdraw them since there's no record of them. For highest bidder this is special case of bids lost.

Vulnerability Details

Impact

The highest bidder will not be able to withdraw his amount that he bid before highest bid.

Tools Used

#[test]
fn test_multiple_bids_by_highest_bidder() {
let (auction_dispatcher, auction_contract, erc20_contract_address, _) =
deploy_auction_contract();
//The owner calls the start function and the auction begins.
auction_dispatcher.start(86400, 10);
let erc20_dispatcher = IMockERC20TokenDispatcher { contract_address: erc20_contract_address };
//Change the caller address
let first_bidder_address: ContractAddress = 123.try_into().unwrap();
start_cheat_caller_address_global(first_bidder_address);
erc20_dispatcher.mint(first_bidder_address, 60);
erc20_dispatcher.token_approve(auction_contract, 60);
auction_dispatcher.bid(15);
auction_dispatcher.bid(20);
auction_dispatcher.bid(25);
stop_cheat_caller_address_global();
//Check the balance of the auction contract.
let balance_auction_contract = erc20_dispatcher.token_balance_of(auction_contract);
println!("auction contract balance {:?}", balance_auction_contract);
// Check the balance of the first bidder after bidding.
let balance_first_bidder_after = erc20_dispatcher.token_balance_of(first_bidder_address);
println!("first bidder balance after bidding {:?}", balance_first_bidder_after);
let highest_bid = load(auction_contract, selector!("highest_bid"), 1);
println!("Highest bid is {highest_bid:?}");
let highest_bidder = load(auction_contract, selector!("highest_bidder"), 1);
println!("Highest bidder is {highest_bidder:?}");
let values = load(
auction_contract,
map_entry_address(
selector!("bid_values"), array![first_bidder_address.try_into().unwrap()].span(),
),
3,
);
let time = get_block_timestamp();
//Change the blocktimestamp.
start_cheat_block_timestamp(auction_contract, time + 86401);
auction_dispatcher.end();
let owner = get_contract_address();
start_cheat_caller_address_global(auction_contract);
erc20_dispatcher.token_approve(owner, 25);
// erc721_dispatcher.approve(first_bidder_address, 1);
// // erc20_dispatcher.token_approve(first_bidder_address, );
stop_cheat_caller_address_global();
let balance_owner = erc20_dispatcher.token_balance_of(owner);
println!("owner contract balance before owner called withdraw {:?}", balance_owner);
start_cheat_caller_address_global(owner);
auction_dispatcher.withdraw();
stop_cheat_caller_address_global();
let balance_owner = erc20_dispatcher.token_balance_of(owner);
println!("owner contract balance after owner called withdraw {:?}", balance_owner);
let balance_auction_contract = erc20_dispatcher.token_balance_of(auction_contract);
println!("auction contract balance after owner called withdraw {:?}", balance_auction_contract);
stop_cheat_block_timestamp(auction_contract);
println!("bid values by highest bidder {:?}", values);
}
auction contract balance 60
first bidder balance after bidding 0
Highest bid is [25]
Highest bidder is [123]
owner contract balance before owner called withdraw 0
owner contract balance after owner called withdraw 25
auction contract balance after owner called withdraw 35
bid values by highest bidder [25, 0, 0]
[PASS] starknet_auction_integrationtest::test_contract::test_multiple_bids_by_highest_bidder (gas: ~2122)

Recommendations

Instead of using the map to store the last bid, it should hold the sum of the bids and when the bidding ends the highest bid should be substracted from the maped value for highest bidder.

Updates

Lead Judging Commences

bube Lead Judge 9 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Wrong bid amount in `bid` function

In the `bid` function the bid values are stored using `self.bid_values.entry(sender).write(amount)` directly, but this overwrites any previous bids made by the same bidder. Therefore if a participant makes 2 or more bids, the participant can then withdraw only the last value of the last bid. That is incorrect, the protocol should save all bids and a participant should withdraw the value of the all unsuccessful bids.

Support

FAQs

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