---
# System prepended metadata

title: 'System Design: Accounting Transactions Sync'

---


# System Design: Accounting Transactions Sync


### Background

At Starlight, one feature we offer is crypto buy/sells. Businesses can buy and sell different coins (ETH, BTC) from their fiat accounts and manage it all in one place.

To help our customers report these transactions on their taxes, we allow them to export transaction data to 3rd party accounting providers (e.g. Intuit Quickbooks).

This interview will focus on

1. Preparing transaction data for export (by computing the cost basis)
2. Syncing transactions to a 3rd party

---

# Part 1: Cost Basis

Cost basis is the original price at which an asset was aquired. For our purposes this is computed for each debit (sale) of an asset (Bitcoin or Ethereum).

For example, in the simplest case:

1. *Buy* 1 ETH @ $1000
2. *Sell* 1 ETH @ $3000 → The cost basis is $1000, since we sold an ETH we bought at $1000

Here's a slightly more complicated case. These are 4 transactions completed in order:

1. Buy 2 ETH @ $1000
2. Buy 1 ETH @ $2000
4. Sell 1 ETH @ $3000
5. Sell 2 ETH @ $3000

```
interface TransactionAmount {
    price: number // price of each token
    quantity: number // number of tokens
}

interface Transaction extends TransactionAmount {
    id: number // unique identifier
    type: "buy" | "sell",
    timestamp: number // milliseconds
}

interface CostBasis {
    transactionId: number;
    cost: number;
}


// Output: an array of cost basis for every sell transaction in the original transaction array.
```

```
// all transactions were ordered by timestamp
Buy 1 @ 2500
Buy 2 @ 2000
Sell 1 @ 3000
```

```
2500 -> 1
2000 -> 2
```

```
// Write your code here
function extractCostbasis(transactions: Transaction[]): CostBasis[] {
    const queue: BuyRecord[] = [];
    for (let t of transactions) {
        if (t.type === "buy") {
            queue.push(t);
            continue;
        }
        
        // t.type == "sell"
        let amount = 0;    // amount of available token
        let amountUSD = 0;    // USD amount spent while buying
        for (let item of queue) {
            if (item.amount < t.amount) {
                amount += item.amount;
                amountUSD += item.amount * item.price;
                queue
            }
        }
    }
    
}
```

## Notes

Now we are presented with a choice: when computing the cost basis for #3, should we use the price of ETH aquired in #1, or in #2? The answer depends on which method of cost basis we want to use: **FIFO**, **LIFO**, or **HIFO**:

Mock a system to compute cost basis for sell transactions using the three methods (FIFO, LIFO, HIFO).

Tip: start by implementing a single method, then expand your solution to cover all 3.

# Part 2: Accounting Sync

Now that we have a method to calculate cost basis, let’s implement the accounting sync feature. We are given the following requirements:

- The user can mark transactions as **INTERNAL** or **EXTERNAL** in our UI, marking transfers as **INTERNAL** excludes them entirely from cost basis calculations.
- The user can use a toggle to switch the cost basis method (FIFO, LIFO, HIFO)
- The user can click a button to sync these transactions to Quickbooks, using the API schema provided.

Design a system to sync transactions between the Starlight backend and quickbooks.

Here's the API schema to help you get started:

**Accounting Integration API**

```
type QuickbookTransaction = Transaction & {
    category: "INTERNAL" | "EXTERNAL"
}
```

```
// it is filter function.
// allTransactions: all internal & external transactions
// id: transaction id, that user toggled between internal and external
// returns external transactions only
function getExternalTransactions(allTransactions: Transaction[], id: number): Transaction[] {
    // [TODO]
}

function extractCostBasis(transactions: Transaction[]): CostBasis[] {
    // finished before
}

extractCostBasis(
    getExternal
)
```
    
    

