Skip to content

Show a balance ​

Read the balance once, then follow it as it changes.

first value is the balance now useBalance ships in the package no retry after FederationClosed

Every amount in this SDK is a bigint of millisatoshis. One sat is 1000n. The core never rounds an amount for you, so a fee of half a sat is 500n, not zero. The type is called Amount. No conversion helpers ship, so do the arithmetic inline: msat / 1000n gives whole sats.

That choice costs you one rule, and Amounts ends with it: a bigint cannot go through JSON.stringify.

01 · Read it once JavaScript ​

fed.balance() is the spendable balance of one federation, now. Use it where you need a number once, such as before a send.

read-balance.ts
ts
import type { FederationLike } from '@fedimint/react-native'

export async function balanceLine(fed: FederationLike): Promise<string> {
  // A bigint, in millisatoshis: 1000n is one sat. A new wallet answers 0n.
  const msat = await fed.balance()
  return `${msat / 1000n} sats`
}

Check

On a federation you just joined, you will see 0 sats.

02 · Follow it JavaScript ​

A screen that shows a balance wants every change, not one reading. fed.balanceUpdates() returns a cursor. Its first next() returns the balance now. Each later next() waits for the next change. Pass an AbortSignal so that you can stop it. This is how code outside React follows a balance:

follow-balance.ts
ts
import type { Amount, FederationLike } from '@fedimint/react-native'

/** Calls onChange with the balance now, then on every change. Returns a function that stops it. */
export function followBalance(
  fed: FederationLike,
  onChange: (msat: Amount) => void,
  onError: (err: unknown) => void,
): () => void {
  const controller = new AbortController()
  const { signal } = controller
  const updates = fed.balanceUpdates()

  void (async () => {
    try {
      for (;;) {
        // The first value is the balance now. Every later value is a change.
        const msat = await updates.next({ signal })
        if (signal.aborted) return
        onChange(msat)
      }
    } catch (err) {
      // A balance never ends cleanly. FederationClosed is how the stream stops.
      if (!signal.aborted) onError(err)
    }
  })()

  return () => controller.abort()
}

In React, use useBalance. It does the same work, and it stops when the component unmounts:

BalanceLine.tsx
tsx
import React from 'react'
import { Text } from 'react-native'
import { useBalance, type FederationLike } from '@fedimint/react-native'

export function BalanceLine({ fed }: { fed: FederationLike | undefined }) {
  // undefined until the first value arrives, then the balance in msat, kept current.
  const msat = useBalance(fed, (err) => console.log('balance watch', err))
  return (
    <Text>{msat === undefined ? 'loading...' : `${msat / 1000n} sats`}</Text>
  )
}

INFO

The onError callback hears about failures to watch, not failures of money. The usual one is FederationClosed, after the federation or the SDK closes. Neither followBalance nor useBalance starts again by itself. After you reopen the federation, start a new watch. For useBalance, remount the component with a new React key. Share the session shows how.

Check

Render BalanceLine and receive some ecash as in Receive money. You will see the line change from 0 sats to the new balance with no code of yours in between.

What you just did ​

You read a balance once, and followed it as it changes, both outside React and with useBalance. See the history uses the same bigint amounts for history rows.