PracHub
QuestionsLearningGuidesInterview Prep

Quick Overview

This question evaluates the ability to design and implement a stateful in-memory banking system, testing skills in data structures, algorithms, API design, transaction semantics, scheduling, and correctness under edge cases within the coding and algorithms domain, and it focuses primarily on practical application with conceptual system-design considerations. It is commonly asked to assess reasoning about state management, invariants, error handling, efficiency (e.g., top-k ranking), time-based scheduled events and cancellation semantics, and preserving operation history during merges, highlighting attention to edge cases and performance trade-offs.

  • medium
  • Coinbase
  • Coding & Algorithms
  • Software Engineer

Design an in-memory banking system

Company: Coinbase

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Take-home Project

Implement an in-memory banking system (e.g., in Java) that supports the following operations on user accounts. Assume user IDs are unique strings and monetary amounts are positive integers. Core requirements: 1) **Account creation and money movement** - `addUser(userId)`: create a new user/account. - `deposit(userId, amount)`: add funds to a user. - `transfer(fromUserId, toUserId, amount)`: move funds between users. - Define and handle error cases (unknown user, insufficient funds, invalid amount, etc.). 2) **Rank accounts by spending** - Provide a method like `getTopSpenders(k)` that returns the top `k` accounts ranked by their **total spending**. - Clearly define “spending” (e.g., total outgoing money via transfers and executed payments), and specify tie-breaking rules (e.g., by userId). - Aim for an efficient approach (a heap/priority queue is acceptable). 3) **Scheduled payments with cancellation** - `schedulePayment(fromUserId, toUserId, amount, executeAtTimestamp)` creates a future payment and returns a `paymentId`. - `cancelPayment(paymentId)` cancels a scheduled payment if it has not executed yet. - Provide a way to advance time / process due payments (e.g., `processPaymentsUpTo(timestamp)`), executing all payments whose execution time is reached. 4) **Merge users while preserving history** - `mergeUsers(sourceUserId, targetUserId)` merges `source` into `target`. - After merging, balances are combined, the source user no longer exists, and **payment/transfer history is preserved** in a sensible way (describe what the history contains and how it is represented after merge). - Define how scheduled payments involving the source user are handled after the merge. You may assume single-threaded execution unless otherwise specified. Design appropriate data structures and APIs, and ensure correctness for edge cases.

Quick Answer: This question evaluates the ability to design and implement a stateful in-memory banking system, testing skills in data structures, algorithms, API design, transaction semantics, scheduling, and correctness under edge cases within the coding and algorithms domain, and it focuses primarily on practical application with conceptual system-design considerations. It is commonly asked to assess reasoning about state management, invariants, error handling, efficiency (e.g., top-k ranking), time-based scheduled events and cancellation semantics, and preserving operation history during merges, highlighting attention to edge cases and performance trade-offs.

Part 1: Account Creation and Money Movement

Implement a small in-memory banking engine. You are given a sequence of operations, each represented as a list of strings. Maintain account balances for unique user IDs. Support creating users, depositing money, transferring money, and querying balances. Amounts must be positive integers. Unknown users, duplicate users, self-transfers, non-positive amounts, and insufficient funds must be handled as errors without changing state.

Constraints

  • 0 <= len(operations) <= 200000
  • 1 <= len(userId) <= 32
  • User IDs contain only letters, digits, and underscores
  • Amounts fit in a signed 64-bit integer
  • All operations are processed sequentially in a single thread

Examples

Input: ([['addUser', 'alice'], ['addUser', 'bob'], ['deposit', 'alice', '100'], ['transfer', 'alice', 'bob', '30'], ['getBalance', 'alice'], ['getBalance', 'bob']],)

Expected Output: ['true', 'true', '100', '70', '70', '30']

Explanation: Alice deposits 100 and transfers 30 to Bob, leaving Alice with 70 and Bob with 30.

