taprootassets

package module
v0.8.0-rc1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 28, 2026 License: MIT Imports: 69 Imported by: 2

README

Taproot Assets

The Taproot Assets Daemon tapd implements the Taproot Assets Protocol for issuing assets on the Bitcoin blockchain. Taproot Assets leverage Taproot transactions to commit to newly created assets and their transfers in an efficient and scalable manner. Multiple assets can be created and transferred in a single bitcoin UTXO, while witness data is transacted and stored off-chain.

Features

  • Mint and burn assets
  • Synchronize to universes
  • Send and receive assets
  • Export and import Taproot Asset proofs
  • Create and manage CLI profiles

How It Works

When minting a new asset, Taproot Assets will generate the relevant witness data, assign the asset to a key held by you and publish the corresponding bitcoin UTXO -- the minting transaction.

The outpoint this minting transaction consumes becomes the genesis_point of the newly minted asset, acting as its unique identifier. Assets can be spent to a new recipient, who provides the sender with the necessary information encoded in their Taproot Asset address.

To transact assets, the witnesses in the prior transaction are recommitted into one or multiple taproot outputs while the necessary witness data is passed to the recipient. Similar to bitcoin transactions, the remaining balance is spent back to the sender as a change output.

Learn more about the Taproot Assets Protocol.

Architecture

Taproot Assets are implemented as the Taproot Assets Daemon tapd and the Taproot Assets Command Line Interface tapcli. Additionally, tapd exposes a gRPC interface to allow for a direct integration into applications.

Taproot Assets leverage several lnd features including the Taproot wallet and signing capabilities. These facilities are accessed through lnd’s gRPC.

The Taproot Assets Stack

Bitcoin blockchain backend <-> lnd <-> tapd

Custody of Taproot Assets is segmented across lnd and tapd to maximize security. lnd holds the private key, which has had a taproot tweak applied to it, controlling the Bitcoin UTXO holding the Taproot Asset. The taproot tweak on the other hand is held by tapd. This increases the requirements for asset recovery as both the internal key as well as the taproot tweak are necessary to spend the output. This prevents lnd from accidentally burning Taproot assets.

Prerequisites

Taproot Assets require lnd version v0.20.0-beta or later to be synced and running on the same Bitcoin network as Taproot Assets (e.g. regtest, simnet, testnet3). RPC connections need to be accepted and a valid macaroon needs to be present.

$ git clone https://github.com/lightningnetwork/lnd.git
$ cd lnd
$ make install tags="signrpc walletrpc chainrpc invoicesrpc"

Installation

From Source

Compile Taproot Assets from source by cloning this repository. Go version 1.24 or higher is required.

$ git clone https://github.com/lightninglabs/taproot-assets.git
$ cd taproot-assets
$ make install

Initialization

Run Taproot Assets with the command tapd. Specify how Taproot Assets can reach lnd and what network to run tapd with by passing it additional flags. The Bitcoin backend and lnd need to be running and synced before the Taproot Assets daemon can be started.

$ tapd --network=testnet --debuglevel=debug \
    --lnd.host=localhost:10009 \
    --lnd.macaroonpath=~/.lnd/data/chain/bitcoin/testnet/admin.macaroon \
    --lnd.tlspath=~/.lnd/tls.cert

Usage

See a full list of options by executing:

$ tapd --help

Use tapcli to interact with tapd:

$ tapcli assets mint --type normal \
    --name fantasycoin --supply 100 --meta_bytes "fantastic money"
$ tapcli assets mint finalize
$ tapcli assets list

Synchronize yourself with a universe, for example the one running as part of the issuer's tapd.

$ tapcli universe sync --universe_host testnet.universe.lightning.finance

Add multiple universes to your local federation to always stay up to date. You can also use the universe to query existing assets and their metadata. You may also configure your tapd instance to listen to incoming requests with --rpclisten 0.0.0.0:10029 to run your own universe.

$ tapcli universe federation add \
    --universe_host testnet.universe.lightning.finance
$ tapcli universe roots

Once you have obtained the necessary proofs and asset IDs, you can generate a Taproot Asset address for a specific asset and amount.

$ tapcli addrs new --asset_id bab08407[...]129bf6d0 --amt 21

