The Wallet Class

The idea

Our wallet class is designed to be a simple and easy to understand class that can be used to create and manage wallets in our blockchain. Create a new file called wallet.ts and copy and paste the code below.

📄wallet.ts
1import { Transaction } from '../types';
2
3export class Wallet {
4  private balances: Map<string, number> = new Map();
5
6  constructor(initialBalances: { address: string; balance: number }[]) {
7    // initialize the balances
8    initialBalances.forEach(({ address, balance }) => {
9      this.balances.set(address, balance);
10    });
11  }
12}

The getBalance() and hasEnoughBalance() methods

This method is used to get the balance of an address.

📄wallet.ts
1// get the balance of an address
2getBalance(address: string): number {
3  return this.balances.get(address) || 0;
4}
5
6// check if an address has enough balance
7hasEnoughBalance(address: string, amount: number): boolean {
8  return this.getBalance(address) >= amount;
9}

The updateBalance() method

This method is used to update the balance of an address. First we get the current balance of the address. Then we update the balance of the address.

📄wallet.ts
1// update the balance of an address
2updateBalance(address: string, amount: number) {
3  const currentBalance = this.getBalance(address);
4  this.balances.set(address, currentBalance + amount);
5}

The processTransaction() method

This method is used to process a transaction. First we check if the sender has enough balance (including fee). Then we update the balances of the sender and receiver.

📄wallet.ts
1// process a transaction
2processTransaction(transaction: Transaction): boolean {
3  const { senderAddress, receiverAddress, amount, fee } = transaction;
4  
5  // check if the sender has enough balance (including fee)
6  if (!this.hasEnoughBalance(senderAddress, amount + fee)) {
7    return false;
8  }
9
10  // update the balances
11  this.updateBalance(senderAddress, -(amount + fee));
12  this.updateBalance(receiverAddress, amount);
13
14  return true;
15}

The checkDoubleSpending() method

This method is used to check for double spending (a transaction that has already been processed) in a list of transactions. First we save the initial balances of the senders. Then we check for double spending in the list of transactions.

📄wallet.ts
1// check for double spending in a list of transactions
2checkDoubleSpending(transactions: Transaction[]): boolean {
3  const spentAmounts = new Map<string, number>();
4  const initialBalances = new Map<string, number>();
5
6  // save the initial balances
7  for (const tx of transactions) {
8    // save the initial balance of the sender
9    if (!initialBalances.has(tx.senderAddress)) {
10      initialBalances.set(tx.senderAddress, this.getBalance(tx.senderAddress));
11    }
12  }
13
14  // check for double spending
15  for (const tx of transactions) {
16    // get the sender address, amount and fee
17    const { senderAddress, amount, fee } = tx;
18    // get the current spent amount
19    const currentSpent = spentAmounts.get(senderAddress) || 0;
20    // get the total spent amount
21    const totalSpent = currentSpent + amount + fee;
22    // get the initial balance of the sender
23    const initialBalance = initialBalances.get(senderAddress) || 0;
24    // check if the total spent would exceed the initial balance
25    if (totalSpent > initialBalance) {
26      return true; // double spending detected
27    }
28
29    // save the total spent amount
30    spentAmounts.set(senderAddress, totalSpent);
31  }
32
33  return false;
34}

The Transaction type

This is the type of the transactions that can be processed by the wallet class.

📄types.ts
1export type Transaction = {
2	amount: number;
3	senderAddress: string;
4	receiverAddress: string;
5	note?: string;
6	timestamp: string;
7	fee: number;
8}