Katkat

Design in-memory payment and friendship system

RobinhoodSoftware Engineer · Technical Screen

Last updated

This question evaluates object-oriented design skills, stateful in-memory data structures, request processing, and correctness constraints such as friend relationships, unique request IDs, and atomic balance transfers.

Design and implement an in-memory payment system with simple social features. The system processes a sequence of requests that can:

  1. Register a user
  2. Send a friend request from one user to another
  3. Accept a friend request (referencing a previous friend request by its request ID)
  4. Transfer money between two users

Rules and Requirements

  1. Users and balances
  • Each user has:
  • A unique user_id (string)
  • A balance (integer amount, e.g., cents)
  • A list or set of friends (other user IDs)
  1. Friend requests
  • A friend request is initiated via a request that includes:
  • A unique req_id for this friend request
  • user1 and user2 (both must be existing users)
  • An accept-friend request does not repeat the usernames; instead it contains:
  • Its own req_id (unique for the accept request)
  • The req_id of the original friend request to accept
  • Only when an accept-friend request is processed successfully do user1 and user2 become friends.
  1. Transfers
  • Money can only be transferred between users who are already friends.
  • A transfer request specifies:
  • A unique req_id
  • from_user
  • to_user
  • amount (> 0)
  • A transfer must fail if:
  • Either user does not exist, or
  • The users are not friends, or
  • from_user does not have enough balance.
  • On success:
  • Subtract amount from from_user.balance.
  • Add amount to to_user.balance.
  1. Error handling
  • If a request is invalid (e.g., refers to unknown user, refers to a non-existent friend request ID, tries to accept a friend request twice, etc.), the system should indicate failure for that request.
  • You can define reasonable behavior for repeated or conflicting requests, but document it in comments.

Interface

Design classes and methods in an object-oriented way.

One possible interface (you can adjust names/signatures as long as behavior is clear):

class PaymentSystem:
 def register_user(self, user_id: str, initial_balance: int) -> bool:
 """Register a new user with given balance. Return False if user_id already exists."""

 def send_friend_request(self, req_id: str, user1: str, user2: str) -> bool:
 """Store a friend request identified by req_id. Return False on invalid input or duplicate req_id."""

 def accept_friend_request(self, req_id: str, original_req_id: str) -> bool:
 """Accept the previously stored friend request with ID original_req_id. Return False if original_req_id doesn't exist, is already accepted, or users are invalid."""

 def transfer(self, req_id: str, from_user: str, to_user: str, amount: int) -> bool:
 """Transfer amount from from_user to to_user if they are friends and balance is sufficient. Return True on success, False otherwise."""

Your implementation should:

  • Maintain all necessary internal state in memory (no external database required).
  • Enforce the friendship and balance constraints for transfers.
  • Correctly handle the indirection where a friend-accept request refers to an earlier friend-request by req_id.

You may ignore concurrency in the basic solution, but you can optionally comment on how you would make operations atomic under multiple threads.