The sender can now fulfill the request by initiating the transfer:

$ tapcli assets send --addr taptb1q[...]tywpre3a

Development

API

Taproot Assets exposes a gRPC (port 10029) and a REST (port 8089) API. Connections are encrypted with TLS and authenticated using macaroons. The API is documented here, and further guides can be found here.

Mainnet

tapd has supported mainnet since version v0.3.0.

IMPORTANT NOTE: To avoid loss of funds, it's imperative that you read the Operational Safety Guidelines before using tapd on mainnet!

The daemon is still in alpha state, which means there can still be bugs and not all desired data safety and backup mechanisms have been implemented yet.

Important Note for Umbrel and Lightning Terminal Users

DO NOT UNDER ANY CIRCUMSTANCE uninstall (or re-install) the "Lightning Terminal" app without first making a manual backup of all local tapd data, if you are using Taproot Assets as part of the "Lightning Terminal" app with Umbrel -- or any comparable node-in-a-box solution. Uninstalling Umbrel apps deletes application data. This Taproot Assets application data encumbers Taproot Assets AND bitcoin funds. Receiving and sending tapd assets updates the daemon's funds-custody material. Merely having the lnd seed phrase is NOT enough to restore assets minted or received.

WITHOUT BACKUP BEFORE DELETION, FUNDS ARE DESTROYED.

RFQ and Price Oracle System

Everything related to the RFQ (Request For Quote) system, the asset's currency precision (decimal display) and the RFQ price oracle can be found in this document.

Bug Reports and Feature Requests

Please use the GitHub issue tracker to report bugs, or to request specific improvements.

Join us on Slack

Join us in the Lightning Labs Slack and join the #taproot-assets channel to ask questions and interact with the community.

Documentation

Index

Constants

View Source
const (
	// AppMajor defines the major version of this binary.
	AppMajor uint = 0

	// AppMinor defines the minor version of this binary.
	AppMinor uint = 8

	// AppPatch defines the application patch for this binary.
	AppPatch uint = 0

	// AppStatus defines the release status of this binary (e.g. beta).
	AppStatus = "alpha"

	// AppPreRelease defines the pre-release version of this binary.
	// It MUST only contain characters from the semantic versioning spec.
	AppPreRelease = "rc1"

	// GitTagIncludeStatus indicates whether the status should be included
	// in the git tag name.
	//
	// Including the app version status in the git tag may be problematic
	// for golang projects when importing them as dependencies. We therefore
	// include this flag to allow toggling the status on and off in a
	// standardised way across our projects.
	GitTagIncludeStatus = false
)

