Katkat

Build a Progressive Banking System

InstacartSoftware Engineer · Technical Screen

Last updated

This problem tests your ability to manage state transitions, handle expiring reservations, and maintain consistent ledger balances across multiple accounts.

Progressive Banking System

You are tasked with building the backend logic for a banking system that handles accounts, transfers, and account merging. Each account is identified by a unique integer ID.

Implement the following methods:

  1. create_account(account_id): Creates a new account with an initial balance of 0. Returns True if successful, False if the account already exists.
  2. deposit(account_id, amount): Increases the balance of the specified account by amount. Returns the new total balance if the account exists, otherwise returns None.
  3. request_transfer(from_id, to_id, amount, timestamp): Attempts to reserve amount from from_id. The transfer is only valid if from_id exists and has a balance of at least amount.
    • This reservation expires if not accepted within 1000 time units (i.e., if current_timestamp > reservation_timestamp + 1000).
    • Returns a reservation_id (a positive integer) if successful, otherwise None.
  4. accept_transfer(reservation_id, current_timestamp): Completes a valid, non-expired transfer. Deducts the reserved amount from the sender and adds it to the recipient. Returns True if successful, False otherwise.
  5. merge_accounts(account_id1, account_id2): Merges account_id2 into account_id1. All funds from account_id2 are moved to account_id1. account_id2 is then deleted and cannot be used again.

Constraints

  • amount is always a positive integer.
  • account_id is a positive integer.
  • reservation_id must be globally unique.
  • Ensure merge_accounts handles cases where a target account might have pending transfers.

Examples

bank = BankingSystem()
bank.create_account(1)
bank.deposit(1, 100)
res_id = bank.request_transfer(1, 2, 50, 100) # Returns None, account 2 doesn't exist
bank.create_account(2)
res_id = bank.request_transfer(1, 2, 50, 100) # Returns 1
bank.accept_transfer(1, 500) # Returns True; 1 balance: 50, 2 balance: 50

Hints

Hint 1

Use a dictionary to map account IDs to their current balances and a separate dictionary or hash map to store active reservations containing metadata like sender, recipient, amount, and timestamp.

Hint 2

For the expiry logic, validate the timestamp against the stored reservation timestamp every time `accept_transfer` is called.

Hint 3

When merging accounts, ensure that you transfer all balance correctly and decide how to handle existing reservations tied to the deleted account (e.g., invalidate them or migrate them to the new ID).

Follow-up questions

  • How would you optimize the `merge_accounts` function if an account has thousands of pending, unexpired transfer reservations?
  • What concurrency challenges arise if this system receives multiple `accept_transfer` requests for the same reservation simultaneously?
  • If we needed to support audit logs, how would you store the history of every transaction to ensure the system is idempotent?