Input: ([['addUser', 'alice'], ['addUser', 'alice'], ['deposit', 'charlie', '10'], ['deposit', 'alice', '0'], ['addUser', 'bob'], ['transfer', 'alice', 'bob', '5'], ['deposit', 'alice', '5'], ['transfer', 'alice', 'alice', '1'], ['transfer', 'alice', 'bob', '5'], ['getBalance', 'bob']],)

Expected Output: ['true', 'false', 'error', 'error', 'true', 'error', '5', 'error', '0', '5']

Explanation: Duplicate creation, unknown users, zero deposits, insufficient funds, and self-transfer are rejected.

Hints

  1. A hash map from user ID to current balance is enough for this part.
  2. Validate all preconditions before mutating balances during a transfer.

Part 2: Rank Accounts by Total Spending

Extend the in-memory banking engine with a ranking query. Spending is defined as the total amount successfully sent out of an account through transfers. Deposits do not count as spending, incoming transfers do not count as spending, and failed transfers do not count. The top spenders are ordered by descending spending; ties are broken by lexicographically smaller user ID.

Constraints

  • 0 <= len(operations) <= 200000
  • 0 <= k <= number of users may be requested; if k is larger, return all users
  • Amounts are positive integer strings for valid money-movement operations
  • User IDs contain only letters, digits, and underscores
  • Only successful outgoing transfers increase spending

Examples

Input: ([['addUser', 'alice'], ['addUser', 'bob'], ['addUser', 'carl'], ['deposit', 'alice', '100'], ['deposit', 'bob', '100'], ['transfer', 'alice', 'bob', '40'], ['transfer', 'bob', 'carl', '70'], ['getTopSpenders', '2']],)

Expected Output: ['true', 'true', 'true', '100', '100', '60', '70', 'bob:70,alice:40']

Explanation: Bob spent 70 and Alice spent 40, so Bob ranks first.

Input: ([['addUser', 'bob'], ['addUser', 'ann'], ['addUser', 'zoe'], ['deposit', 'bob', '10'], ['deposit', 'ann', '10'], ['transfer', 'bob', 'zoe', '5'], ['transfer', 'ann', 'zoe', '5'], ['getTopSpenders', '3']],)

Expected Output: ['true', 'true', 'true', '10', '10', '5', '5', 'ann:5,bob:5,zoe:0']

Explanation: Ann and Bob tie at 5, so lexicographic order puts ann before bob.

Hints

  1. Maintain a second map: user ID to total outgoing successful transfer amount.
  2. For each ranking query, sort by (-spending, userId), or use a heap if you only need the first k.

Part 3: Scheduled Payments with Cancellation

Build an in-memory banking system that supports future payments. A scheduled payment transfers money from one user to another at a future timestamp. The system starts at time 0. Calling processPaymentsUpTo(t) advances time to t and processes all pending payments with executeAtTimestamp <= t, in increasing timestamp order and then creation order. If the sender lacks funds when a payment is due, that payment fails permanently and is not retried. Canceled payments are skipped.

Constraints

  • 0 <= len(operations) <= 200000
  • processPaymentsUpTo timestamps must be non-decreasing; a backward timestamp returns 'error'
  • schedulePayment requires executeAtTimestamp to be strictly greater than the current time
  • Amounts must be positive integers
  • Payments execute in order of (executeAtTimestamp, creationOrder)

Examples

Input: ([['addUser', 'a'], ['addUser', 'b'], ['deposit', 'a', '100'], ['schedulePayment', 'a', 'b', '40', '10'], ['processPaymentsUpTo', '5'], ['getBalance', 'a'], ['processPaymentsUpTo', '10'], ['getBalance', 'a'], ['getBalance', 'b']],)

Expected Output: ['true', 'true', '100', 'p1', '', '100', 'p1:executed', '60', '40']

Explanation: The payment is not due at time 5, then executes at time 10.

