A Rust-based financial transactions processing engine that handles deposits, withdrawals, disputes, resolutions, and chargebacks with precise decimal arithmetic.
- Transaction Types: deposit, withdrawal, dispute, resolve, chargeback
- Account Management: Tracks available, held, total balances and locked status
- Precise Arithmetic: Uses
rust_decimal
for exact financial calculations (4 decimal places) - CSV Input/Output: Reads transactions from a CSV file, outputs account balances to
stdout
in a CSV format - Error Handling: Fails completely on invalid CSV file, ignores invalid transactions
cargo run -- <input.csv>
The input CSV must have the following columns:
type
: Transaction type (deposit, withdrawal, dispute, resolve, chargeback)client
: Client ID (u16)tx
: Transaction ID (u32)amount
: Transaction amount (only for deposit/withdrawal)
Example:
type,client,tx,amount
deposit,1,1,1.0
deposit,2,2,2.0
deposit,1,3,2.0
withdrawal,1,4,1.5
Outputs account balances with columns:
client
: Client IDavailable
: Available balanceheld
: Held balance (disputed funds)total
: Total balance (available + held)locked
: Account locked status
Example:
client,available,held,total,locked
1,1.5,0,1.5,false
2,2,0,2,false
- Increase available and total balance
- Must have positive amount
- Cannot process if account is locked
- Decrease available and total balance
- Must have sufficient available funds
- Must have positive amount
- Cannot process if account is locked
- Move funds from available to held
- Can only dispute deposit transactions
- Client must match original transaction
- Cannot dispute already disputed transactions
- Cannot process if account is locked
- Move funds from held back to available
- Can only resolve disputed transactions
- Client must match original transaction
- Cannot process if account is locked
- Remove disputed funds from total balance
- Lock the account permanently
- Can only chargeback disputed transactions
- Client must match original transaction
cargo build
cargo test
serde
: Serialization/deserializationcsv
: CSV file processingrust_decimal
: Precise decimal arithmetic for financial calculations
Run with the provided test file:
cargo run -- example.csv
You can generate a file with random transactions using the generate_rand_tx.sh
script:
./generate_rand_tx.sh 50 > random.csv
cargo run -- random.csv
The engine fails completely on an invalid CSV file or if a transaction row doesn't have the required information, such as:
- Invalid transaction types
- Missing amounts for deposits/withdrawals
- Amounts provided for dispute-related transactions
- Negative amounts
The engine will ignore correctly formed transactions that are invalid, such as:
- Insufficient funds for withdrawals
- Duplicate transaction IDs (for deposits/withdrawals)
- Operations on locked accounts (except chargebacks)
- Invalid dispute operations (wrong client, non-existent transactions, etc.)
If a dispute is made when the amount available is not enough to cover for the original transaction amount, then we put on hold the maximum available amount possible.
When resolving that transaction, the amount previously held will be credited back to the account (not the original transaction amount).
When charging back that transaction, the amount previously held will be debited from the account. Even if at that point the available amount (or held amount) is enough to cover the original transaction amount, we still only debit the amount that was put on hold at the time of the dispute of the transaction.
See tests/data/dispute_after_withdrawal.csv
for an example of such a case.
main.rs
: CLI entry pointlib.rs
: Library interface that will call the enginetransaction.rs
: Transaction typeaccount.rs
: Account management and balance operationsengine.rs
: Main transaction processing engineengine_error.rs
: Engine error type