These constants define the application version and follow the semantic versioning 2.0.0 spec (http://semver.org/).

Variables

View Source
var (
	// Commit stores the current commit of this build, which includes the
	// most recent tag, the number of commits since that tag (if non-zero),
	// the commit hash, and a dirty marker. This should be set using the
	// -ldflags during compilation.
	Commit string

	// CommitHash stores the current commit hash of this build.
	CommitHash string

	// RawTags contains the raw set of build tags, separated by commas.
	RawTags string

	// GoVersion stores the go version that the executable was compiled
	// with.
	GoVersion string
)

Functions

func AddSubLogger

func AddSubLogger(root *build.SubLoggerManager, subsystem string,
	interceptor signal.Interceptor, useLoggers ...func(btclog.Logger))

AddSubLogger is a helper method to conveniently create and register the logger of one or more sub systems.

func SetAgentName

func SetAgentName(newAgentName string)

SetAgentName overwrites the default agent name which can be used to identify the software tapd is bundled in (for example LiT). This function panics if the agent name contains characters outside of the allowed semantic alphabet.

func SetSubLogger

func SetSubLogger(root *build.SubLoggerManager, subsystem string,
	logger btclog.Logger, useLoggers ...func(btclog.Logger))

SetSubLogger is a helper method to conveniently register the logger of a sub system.

func SetupLoggers

func SetupLoggers(root *build.SubLoggerManager,
	interceptor signal.Interceptor)

SetupLoggers initializes all package-global logger variables.

func Tags

func Tags() []string

Tags returns the list of build tags that were compiled into the executable.

func UserAgent

func UserAgent(initiator string) string

UserAgent returns the full user agent string that identifies the software that is submitting swaps to the loop server.

func Version

func Version() string

Version returns the application version as a properly formed string per the semantic versioning 2.0.0 spec (http://semver.org/).

Types

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the main daemon construct for the Taproot Asset server. It handles spinning up the RPC sever, the database, and any other components that the Taproot Asset server needs to function.

func NewServer

func NewServer(chainParams *address.ChainParams) *Server

NewServer creates a new server.

func (*Server) ApplyHtlcView added in v0.4.0

func (s *Server) ApplyHtlcView(
	in lnwl.CommitDiffAuxInput) lfn.Result[lfn.Option[tlv.Blob]]

ApplyHtlcView serves as the state transition function for the custom channel's blob. Given the old blob, and an HTLC view, then a new blob should be returned that reflects the pending updates.

NOTE: This method is part of the lnwallet.AuxLeafStore interface.

func (*Server) AuxCloseOutputs added in v0.4.0

func (s *Server) AuxCloseOutputs(
	desc types.AuxCloseDesc) (lfn.Option[chancloser.AuxCloseOutputs],
	error)

AuxCloseOutputs returns the set of close outputs to use for this co-op close attempt. We'll add some extra outputs to the co-op close transaction, and also give the caller a custom sorting routine.

NOTE: This method is part of the types.AuxChanCloser interface.

func (*Server) CanHandle added in v0.4.0

func (s *Server) CanHandle(msg msgmux.PeerMsg) bool

CanHandle returns true if the target message can be routed to this endpoint.

NOTE: This method is part of the msgmux.MsgEndpoint interface.

func (*Server) ChannelFinalized added in v0.4.0

func (s *Server) ChannelFinalized(pid funding.PendingChanID) error

ChannelFinalized is called once we receive the commit sig from a remote party and find it to be valid.

NOTE: This method is part of the funding.AuxFundingController interface.

func (*Server) ChannelReady added in v0.4.0

func (s *Server) ChannelReady(openChan lnwl.AuxChanState) error

ChannelReady is called when a channel has been fully opened and is ready to be used. This can be used to perform any final setup or cleanup.

NOTE: This method is part of the funding.AuxFundingController interface.

func (*Server) DeriveSweepAddr added in v0.4.0

func (s *Server) DeriveSweepAddr(inputs []input.Input,
	change lnwl.AddrWithKey) lfn.Result[sweep.SweepOutput]

DeriveSweepAddr takes a set of inputs, and the change address we'd use to sweep them, and maybe results in an extra sweep output that we should add to the sweeping transaction.

NOTE: This method is part of the sweep.AuxSweeper interface.

func (*Server) DeriveTapscriptRoot added in v0.4.0

func (s *Server) DeriveTapscriptRoot(
	pid funding.PendingChanID) funding.AuxTapscriptResult

DeriveTapscriptRoot takes a pending channel ID and maybe returns a tapscript root that should be used when creating any MuSig2 sessions for a channel.

NOTE: This method is part of the funding.AuxFundingController interface.

func (*Server) DescFromPendingChanID added in v0.4.0

func (s *Server) DescFromPendingChanID(pid funding.PendingChanID,
	chanState lnwl.AuxChanState,
	keyRing lntypes.Dual[lnwl.CommitmentKeyRing],
	initiator bool) funding.AuxFundingDescResult

DescFromPendingChanID takes a pending channel ID, that may already be known due to prior custom channel messages, and maybe returns an aux funding desc which can be used to modify how a channel is funded.

NOTE: This method is part of the funding.AuxFundingController interface.

func (*Server) ExtraBudgetForInputs added in v0.5.0

func (s *Server) ExtraBudgetForInputs(
	inputs []input.Input) lfn.Result[btcutil.Amount]

ExtraBudgetForInputs takes a set of inputs and maybe returns an extra budget that should be added to the sweep transaction.

NOTE: This method is part of the sweep.AuxSweeper interface.

func (*Server) FetchLeavesFromCommit added in v0.4.0

func (s *Server) FetchLeavesFromCommit(chanState lnwl.AuxChanState,
	com channeldb.ChannelCommitment, keys lnwl.CommitmentKeyRing,
	whoseCommit lntypes.ChannelParty) lfn.Result[lnwl.CommitDiffAuxResult]

FetchLeavesFromCommit attempts to fetch the auxiliary leaves that correspond to the passed aux blob, and an existing channel commitment.

NOTE: This method is part of the lnwallet.AuxLeafStore interface. nolint:lll

func (*Server) FetchLeavesFromRevocation added in v0.4.0

func (s *Server) FetchLeavesFromRevocation(
	r *channeldb.RevocationLog) lfn.Result[lnwl.CommitDiffAuxResult]

FetchLeavesFromRevocation attempts to fetch the auxiliary leaves from a channel revocation that stores balance + blob information.

NOTE: This method is part of the lnwallet.AuxLeafStore interface.

func (*Server) FetchLeavesFromView added in v0.4.0

func (s *Server) FetchLeavesFromView(
	in lnwl.CommitDiffAuxInput) lfn.Result[lnwl.CommitDiffAuxResult]

FetchLeavesFromView attempts to fetch the auxiliary leaves that correspond to the passed aux blob, and pending fully evaluated HTLC view.

NOTE: This method is part of the lnwallet.AuxLeafStore interface.

func (*Server) FinalizeClose added in v0.4.0

func (s *Server) FinalizeClose(desc types.AuxCloseDesc,
	closeTx *wire.MsgTx) error

FinalizeClose is called once the co-op close transaction has been agreed upon. We'll finalize the exclusion proofs, then send things off to the custodian or porter to finish sending/receiving the proofs.

NOTE: This method is part of the types.AuxChanCloser interface.

func (*Server) GetInitRecords added in v0.7.0

func (s *Server) GetInitRecords(
	peer route.Vertex) (lnwire.CustomRecords, error)

GetInitRecords is called when sending an init message to a peer. It returns custom records to include in the init message TLVs. The implementation can decide which records to include based on the peer identity.

func (*Server) InlineParseCustomData added in v0.4.0

func (s *Server) InlineParseCustomData(msg proto.Message) error

InlineParseCustomData replaces any custom data binary blob in the given RPC message with its corresponding JSON formatted data. This transforms the binary (likely TLV encoded) data to a human-readable JSON representation (still as byte slice).

NOTE: This method is part of the lnd.AuxDataParser interface.

func (*Server) IsCustomHTLC added in v0.5.1

func (s *Server) IsCustomHTLC(htlcRecords lnwire.CustomRecords) bool

IsCustomHTLC returns true if the HTLC carries the set of relevant custom records to put it under the purview of the traffic shaper, meaning that it's from a custom channel.

NOTE: This method is part of the routing.TlvTrafficShaper interface.

func (*Server) Name added in v0.4.0

func (s *Server) Name() msgmux.EndpointName

Name returns the name of this endpoint. This MUST be unique across all registered endpoints.

NOTE: This method is part of the msgmux.MsgEndpoint interface.

func (*Server) NotifyBroadcast added in v0.4.0

func (s *Server) NotifyBroadcast(req *sweep.BumpRequest,
	tx *wire.MsgTx, fee btcutil.Amount,
	outpointToTxIndex map[wire.OutPoint]int) error

NotifyBroadcast is used to notify external callers of the broadcast of a sweep transaction, generated by the passed BumpRequest.

NOTE: This method is part of the sweep.AuxSweeper interface.

func (*Server) PackSigs added in v0.4.0

func (s *Server) PackSigs(
	blob []lfn.Option[tlv.Blob]) lfn.Result[lfn.Option[tlv.Blob]]

PackSigs takes a series of aux signatures and packs them into a single blob that can be sent alongside the CommitSig messages.

NOTE: This method is part of the lnwallet.AuxSigner interface.

func (*Server) PaymentBandwidth added in v0.4.0

func (s *Server) PaymentBandwidth(fundingBlob, htlcBlob,
	commitmentBlob lfn.Option[tlv.Blob], linkBandwidth,
	htlcAmt lnwire.MilliSatoshi, htlcView lnwallet.AuxHtlcView,
	peer route.Vertex) (lnwire.MilliSatoshi, error)

PaymentBandwidth returns the available bandwidth for a custom channel decided by the given channel aux blob and HTLC blob. A return value of 0 means there is no bandwidth available. To find out if a channel is a custom channel that should be handled by the traffic shaper, the HandleTraffic method should be called first.

NOTE: This method is part of the routing.TlvTrafficShaper interface.

func (*Server) ProcessChannelReady added in v0.7.0

func (s *Server) ProcessChannelReady(cid lnwire.ChannelID, peer route.Vertex)

ProcessChannelReady handles the event of marking a channel identified by its channel ID as ready to use. We also provide the peer the channel was established with.

func (*Server) ProcessInitRecords added in v0.7.0

func (s *Server) ProcessInitRecords(peer route.Vertex,
	customRecords lnwire.CustomRecords) error

ProcessInitRecords handles received init records from a peer. The implementation can store state internally to affect future channel operations with this peer.

func (*Server) ProcessReestablish added in v0.7.0

func (s *Server) ProcessReestablish(cid lnwire.ChannelID, peer route.Vertex)

ProcessReestablishFeatures handles received channel_reestablish feature TLVs. This is a blocking call - the channel link will wait for this method to complete before continuing channel operations. The implementation can modify aux channel behavior based on the negotiated features.

func (*Server) ProduceHtlcExtraData added in v0.4.0

func (s *Server) ProduceHtlcExtraData(totalAmount lnwire.MilliSatoshi,
	htlcCustomRecords lnwire.CustomRecords,
	peer route.Vertex) (lnwire.MilliSatoshi, lnwire.CustomRecords, error)

ProduceHtlcExtraData is a function that, based on the previous custom record blob of an HTLC, may produce a different blob or modify the amount of bitcoin this HTLC should carry.

NOTE: This method is part of the routing.TlvTrafficShaper interface.

func (*Server) RegisterGrpcService added in v0.7.0

func (s *Server) RegisterGrpcService(registrar grpc.ServiceRegistrar)

RegisterGrpcService must register the sub-server's GRPC server with the given registrar.

NOTE: this is part of the SubServer interface.

func (*Server) RegisterRestService added in v0.7.0

func (s *Server) RegisterRestService(ctx context.Context, mux *proxy.ServeMux,
	endpoint string, dialOpts []grpc.DialOption) error

RegisterRestService registers the sub-server's REST handlers with the given endpoint.

NOTE: this is part of the SubServer interface.

func (*Server) ResolveContract added in v0.4.0

func (s *Server) ResolveContract(req lnwl.ResolutionReq) lfn.Result[tlv.Blob]

ResolveContract attempts to obtain a resolution blob for the specified contract.

NOTE: This method is part of the lnwallet.AuxContractResolver interface.

func (*Server) RunUntilShutdown

func (s *Server) RunUntilShutdown(mainErrChan <-chan error) error

RunUntilShutdown runs the main Taproot Asset server loop until a signal is received to shut down the process.

func (*Server) SendMessage added in v0.4.0

func (s *Server) SendMessage(ctx context.Context, msg msgmux.PeerMsg) bool

SendMessage handles the target message, and returns true if the message was able to be processed.

NOTE: This method is part of the msgmux.MsgEndpoint interface.

func (*Server) ShouldHandleTraffic added in v0.5.0

func (s *Server) ShouldHandleTraffic(cid lnwire.ShortChannelID,
	fundingBlob, htlcBlob lfn.Option[tlv.Blob]) (bool, error)

ShouldHandleTraffic is called in order to check if the channel identified by the provided channel ID is handled by the traffic shaper implementation. If it is handled by the traffic shaper, then the normal bandwidth calculation can be skipped and the bandwidth returned by PaymentBandwidth should be used instead.

NOTE: This method is part of the routing.TlvTrafficShaper interface.

func (*Server) ShutdownBlob added in v0.4.0

func (s *Server) ShutdownBlob(
	req types.AuxShutdownReq) (lfn.Option[lnwire.CustomRecords],
	error)

ShutdownBlob returns the set of custom records that should be included in the shutdown message.

NOTE: This method is part of the types.AuxChanCloser interface.

func (*Server) StartAsSubserver

func (s *Server) StartAsSubserver(lndGrpc *lndclient.GrpcLndServices) error

StartAsSubserver is an alternative to Start where the RPC server does not create its own gRPC server but registers to an existing one. The same goes for REST (if enabled), instead of creating an own mux and HTTP server, we register to an existing one.

func (*Server) Stop

func (s *Server) Stop() error

Stop signals that the main tapd server should attempt a graceful shutdown.

func (*Server) SubmitSecondLevelSigBatch added in v0.4.0

func (s *Server) SubmitSecondLevelSigBatch(chanState lnwl.AuxChanState,
	commitTx *wire.MsgTx, sigJob []lnwl.AuxSigJob) error

SubmitSecondLevelSigBatch takes a batch of aux sign jobs and processes them asynchronously.

NOTE: This method is part of the lnwallet.AuxSigner interface.

func (*Server) UnpackSigs added in v0.4.0

func (s *Server) UnpackSigs(
	blob lfn.Option[tlv.Blob]) lfn.Result[[]lfn.Option[tlv.Blob]]

UnpackSigs takes a packed blob of signatures and returns the original signatures for each HTLC, keyed by HTLC index.

NOTE: This method is part of the lnwallet.AuxSigner interface.

func (*Server) UpdateConfig added in v0.4.0

func (s *Server) UpdateConfig(cfg *tapconfig.Config)

UpdateConfig updates the server's configuration. This MUST be called before the server is started.

func (*Server) ValidateMacaroon

func (s *Server) ValidateMacaroon(ctx context.Context,
	requiredPermissions []bakery.Op, fullMethod string) error

ValidateMacaroon extracts the macaroon from the context's gRPC metadata, checks its signature, makes sure all specified permissions for the called method are contained within and finally ensures all caveat conditions are met. A non-nil error is returned if any of the checks fail. This method is needed to enable tapd running as an external subserver in the same process as lnd but still validate its own macaroons.

func (*Server) VerifySecondLevelSigs added in v0.4.0

func (s *Server) VerifySecondLevelSigs(chanState lnwl.AuxChanState,
	commitTx *wire.MsgTx, verifyJob []lnwl.AuxVerifyJob) error

VerifySecondLevelSigs attempts to synchronously verify a batch of aux sig jobs.

NOTE: This method is part of the lnwallet.AuxSigner interface.

type ValidatorV0

type ValidatorV0 struct{}

ValidatorV0 is an implementation of the tapscript.TxValidator interface that supports Taproot Asset script version 0.

func (*ValidatorV0) Execute

func (v *ValidatorV0) Execute(newAsset *asset.Asset,
	splitAssets []*commitment.SplitAsset, prevAssets commitment.InputSet,
	chainLookup asset.ChainLookup) error

Execute creates and runs an instance of the Taproot Asset script V0 VM.

type WitnessValidatorV0 added in v0.4.0

type WitnessValidatorV0 struct{}

WitnessValidatorV0 is an implementation of the tapscript.WitnessValidator interface that supports Taproot Asset script version 0.

func (*WitnessValidatorV0) ValidateWitnesses added in v0.4.0

func (v *WitnessValidatorV0) ValidateWitnesses(newAsset *asset.Asset,
	splitAssets []*commitment.SplitAsset,
	prevAssets commitment.InputSet) error

ValidateWitnesses validates the created witnesses of an asset transfer.

Directories

Path Synopsis
Package backup implements wallet asset backup and restore functionality.
Package backup implements wallet asset backup and restore functionality.
cmd
tapcli command
tapd command
tapd-integrated command
Package main implements a minimal integrated daemon that runs lnd and tapd in the same process.
Package main implements a minimal integrated daemon that runs lnd and tapd in the same process.
docs
examples/basic-portfolio-pilot command
WARNING: This is a demonstration example only and is NOT suitable for production use.
WARNING: This is a demonstration example only and is NOT suitable for production use.
Package healthcheck contains a monitor which takes a set of liveness checks which it periodically checks.
Package healthcheck contains a monitor which takes a set of liveness checks which it periodically checks.
Package integration provides the glue layer for running lnd with tapd's custom channel support.
Package integration provides the glue layer for running lnd with tapd's custom channel support.
internal
nolint:lll
nolint:lll
taprpc module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL