PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates a software engineer's competency in precise integer arithmetic and rounding semantics, multi-currency FX conversion with basis-point fees, resource allocation across balances, and maintaining transactional correctness under ordered updates.

  • medium
  • Stripe
  • Coding & Algorithms
  • Software Engineer

Process multi-currency payments with fees

Company: Stripe

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

You are building a small payment processor for a multi-currency wallet. ## Inputs 1. **Wallet balances**: a map `balances[currency] -> integer` representing the available amount in the *smallest unit* (e.g., cents). 2. **Payment method fees**: a map `methodFeeBps[method] -> integer` (fee in basis points). The **payment method fee** is: \[ fee = \left\lceil amount \times \frac{methodFeeBps}{10000} \right\rceil \] Total cost to the wallet is `amount + fee`. 3. **FX rates** (added in Part 2): a map `fx[from][to] -> (num, den)` meaning: \[ 1\ \text{unit of } from = \frac{num}{den}\ \text{units of } to \] All amounts are integer in smallest units; conversions must use **ceil** when needed. 4. **Conversion fee** (added in Part 2): `conversionFeeBps` (basis points) charged on the **source currency** amount you convert. If you convert `x` units of `from`, the fee is: \[ convFee = \left\lceil x \times \frac{conversionFeeBps}{10000} \right\rceil \] and the wallet is debited `x + convFee` from the source currency. 5. **Payments**: a list of payment requests. Each payment has: - `id` - `amount` (integer smallest units) - `currency` - `method` Payments must be processed **in order**, and balances update after each payment. --- ## Part 1 (no FX) For each payment, determine whether it **succeeds** using only the wallet balance in the same currency. - If `balances[currency] >= amount + methodFee`, mark **SUCCESS** and subtract the total from that currency. - Otherwise mark **FAIL** and do not change balances. Return the per-payment result list. --- ## Part 2 (with FX + conversion fee) Now allow paying a charge in currency `C` by using the balance in `C` and, if needed, converting funds from other currencies. Rules/assumptions: - You may convert from any other currency `S != C` directly to `C` using `fx[S][C]`. - You may perform multiple conversions for a single payment (from multiple source currencies). - Do **not** use multi-hop conversions (only direct `S -> C`). - If a payment can be funded, it must be applied and balances updated; otherwise it fails with no balance changes. - Use integer arithmetic and apply **ceil rounding** for (a) method fees, (b) conversion fees, and (c) FX conversion when computing how much source currency is required. Task: determine **SUCCESS/FAIL** for each payment and update balances accordingly. Implementation note (to remove ambiguity): when a payment needs extra funds beyond `balances[C]`, your algorithm may choose any deterministic conversion order (e.g., iterate currencies in sorted order) as long as it never overspends a balance and correctly determines feasibility. --- ## What to implement Write a function (language-agnostic) like: - `processPayments(balances, methodFeeBps, payments, fx, conversionFeeBps) -> (results, finalBalances)` where `results[i]` is `"SUCCESS"` or `"FAIL"`. ## Constraints (typical interview scale) - Number of payments up to `1e5` - Number of currencies up to `50` - All amounts fit in 64-bit signed integers

Quick Answer: This question evaluates a software engineer's competency in precise integer arithmetic and rounding semantics, multi-currency FX conversion with basis-point fees, resource allocation across balances, and maintaining transactional correctness under ordered updates.

Part 1: Process Same-Currency Payments with Method Fees

You are building a payment processor for a multi-currency wallet. Each wallet balance is stored in the smallest unit of that currency, such as cents. For each payment, you may only use the balance in the payment's own currency; foreign exchange is not allowed. Each payment method charges a fee in basis points. For a payment with amount `amount` and method fee `bps`, the fee is `ceil(amount * bps / 10000)`. The total amount debited from the wallet is `amount + fee`. Payments are processed in order. If the wallet has enough balance in the payment currency, the payment succeeds and the balance is reduced. Otherwise, the payment fails and balances remain unchanged for that payment. Payment IDs are included in the input for record-keeping, but the return value only needs one status per payment in the same order.

Constraints

  • 0 <= number of payments <= 100000
  • 1 <= number of currencies <= 50
  • 0 <= amount <= 10^18
  • 0 <= method fee basis points <= 10000
  • Every payment method appears in `method_fee_bps`
  • All balances and total costs fit in signed 64-bit integers

Examples

Input: ({'USD': 10000, 'EUR': 5000}, {'card': 250, 'bank': 0}, ['p1', 'p2', 'p3'], [1000, 9000, 5000], ['USD', 'USD', 'EUR'], ['card', 'card', 'bank'])

Expected Output: (['SUCCESS', 'FAIL', 'SUCCESS'], {'USD': 8975, 'EUR': 0})

Explanation: p1 costs 1000 + ceil(2.5%) = 1025, so it succeeds. p2 costs 9225, but USD has only 8975 left, so it fails. p3 costs 5000 and uses all EUR.

Input: ({'USD': 101}, {'card': 1}, ['p1'], [100], ['USD'], ['card'])

Expected Output: (['SUCCESS'], {'USD': 0})

Explanation: The fee is ceil(100 * 1 / 10000) = 1, so the total cost is exactly 101.

Input: ({'USD': 500}, {'card': 100}, [], [], [], [])

Expected Output: ([], {'USD': 500})

Explanation: There are no payments, so the result list is empty and balances are unchanged.

Input: ({'USD': 100}, {'bank': 0}, ['p1'], [50], ['EUR'], ['bank'])

Expected Output: (['FAIL'], {'USD': 100})

Explanation: The wallet has no EUR balance, so the EUR payment fails even though USD exists.

Hints

  1. Use integer ceiling division: `ceil(a / b) = (a + b - 1) // b` for non-negative integers.
  2. Process payments one by one and mutate a copy of the balances only when a payment succeeds.

Part 2: Process Multi-Currency Payments with Direct FX Conversions

You are building a payment processor for a multi-currency wallet. Each payment has an amount, currency, and payment method. The payment method charges a fee in basis points, so the total charge in the payment currency is `amount + ceil(amount * methodFeeBps / 10000)`. Unlike Part 1, if the wallet does not have enough balance in the payment currency, it may convert funds from other currencies using direct FX rates. Multi-hop conversions are not allowed. An FX rate `fx[S][C] = (num, den)` means `1` unit of source currency `S` is worth `num / den` units of target currency `C`. To cover `need` units of target currency `C` from source currency `S`, the required source principal is `ceil(need * den / num)`. A conversion fee is charged on the source principal. If you convert source principal `x`, the wallet is debited `x + ceil(x * conversionFeeBps / 10000)` from the source currency. For deterministic output, when a payment needs FX, source currencies must be considered in lexicographic order of their currency codes. Use the payment currency balance first, then convert from other currencies in that order. Missing direct FX rates cannot be used. Any rounding surplus caused by the ceiling source calculation is not credited as extra balance; the conversion covers only the target amount it was chosen to cover. If a payment can be fully funded, apply all balance updates and mark it `SUCCESS`. If it cannot be fully funded, mark it `FAIL` and leave all balances unchanged for that payment.

Constraints

  • 0 <= number of payments <= 100000
  • 1 <= number of currencies <= 50
  • 0 <= amount <= 10^18
  • 0 <= method fee basis points <= 10000
  • 0 <= conversion fee basis points <= 10000
  • FX rate numerators and denominators are positive integers
  • Only direct FX rates may be used; no multi-hop conversion
  • Every payment method appears in `method_fee_bps`
  • All balances and final results fit in signed 64-bit integers; use wide integer arithmetic for products in fixed-width languages

Examples

Input: ({'USD': 10000, 'EUR': 1000}, {'card': 250, 'bank': 0}, ['p1', 'p2'], [1000, 9500], ['USD', 'USD'], ['card', 'bank'], {'EUR': {'USD': (2, 1)}}, 1000)

Expected Output: (['SUCCESS', 'SUCCESS'], {'USD': 0, 'EUR': 710})

Explanation: p1 costs 1025 USD and succeeds from USD. p2 needs 525 extra USD. EUR->USD is 2:1, so covering 525 USD needs ceil(525/2)=263 EUR principal. The 10% conversion fee is ceil(26.3)=27 EUR, so EUR is debited by 290.

Input: ({'USD': 100, 'EUR': 200, 'GBP': 300}, {'card': 100}, ['p1'], [500], ['USD'], ['card'], {'EUR': {'USD': (1, 1)}, 'GBP': {'USD': (2, 1)}}, 0)

Expected Output: (['SUCCESS'], {'USD': 0, 'EUR': 0, 'GBP': 197})

Explanation: The total USD cost is 505, so the shortage is 405. Sources are tried in lexicographic order: EUR covers 200, then GBP covers the remaining 205 using ceil(205/2)=103 GBP.

Input: ({'USD': 100, 'EUR': 100}, {'bank': 0}, ['p1', 'p2'], [500, 100], ['USD', 'EUR'], ['bank', 'bank'], {'EUR': {'USD': (1, 1)}, 'USD': {'EUR': (1, 1)}}, 0)

Expected Output: (['FAIL', 'SUCCESS'], {'USD': 100, 'EUR': 0})

Explanation: p1 cannot be funded because only 100 EUR can be converted toward the 400 USD shortage, so balances remain unchanged. p2 then succeeds using the existing 100 EUR.

Input: ({'USD': 0, 'EUR': 102}, {'card': 1}, ['p1'], [100], ['USD'], ['card'], {'EUR': {'USD': (1, 1)}}, 1)

Expected Output: (['SUCCESS'], {'USD': 0, 'EUR': 0})

Explanation: The method fee is ceil(100 * 1 / 10000) = 1, so 101 USD is needed. Converting 101 EUR principal has conversion fee ceil(101 * 1 / 10000) = 1, debiting all 102 EUR.

Input: ({'USD': 123}, {'card': 250}, [], [], [], [], {}, 100)

Expected Output: ([], {'USD': 123})

Explanation: There are no payments, so balances remain unchanged.

Hints

  1. For a source balance `b`, the largest source principal `x` you can convert satisfies `x + ceil(x * feeBps / 10000) <= b`. This is equivalent to `x * (10000 + feeBps) <= 10000 * b`.
  2. Plan conversions first without mutating balances. Only apply the planned debits if the payment can be fully covered.
Last updated: Jun 22, 2026

Loading coding console...

PracHub

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

Product

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

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL 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

  • Assign Reviewers from Changed Files - Stripe (medium)
  • Generate Account Email Notifications - Stripe (medium)
  • Calculate Transaction Fees - Stripe (medium)
  • Build an Account Transfer Ledger - Stripe (medium)
  • Implement Validation and String Compression - Stripe (hard)