IOP _ ThunderNFT 34578 - [Smart Contract - Insight] unds Not Locked During Order Placement
Submitted on Fri Aug 16 2024 09:32:39 GMT-0400 (Atlantic Standard Time) by @bugtester for IOP | ThunderNFT
Report ID: #34578
Report type: Smart Contract
Report severity: Insight
Target: https://github.com/ThunderFuel/smart-contracts/tree/main/contracts-v1/thunder_exchange
Impacts:
Permanent freezing of funds
Description
Brief/Intro
in the place_order function of the ThunderExchange contract where user funds are not properly locked during the order placement process. This allows users to place multiple orders using the same funds
The current implementation of the place_order function only checks if the user has enough balance to cover the order but does not lock these funds immediately. This oversight allows users to place multiple buy orders simultaneously with the same pool balance, .
Impact
Place multiple buy orders with insufficient funds. leads funds loss
Proof of concept
Proof of Concept
https://github.com/ThunderFuel/smart-contracts/blob/260c9859e2cd28c188e8f6283469bcf57c9347de/contracts-v1/thunder_exchange/src/main.sw#L84C3-L132C6
User A has a balance of 100 units in payment_asset. User A places a buy order for 100 units of payment_asset. Before the system processes and updates the balance, User A quickly places another buy order for 100 units of payment_asset. Both orders are accepted because the system checks the balance but does not lock the funds during the process. ( or minus balance after place order )
/// Places MakerOrder by calling the strategy contract /// Checks if the order is valid #[storage(read), payable] fn place_order(order_input: MakerOrderInput) { _validate_maker_order_input(order_input);
}
FIX
implement a mechanism to lock user funds during the order placement process. This can be achieved by:
Locking the required funds immediately after validating the order and before any further processing.
#[storage(read, write), payable] fn place_order(order_input: MakerOrderInput) { _validate_maker_order_input(order_input);
}
fn _lock_funds(account: Identity, asset: AssetId, amount: u64) { // Logic to lock the specified amount of funds for the account // This can involve updating a separate storage map to track locked funds }
Last updated