Reference: Lightning Balances

Overview

The Lightning Network operates fundamentally differently from traditional Bitcoin blockchain transactions. Understanding these differences is crucial for properly managing Lightning wallets.

Liquidity Network

On the Bitcoin blockchain, bitcoin balances exists in on-chain addresses. However, on the Lightning Network, Lightning bitcoin exist in payment channels between nodes within the liquidity network - an L2 built on top of the Bitcoin blockchain. Your ability to send or receive payments depends on the liquidity available within these channels.

This results in following two types of liquidity:

  • Inbound liquidity - The capacity others have to send payments to you.
  • Outbound liquidity - Your capacity you have to send payments to others

Both directions of liquidity exist simultaneously in the same channel.

Millisatoshi Precision

Lightning Network uses millisatoshis (msats) as its base unit, which is 1/1000th of a satoshi. This enables for micro-payments that would be impractical on the Bitcoin blockchain. While smallest unit of bitcoin is 1 satoshi (0.00000001 BTC), Lightning can handle payments as small as 0.001 satoshis.

State vs. Settlement

Lightning balances represent your current state in payment channels - not confirmed blockchain transactions. Channels can open and closed on the Bitcoin blockchain, but the individual Lightning payments occur off-chain with near-instant finality.

Lightning Balance Fields

When you retrieve a Lightning wallet balance from BitGo, you see several fields that represent different aspects of your Lightning liquidity:

Inbound Balance Fields

"inboundBalance": "0",
"inboundPendingBalance": "0",
"inboundUnsettledBalance": "0"
  • inboundBalance - The total amount (in satoshis) you can receive through your Lightning channels. This represents your receiving capacity across all open channels.

  • inboundPendingBalance - The amount (in satoshis) currently being added to your inbound liquidity. For example, channels that are in the process of opening and will impact your receiving capacity.

  • inboundUnsettledBalance - The amount (in satoshis) from incoming payments you received, but haven't yet fully settled in the channel state.

Outbound Balance Fields

"outboundBalance": "0",
"outboundPendingBalance": "0",
"outboundUnsettledBalance": "0"
  • outboundBalance - The total amount (in satoshis) you can send through your Lightning channels. This represents your sending capacity across all open channels and is effectively the assets you control.

  • outboundPendingBalance - The amount (in satoshis) that's in the process of being added to your outbound liquidity. For example, in-progress deposits to channels that are still pending on-chain confirmation.

  • outboundUnsettledBalance - The amount (in satoshis) from outgoing payments that were sent, but not yet fully settled in the channel state.

On-Chain Balance Fields

"balanceString": "0",
"confirmedBalanceString": "0",
"spendableBalanceString": "0"

These fields represent your on-chain bitcoin balance, separate from your Lightning channel liquidity:

  • balanceString - Your total on-chain bitcoin balance (in satoshis) in the wallet. This is the traditional balance on the Bitcoin blockchain -e not Lightning channel funds.

  • confirmedBalanceString - The portion of your on-chain balance that received sufficient blockchain confirmations and is considered fully settled.

  • spendableBalanceString - The amount of on-chain Bitcoin you can immediately withdraw. This can differ from the confirmed balance if there are any restrictions or reserved amounts.

Important - These on-chain balances are distinct from your Lightning channel balances (inboundBalance and outboundBalance). The on-chain balance represents bitcoin held in regular blockchain addresses, while Lightning balances represent funds locked in payment channels.

Total Balance Owned

Your total balance across the Lightning wallet is the sum of your on-chain Bitcoin and your Lightning channel funds:

Total Balance = balanceString + outboundBalances

Why this Calculation?

  • balanceString - Your on-chain bitcoin that you control.
  • outboundBalances - Your Lightning channel funds that you can spend.

What About Inbound Balance?

The inboundBalance represents your capacity to receive payments, not assets you currently own. Inbound liquidity is capacity provided by your channel partners on their side of the channels. Only your outboundBalance represents Lightning assets you actually control.

Example:

{
  "confirmedBalanceString": "500000",    // 0.005 BTC on-chain
  "outboundBalance": "1000000",          // 0.01 BTC in Lightning channels
  "inboundBalance": "2000000"            // 0.02 BTC receiving capacity (not yours)
}

In this example:

  • Total funds you own - 1,500,000 satoshis (0.015 BTC)
    • 500,000 sats on-chain
    • 1,000,000 sats in Lightning channels
  • Receiving capacity - 2,000,000 satoshis (not part of your balance)

Key Considerations

  • Bidirectional liquidity - Unlike traditional Bitcoin wallets, you must consider both your ability to send (outbound) and receive (inbound) funds.
  • Channel capacity - Your total channel capacity is the sum of inbound and outbound balance for each channel.
  • Rebalancing - You may need to rebalance channels to maintain optimal inbound and outbound liquidity for your use case.
  • Channel fees - Opening and closing channels involves on-chain Bitcoin transactions with associated fees.

Get Lightning Balance from BitGo

Endpoint: Get Wallet By ID

export BITGO_EXPRESS_HOST="<YOUR_LOCALHOST>"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"

curl -X GET \
  https://$BITGO_EXPRESS_HOST/api/v2/wallet/$WALLET_ID \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" 
  const { BitGo } = require('bitgo');
  const accessToken = '<YOUR_ACCESS_TOKEN>';

  // Initialize the SDK
  const bitgo = new BitGo({
    accessToken: accessToken,
    env: 'test',
    customRootURI: 'https://app.bitgo-test.com',
  });

  // Enter your Lightning wallet
  const walletId = '<YOUR_WALLET_ID>'
  const existingWallet = await bitgo.coin('tlnbtc').wallets().get({ id: walletId });
  console.dir(existingWallet);

Step Result

In this example:

  • You can receive up to 500,000,000 mili-satoshis (500,000 satoshis) (0.005 BTC)
  • You can send up to 1,000,000,000 mili-satoshis (1,000,000 satoshis) (0.01 BTC)
  • Your spendable balance is 1,000,000,000 mili-satoshis (accounting for 100,000 mili-satoshi on-chain network fee)
{
  ...
  offchain: {
    inboundBalance: '500000000',
    inboundPendingBalance: '0',
    inboundUnsettledBalance: '0',
    outboundBalance: '1000000000',
    outboundPendingBalance: '0',
    outboundUnsettledBalance: '0',
    outboundLockedBalance: '0'
  },
  balanceString: '1000100000',
  confirmedBalanceString: '1000100000',
  spendableBalanceString: '1000000000',
  ...
}

See Also