Input: ([['addUser', 'a'], ['addUser', 'b'], ['deposit', 'a', '50'], ['schedulePayment', 'a', 'b', '25', '5'], ['cancelPayment', 'p1'], ['processPaymentsUpTo', '10'], ['getBalance', 'a'], ['getBalance', 'b'], ['cancelPayment', 'p1']],)

Expected Output: ['true', 'true', '50', 'p1', 'true', '', '50', '0', 'false']

Explanation: Canceled payment p1 is skipped and cannot be canceled again.

Hints

  1. Store scheduled payments in a min-heap ordered by execution timestamp and creation order.
  2. Keep a payment-status map so canceled payments can remain in the heap and be skipped later.

Part 4: Merge Users While Preserving History

Implement an in-memory banking system with user merging. The system supports account creation, deposits, transfers, scheduled payments, cancellation, processing due payments, balance queries, history queries, and merging users. mergeUsers(source, target) moves source's balance into target and deletes source. User IDs that have ever existed cannot be reused. History is preserved by moving source's historical events into target's history. Historical events keep the original user IDs that participated at the time. Future scheduled payments involving source are rewritten to target; if rewriting makes a pending payment a self-payment, it is automatically canceled and will not appear in processPaymentsUpTo results.

Constraints

  • 0 <= len(operations) <= 50000
  • User IDs are unique forever: a deleted merged source ID cannot be created again
  • processPaymentsUpTo timestamps must be non-decreasing; a backward timestamp returns 'error'
  • schedulePayment requires executeAtTimestamp to be strictly greater than current time
  • User IDs contain only letters, digits, and underscores, so they do not contain formatting delimiters

Examples

Input: ([['addUser', 'alice'], ['addUser', 'bob'], ['deposit', 'alice', '100'], ['deposit', 'bob', '30'], ['transfer', 'alice', 'bob', '40'], ['mergeUsers', 'bob', 'alice'], ['getBalance', 'bob'], ['getBalance', 'alice'], ['getHistory', 'alice'], ['getHistory', 'bob']],)

Expected Output: ['true', 'true', '100', '30', '60', 'true', 'error', '130', 'deposit:alice:100;deposit:bob:30;transfer:alice->bob:40;merge:bob->alice', 'error']

Explanation: Bob is deleted, Alice receives Bob's balance, and Alice's history contains both accounts' prior events without duplicating their shared transfer.

Input: ([['addUser', 'a'], ['addUser', 'b'], ['addUser', 'c'], ['deposit', 'a', '100'], ['deposit', 'b', '50'], ['schedulePayment', 'b', 'c', '30', '10'], ['schedulePayment', 'a', 'b', '20', '10'], ['schedulePayment', 'b', 'a', '5', '10'], ['mergeUsers', 'b', 'a'], ['processPaymentsUpTo', '10'], ['getBalance', 'a'], ['getBalance', 'c'], ['cancelPayment', 'p2'], ['getHistory', 'a']],)

Expected Output: ['true', 'true', 'true', '100', '50', 'p1', 'p2', 'p3', 'true', 'p1:executed', '120', '30', 'false', 'deposit:a:100;deposit:b:50;merge:b->a;payment:p1:a->c:30']

Explanation: b is merged into a. Payment p1 is rewritten from b->c to a->c and executes. p2 and p3 become self-payments and are automatically canceled.

Hints

  1. Store each user's history as a list of chronological event records; during merge, union the two histories and deduplicate shared transfer records.
  2. When merging, examine pending scheduled payments and replace source with target in their endpoints.
Last updated: Jul 11, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,500+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • AI Coding Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Implement a Stateful Trading Order Manager - Coinbase (medium)
  • Implement a Coin-Constrained Jump Strategy - Coinbase (hard)
  • Implement an In-Memory Database - Coinbase (hard)
  • Implement Game Physics and Block Mining - Coinbase (hard)
  • Compute Total Manual Distance - Coinbase (medium)