Explore how the Exchange tracks and manages user balances with fund locking mechanisms
The Exchange implements a robust in-memory balance management system that tracks available and locked funds for each user across multiple assets. This ensures users cannot spend the same funds twice and maintains consistency during order execution.
Each user’s balances are wrapped in a Mutex to enable safe concurrent access. Multiple threads can read or update different users’ balances simultaneously, while the Mutex prevents race conditions when accessing the same user’s balance.
Buyer’s USDC: available -= total_cost, locked += total_cost
After each fill (in update_user_balance):
Buyer receives SOL: available += fill.quantity
Buyer’s locked USDC is consumed: locked -= fill.price × fill.quantity
Seller receives USDC: available += fill.price × fill.quantity
Seller’s locked SOL is consumed: locked -= fill.quantity
Notice that locked funds decrease (negative amount) and available funds increase (positive amount) during settlement. The helper function handles both increases and decreases through signed arithmetic.
All balance modifications go through a single helper function:
engine.rs
fn update_balance_with_lock( &self, user_id: String, asset: Asset, amount: Decimal, amount_type: AmountType,) -> Result<(), &str> { let balances = &self.balances; let user_balance_mutex = balances.get(&user_id) .ok_or("No matching user found")?; let mut user_balance = user_balance_mutex.lock() .map_err(|_| "Mutex lock failed")?; let balance = user_balance .balance .get_mut(&asset) .ok_or("No balance for asset found")?; match amount_type { AmountType::AVAILABLE => balance.available += amount, AmountType::LOCKED => balance.locked += amount, } Ok(())}
This function:
Acquires the Mutex lock for the user’s balance
Finds the specific asset’s balance
Adds the amount (which can be negative) to either available or locked
Releases the lock automatically when the function returns
Using += with potentially negative values is cleaner than having separate increment/decrement logic. A negative amount decreases the balance, a positive amount increases it.
use rust_decimal::Decimal;use rust_decimal_macros::dec;let price = dec!(150.25);let quantity = dec!(10.5);let total = price * quantity; // Exact: 1577.625
Using Decimal instead of f64 is essential for an exchange. Floating-point arithmetic can introduce rounding errors that would be unacceptable in financial applications.