Skip to content

hpn777/toy_transaction_processor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Toy Payments Engine

A CLI program in Rust that processes a CSV stream of transactions and outputs final client account states.

Overview

This implementation processes financial transactions including deposits, withdrawals, and a complete dispute lifecycle (dispute → resolve → chargeback). The system maintains account states with precise decimal arithmetic and enforces business rules around locked accounts and insufficient funds.

Features

  • Transaction Types: Deposits, withdrawals, disputes, resolves, and chargebacks
  • Decimal Precision: Uses rust_decimal for exact fixed-point arithmetic (4 decimal places)
  • Streaming Processing: Processes CSV row-by-row without loading entire file into memory
  • Robust Error Handling: Continues processing on row-level errors, fails fast on fatal errors
  • Account Locking: Accounts become frozen after chargeback
  • Dispute Lifecycle: Only deposits are disputable

Usage

cargo run -- <input.csv> > accounts.csv

Example

cargo run -- sample/transactions.csv > output.csv

Input Format

CSV file with the following columns:

  • type: Transaction type (deposit, withdrawal, dispute, resolve, chargeback)
  • client: Client ID (u16)
  • tx: Transaction ID (u32, globally unique)
  • amount: Decimal amount with up to 4 decimal places (required for deposit/withdrawal only)

Example:

type, client, tx, amount
deposit, 1, 1, 100.0
deposit, 2, 2, 200.0
withdrawal, 1, 3, 50.0
dispute, 1, 1,
resolve, 1, 1,

Output Format

CSV with the following columns:

  • client: Client ID
  • available: Available funds (4 decimal places)
  • held: Held funds due to disputes (4 decimal places)
  • total: Total funds (available + held, 4 decimal places)
  • locked: Boolean indicating if account is frozen

Example:

client,available,held,total,locked
1,50.0000,0.0000,50.0000,false
2,200.0000,0.0000,200.0000,false

Transaction Semantics

Deposit

  • Adds funds to the client's available balance
  • Records transaction for future disputes
  • Duplicate transaction IDs are ignored (first-write-wins)

Withdrawal

  • Deducts funds from available balance
  • Fails silently if insufficient funds
  • Not disputable

Dispute

  • Only applies to deposits
  • Moves funds from available to held
  • Total balance remains unchanged
  • Must be from the same client who made the deposit

Resolve

  • Releases disputed funds back to available
  • Can only resolve transactions in disputed state
  • Total balance remains unchanged

Chargeback

  • Finalizes dispute by removing funds from held and total
  • Locks the account permanently
  • All subsequent transactions for locked accounts are ignored

Key Design Decisions

1. Only Deposits Are Disputable

The specification explicitly states that only deposits can be disputed. This makes sense from a business logic perspective: disputes reverse incoming funds, not outgoing withdrawals.

2. Decimal Arithmetic

Uses rust_decimal crate to avoid floating-point precision issues. All monetary values are exact.

3. Error Handling

  • Fatal errors (exit non-zero): Cannot open file, missing CSV headers
  • Row-level errors (logged to stderr, continue): Invalid transaction types, missing amounts, parsing failures, business rule violations
  • Errors are logged with row numbers for debugging

4. Account Invariants

  • total = available + held at all times
  • No negative balances
  • Once locked = true, all transactions are rejected

5. Transaction Ordering

Assumes chronological ordering in input file (later rows occur after earlier rows).

6. Memory Efficiency

  • Streaming CSV processing (O(1) memory per row)
  • In-memory storage: O(C) for clients, O(D) for deposit transactions
  • Transaction IDs are stored in HashMap (not array-indexed)

Testing

Run unit tests:

cargo test

Tests cover:

  1. Basic deposits and withdrawals
  2. Insufficient funds handling
  3. Dispute → resolve lifecycle
  4. Dispute → chargeback → account locking
  5. Cross-client dispute attempts (should fail)
  6. Whitespace and decimal formatting
  7. Duplicate transaction IDs
  8. Precision with 4 decimal places
  9. Invalid transaction types

Building

cargo build --release

The optimized binary will be at target/release/toy_payments_engine.

Project Structure

.
├── Cargo.toml          # Dependencies and project metadata
├── src/
│   ├── main.rs         # CLI: argument parsing, CSV I/O
│   └── lib.rs          # Engine core: business logic, testable
├── tests/
│   └── basic.rs        # Integration tests
├── sample/
│   └── transactions.csv # Sample input file
└── README.md           # This file

Error Scenarios

The program handles various error conditions gracefully:

  • Unknown transaction type: Row skipped, logged to stderr
  • Missing amount: For deposit/withdrawal, row skipped
  • Invalid amount: Negative or non-parsable, row skipped
  • Too many decimal places: More than 4, row skipped
  • Insufficient funds: Withdrawal fails silently
  • Duplicate transaction ID: Second occurrence ignored
  • Invalid dispute: Wrong client, wrong state, or non-existent tx ignored
  • Locked account: All transactions rejected

Assumptions

  1. Transaction IDs are globally unique across all clients
  2. Input file is in chronological order
  3. Only deposits are disputable
  4. After chargeback, accounts remain permanently locked
  5. CSV parsing is flexible (whitespace tolerance)
  6. Output can be in any client order (implementation sorts by client ID)

Future Enhancements

Possible extensions not implemented:

  • Multiple currencies/assets per client
  • Concurrent processing with per-client partitioning
  • Persistent transaction journal for replay
  • Rich metrics and telemetry
  • Configurable rounding strategies

License

This is a toy implementation for demonstration purposes.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages