tap-sdk is a client-side SDK for applications that talk to tapd, the
Taproot Assets daemon. The root package exposes the business API; transport
packages own wire formats and connection setup.
The current Go implementation is the source of truth for the public API model, but the design is intentionally language-portable. Future TypeScript, Rust, Python, Kotlin, and Swift SDKs should expose the same business concepts even if their package layout differs.
Application
│
│ uses AssetRef, Wallet, Issuer, Universe, TxBuilder
▼
tap-sdk root package
│
│ Client interface
▼
grpc/ or rest/
│
│ tapd RPC over TLS + macaroons
▼
tapd
│
├─ lnd wallet/signing backend
└─ Taproot Assets state, proofs, universe, mint batches
| Package | Boundary |
|---|---|
tapsdk |
Business API, domain types, high-level wallet/issuer/universe surfaces, builders, errors |
grpc |
Native gRPC client, TLS setup, macaroon auth, proto marshal/unmarshal |
rest |
REST client, TLS setup, macaroon auth, JSON marshal/unmarshal, WebSocket event streams |
macaroon |
Low-level macaroon source helpers shared by transports |
internal/anchor |
Anchor PSBT helpers |
internal/codec |
Internal TLV/alt-leaf/STXO encoding helpers |
internal/vpsbt |
Virtual PSBT encoding for interactive transfers |
The root package must not import transport packages. Transports import the root package and return root SDK types. That one-way dependency keeps the business API stable even if the repo layout changes later.
The SDK separates user-facing business concepts from tapd protocol details.
| Concept | Meaning |
|---|---|
AssetRef |
Opaque, storable handle for an asset in the SDK API |
Asset |
A fungible token or one NFT item |
Collection |
A group of NFT items |
Issuance |
One concrete protocol issuance/tranche of a fungible asset |
AssetRecord |
Low-level wallet row that still exposes protocol details |
Balance |
Confirmed balance for one semantic AssetRef |
Transfer / Burn |
Asset movement or destruction keyed by AssetRef |
Grouped fungibles are keyed by group AssetRef. Standalone NFTs and NFT
collection items are keyed by asset-ID AssetRef. Collections are keyed by
group AssetRef, but a collection is not itself an asset.
See Asset Model for more detail.
Wallet is the primary application surface. It wraps a Client and exposes
common operations using AssetRef:
- receive addresses
- sends and multi-sends
- balances, assets, issuances, collections, transfers
- proof import/export
- burns
- ownership proofs
- transaction builders
- event listeners
- access to
IssuerandUniverse
Low-level RPC-shaped methods remain available through wallet.Client() for
advanced callers.
Issuer hides tapd mint batch mechanics behind business actions:
CreateFungibleIssueFungibleCreateNFTCreateCollectionMintCollectionItem
The issuer serializes its own mint operations because tapd has one active mint batch per daemon. If a mint result times out while resolving, callers should inspect wallet assets or batches before retrying to avoid duplicate issuance.
Universe is the high-level discovery and proof surface:
HasAssetGetRootsListProofsGetProofSyncAssetSyncAssets
The high-level API takes AssetRef. The low-level UniverseClient remains
available for direct protocol-shaped universe operations.
Both transports satisfy the same root Client interface.
type Client interface {
WalletClient
WalletKitClient
ProofClient
UniverseClient
MintClient
EventClient
Close() error
}The gRPC transport consumes native server-streaming RPCs. The REST transport uses tapd's grpc-gateway JSON endpoints and WebSocket bridge for event streams. Both transports map tapd responses to the same root SDK types and error surface.
Transport configs accept typed TLS and macaroon sources:
client, err := tapgrpc.NewClient(&tapgrpc.Config{
Host: "localhost:10029",
Network: tapsdk.NetworkRegtest,
TLS: tapgrpc.TLSFromPath("/path/to/tls.cert"),
Macaroon: tapsdk.MacaroonFromPath("/path/to/admin.macaroon"),
})TLS supports:
- default tapd certificate path
- certificate file
- certificate PEM data
- system certificate pool
- explicit insecure mode for local tests
- minimum TLS version
- optional SHA-256 certificate pinning
Macaroons can be loaded from one file, a directory of per-service macaroons, or one hex-encoded macaroon.
See Transports and Auth.
The low-level EventClient streams tapd event records. The high-level
EventListener projects those records into SDK business events:
MintEventSendEventReceiveEvent
Transfer rows include tapd asset type data. The SDK uses that field to keep
grouped fungibles keyed by group AssetRef while NFT collection items stay
keyed by concrete item AssetRef.
SDK methods wrap failures in *tapsdk.Error where possible:
type Error struct {
Op string
Err error
}Errors preserve the underlying gRPC status when available, including REST
responses that originate from grpc-gateway. Common conditions also map to
sentinel errors such as ErrAssetUnknown, ErrInsufficientBalance,
ErrProofNotFound, ErrPermissionDenied, and ErrUnsupportedByTapd.
The SDK targets tapd v0.8.0 or newer. Older versions do not expose enough asset type data for the SDK to reliably distinguish grouped fungibles from NFT collection items across transfers, burns, and events.
See Compatibility.
- Developer-facing first. The SDK should expose business operations, not raw tapd nouns, unless a caller intentionally drops to the low-level client.
AssetRefeverywhere. Application code should store and pass one asset handle across wallet, issuer, proof, burn, event, and universe flows.- Honest names. Assets, collections, and issuances are distinct concepts. The SDK should not hide that distinction behind a generic type.
- Transport parity. gRPC and REST should return the same SDK types and comparable errors.
- Portable API model. Go package layout should not leak into the long-term SDK model intended for other languages.