Standalone

Unsafe Math

close button

Unsafe Math

Download quests in Questplay

View the contracts and any other additional content from your IDE.

BadMarket sells incense, but at a cruelly expensive price. Sure, you can claim free coins, but they will never be enough for you to buy enough incense.

However, it seems like there is a loophole in the contract for you to abuse...

Your Task

Buy at least 1000000000000000 incense. (i.e., set incense_sold to at least 1000000000000000).

Contract Code

#[starknet::interface] trait IBadMarket<TContractState> { fn incense_sold(self: @TContractState) -> felt252; fn coin_balance(self: @TContractState, owner: starknet::ContractAddress) -> felt252; fn claim_coin(ref self: TContractState); fn buy_incense(ref self: TContractState, amount: felt252); } #[starknet::contract] mod BadMarket { use starknet::{ ContractAddress, get_caller_address }; const COST_OF_INCENSE: felt252 = 0x1777; #[storage] struct Storage { coin_balances: LegacyMap<ContractAddress, felt252>, incense_sold: felt252 } #[abi(embed_v0)] impl BadMarketImpl of super::IBadMarket<ContractState> { fn incense_sold(self: @ContractState) -> felt252 { self.incense_sold.read() } fn coin_balance(self: @ContractState, owner: ContractAddress) -> felt252 { self.coin_balances.read(owner) } // Claim a free coin! fn claim_coin(ref self: ContractState) { let caller = get_caller_address(); let balance = self.coin_balances.read(caller); self.coin_balances.write(caller, balance + 1); } fn buy_incense(ref self: ContractState, amount: felt252) { let caller = get_caller_address(); let balance = self.coin_balances.read(caller); let total_cost = amount * COST_OF_INCENSE; assert(balance == total_cost, 'BAD_COIN_BALANCE'); self.coin_balances.write(caller, 0); self.incense_sold.write( self.incense_sold.read() + amount ); } } }

Manipulate the loophole in the merchant’s sales to liberate the incense supply…