Skip to content

taprpc+tapcli: expose channel and pending asset balances#2094

Draft
jtobin wants to merge 6 commits into
lightninglabs:mainfrom
jtobin:issue2093
Draft

taprpc+tapcli: expose channel and pending asset balances#2094
jtobin wants to merge 6 commits into
lightninglabs:mainfrom
jtobin:issue2093

Conversation

@jtobin
Copy link
Copy Markdown
Member

@jtobin jtobin commented Apr 25, 2026

Resolves #2093, #1634. Tested e2e on a Docker regtest network.

Lightly-edited Opus-generated summary:

Each of tapcli assets {list,balance,utxos} now accepts --include_channel to show assets locked in Lightning channels alongside regular on-chain assets. For assets balance, this also reports in-channel balances (open and pending-close/force-close) broken down by local and remote amounts. Each of tapcli assets {balance,list} also now accepts --include_pending to show unconfirmed outbound transfer balances and pending transfer outputs without having to manually filter ListTransfers.

All this stuff is backed by new, backward-compatible, opt-in fields on the List{Balances,Assets,Utxos} RPCs.

Examples:

# Show on-chain balances plus channel-locked balances
$ tapcli assets balance --by_group --include_channel

# Show confirmed and pending (unconfirmed) balances
$ tapcli assets balance --include_pending

# List confirmed assets plus pending transfer outputs
$ tapcli assets list --include_pending

# Show UTXOs that anchor channel assets
$ tapcli assets utxos --include_channel

# Combine: full picture of a specific asset
$ tapcli assets balance --asset_id=$ASSET_ID --include_channel --include_pending

jtobin added 4 commits April 24, 2026 12:36
Add opt-in flags to surface two classes of hidden assets:

ListBalancesRequest: include_channel (field 7), include_pending
(field 8). ListUtxosRequest: include_channel (field 3).
ListAssetRequest: include_channel (field 14),
include_pending_transfers (field 15).

ListBalancesResponse: pending_asset_balances (field 4),
pending_asset_group_balances (field 5), channel_asset_balances
(field 6), channel_group_balances (field 7),
pending_channel_asset_balances (field 8),
pending_channel_group_balances (field 9).

ListAssetResponse: pending_assets (field 4) as a separate list
from the paginated confirmed assets.

Add AssetChannelBalance message for in-channel local/remote
balance reporting.

Refs lightninglabs#2093, lightninglabs#1634.
Add includeChannel parameter to QueryBalancesByAsset and
QueryAssetBalancesByGroup. When set, the channel script key type
is unconditionally appended via appendChannelKeyType, ensuring
it takes effect even when the default BIP-86 type causes
ScriptKeyTypeForDatabaseQuery to return early.

Add IncludeChannel field to AssetQueryFilters and wire it
through constraintsToDbFilter for ListAssets/ListUtxos.

Add FetchGenesisByAssetID to AssetStore for looking up genesis
info when computing pending balances for assets with zero
confirmed balance.
Pass include_channel and include_pending flags through
ListBalances, ListAssets, and ListUtxos to the store queries.

ListBalances: pendingBalancesByAsset and pendingBalancesByGroup
aggregate local outputs from unconfirmed outbound parcels,
filtered by the same script key type constraints as confirmed
balances. pendingBalancesByGroup extracts group keys from proof
suffixes via sparse decoding and skips ungrouped assets.
genesisForAsset provides genesis info lookup with DB fallback.
Channel balances (open and pending-close) are fetched from lnd
via fetchChannelAssetBalances and populated into the new
response fields.

ListAssets: pendingTransferAssets constructs Asset proto objects
from unconfirmed parcel outputs by sparse-decoding proof
suffixes into ChainAssets with AnchorBlockHeight=0. Content
filters (amount range, group key, script key, anchor outpoint,
script key type) are applied. The output's wallet-aware
ScriptKey is preserved over the sparse-decoded one so
script_key_is_local and script_key_type are accurate. Results
go into a separate pending_assets response field to avoid
inflating paginated confirmed results.
Add --include_channel to 'assets list', 'assets utxos', and
'assets balance'. Add --include_pending to 'assets balance' and
'assets list'. Update help text for list/utxos commands to
clarify on-chain scope.
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the visibility of asset balances and UTXOs by introducing new opt-in flags for RPC calls. These changes allow users to see assets currently locked in Lightning channels and track unconfirmed outbound transfers directly through the standard asset listing and balance commands. The implementation ensures that these new data points are surfaced in a backward-compatible manner, improving the overall developer experience when managing assets across different states.

Highlights

  • New RPC Flags: Added --include_channel and --include_pending flags to tapcli assets {list,balance,utxos} to expose previously hidden asset data.
  • Channel Asset Visibility: The --include_channel flag allows users to view assets locked in Lightning channels, including open and pending-close balances.
  • Pending Transfer Visibility: The --include_pending flag enables viewing unconfirmed outbound transfer balances and outputs, removing the need for manual filtering.
  • Backward Compatibility: All new RPC fields are backward-compatible and opt-in, ensuring no breaking changes for existing integrations.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

jtobin added 2 commits April 25, 2026 01:33
tapdb: extend TestQueryAssetBalancesCustomChannelFunding to verify
that includeChannel=true returns both channel and normal assets
with the correct combined balance. Add TestFetchGenesisByAssetID
to validate the new DB method used by the rpcserver genesis
lookup fallback.

rpcserver: add unit tests for the pure/standalone helper functions
introduced for balance visibility: scriptKeyTypeAllowed,
appendChannelScriptKeyType, jsonToChannelBalances, and
pendingBalancesByGroup (with sub-tests for aggregation, remote
output skipping, ungrouped asset skipping, empty proof suffix
handling, group key filtering, and script key type filtering).

itest: in testAssetBalances, smoke-test ListBalances with
include_pending and include_channel flags after minting. In
testBasicSendUnidirectional, assert that the pending balance for
the sender's change output is correct between send broadcast and
block confirmation.
Document the new include_channel, include_pending, and
include_pending_transfers flags across ListBalances, ListAssets,
and ListUtxos, along with the corresponding CLI flags.
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the --include_channel and --include_pending flags to the asset listing and balance RPCs and CLI commands, enabling visibility into assets within Lightning channels and unconfirmed outbound transfers. The changes span the CLI, RPC server, and database layers, supported by new unit and integration tests. Feedback focuses on performance optimizations in the pending asset filtering logic and leveraging existing library methods for outpoint deserialization to improve code readability.

Comment thread rpcserver/rpcserver.go
Comment thread rpcserver/rpcserver.go
@jtobin jtobin requested a review from darioAnongba April 25, 2026 04:05
Copy link
Copy Markdown
Contributor

@darioAnongba darioAnongba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should pause this PR before we figure out how to improve the API request/response shapes because we are growing into an already badly shaped API:

  • ListBalancesResponse now has 8 maps keyed across the 4×2 product of (state, grouping). The shape is asymmetric, not uniformly filterable, and every future state will add another two maps.
  • Clients can't be expected to merge/iterate 6 mutually exclusive maps that index over the same assetID / group key.

We can collapse everything into 1 iterable response for clients, something like this (generated by Opus):

enum BalanceState {
  BALANCE_STATE_UNSPECIFIED       = 0;
  BALANCE_STATE_CONFIRMED         = 1;
  BALANCE_STATE_PENDING           = 2;  // local outputs of unconfirmed sends
  BALANCE_STATE_CHANNEL_OPEN      = 3;
  BALANCE_STATE_CHANNEL_CLOSING   = 4;  // force/coop close in flight
}

enum BalanceGrouping {
  BALANCE_GROUPING_UNSPECIFIED = 0;
  BALANCE_GROUPING_ASSET_ID    = 1;
  BALANCE_GROUPING_GROUP_KEY   = 2;
}

message AssetBalanceEntry {
  BalanceGrouping     grouping       = 1;  // how `key` is interpreted
  bytes               key            = 2;  // raw asset_id (32B) or group key
  BalanceState        state          = 3;
  uint64              amount         = 4;  // total / on-chain amount
  AssetChannelBalance channel        = 5;  // populated only for channel states
  GenesisInfo         asset_genesis  = 6; 
}

message ListBalancesResponse {
  repeated AssetBalanceEntry entries = 1;
  uint64 unconfirmed_transfers       = 2;
}

On the request, the current oneof of two bool makes no sense. Then, with all the include_*, this API is way too ugly, just a soup of boolean flags.
We can improve with something like:

message ListBalancesRequest {
  BalanceGrouping     grouping          = 1;  // replaces oneof
  bytes               asset_id_filter   = 2;
  bytes               group_key_filter  = 3;
  ScriptKeyTypeQuery  script_key_type   = 4;
  bool                include_leased    = 5;

  // Empty = CONFIRMED only (preserves current default).
  repeated BalanceState include_states  = 6;

  uint64 min_amount = 7;
  uint64 max_amount = 8;
}

Since this is v0.9, we should think this through and not be afraid to break the shape IMO.

@@ -0,0 +1,76 @@
# Release Notes
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe worth considering moving to Keep a changelog https://keepachangelog.com/en/1.1.0/ for v0.9.0?

@github-project-automation github-project-automation Bot moved this from 🆕 New to 👀 In review in Taproot-Assets Project Board Apr 27, 2026
@jtobin
Copy link
Copy Markdown
Member Author

jtobin commented Apr 30, 2026

Going to convert this one to draft as I agree we should hold off on merging until we're more properly focused on v0.9.

@jtobin jtobin marked this pull request as draft April 30, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

[feature]: Expose pending asset balances/transactions [feature]: make tapcli commands aware of off chain assets in a channel

2 participants