Skip to content

multi: Add the embedded Taproot Assets backend - #1583

Open
darioAnongba wants to merge 11 commits into
mainfrom
darioAnongba/assets-embedded-backend
Open

darioAnongba wants to merge 11 commits into
mainfrom
darioAnongba/assets-embedded-backend

Conversation

@darioAnongba

@darioAnongba darioAnongba commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

assets.backend=embedded runs Taproot Assets inside waved. The daemon holds, verifies and moves assets on its own seed, chain backend and database, with no tapd or lnd beside it, so the same code serves the desktop daemon, the gomobile bindings and the js/wasm build. The backend is tap-sdk's in-process engine (lightninglabs/tap-sdk#197), and waved's asset code keeps calling the tap-sdk interface it calls on the tapd backend.

  • Ports. The engine takes its keys from the wallet's keychain.SecretKeyRing, its headers and broadcast from the chain backend, and its storage from db.AssetEngineStore (migration 31). It follows a transfer's confirmation through the chain source actor, which orders the events of every backend and reports finality, so tracking a transfer ends on the light wallet too. The Esplora and neutrino backends serve block headers by height through the new chainsource.BlockHeaderSource. The wallet can still be locked when the backend starts, so the ports resolve the wallet on each call, and the engine resumes its transfers once the wallet services are up.
  • Verification. tapassets.LocalProofChainVerifier checks a confirmed proof with the engine. A grouped asset verifies only for a trusted group: one listed in assets.groupkeys, the group of the asset a request names, or the group of an asset the wallet holds.
  • Asset wallet. NewAssetReceiveKeys, ImportAssetProof and ListOwnedAssets receive an asset on chain and list the holdings. They go through tap-sdk, so they serve the tapd backend too. The engine is given only a proof file that verifies, while tapd verifies each proof as the import inserts it. NewAssetFundingAddress returns a backing-wallet address for the Bitcoin a deposit spends, which a wallet SDK host cannot learn otherwise.
  • Deposits. DepositAsset and BoardAssetDeposit run on the engine through the existing onboarding code. The engine signs its anchor inputs with keys of the daemon's seed, so the tapd version check does not apply to it, and the deposit journal lives in the database, since a browser has no files. Claims stay on the tapd backend: ClaimAssetDeposit returns FailedPrecondition on the engine.
  • SDK. assets_backend and asset_group_keys reach the daemon from the wallet SDK, the mobile facade and the wasm entry point, which also gain the asset verbs. Asset amounts are decimal strings in the JSON of the asset types, since they can exceed what a JavaScript number holds exactly.

The backend requires wallet.type lwwallet or btcwallet and is refused outside regtest. assets.backend still defaults to none.

TestEmbeddedAssetDeposit covers the lifecycle on a daemon with a light wallet: fund, receive from a tapd, deposit, change, restart and board, with the tapd verifying the proof the engine wrote. The same lifecycle also ran through the gomobile bindings inside an iOS app in the simulator.

@darioAnongba
darioAnongba force-pushed the darioAnongba/assets-embedded-backend branch from 581e559 to 2a6fdbe Compare November 11, 2026 22:40
@darioAnongba darioAnongba self-assigned this Nov 12, 2026
@darioAnongba
darioAnongba marked this pull request as ready for review November 12, 2026 13:42
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-12T13:45:03.425307Z 2a6fdbe Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2a6fdbef48

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread waved/asset_engine.go Outdated
Comment on lines +315 to +319
case <-registration.Done:
select {
case done <- struct{}{}:
case <-quit:
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Forward the buffered confirmation before terminating on Done

When the btcwallet backend registers a transaction already beyond its reorg-safety depth, such as when resuming an old transfer after restart, btcwbackend.ChainBackend.RegisterConf can buffer both Confirmed and Done before this goroutine runs. Go's select can choose Done first, and this branch then exits without forwarding the buffered confirmation or its block. The embedded engine consequently cannot reconstruct the transfer's confirmed proofs. Preserve a pending terminal signal until the positive confirmation has been forwarded, as chainsource.ConfActor does with PositiveDoneOrder, and distinguish channel closure from an actual finality event.

Useful? React with 👍 / 👎.

@darioAnongba
darioAnongba force-pushed the darioAnongba/asset-deposit-funding branch 2 times, most recently from 95ea542 to 72b8437 Compare November 13, 2026 12:32
@darioAnongba
darioAnongba force-pushed the darioAnongba/assets-embedded-backend branch from 2a6fdbe to 3e67b69 Compare November 13, 2026 17:00
@darioAnongba
darioAnongba force-pushed the darioAnongba/asset-deposit-funding branch from 72b8437 to cf3f739 Compare November 13, 2026 19:26
@darioAnongba
darioAnongba force-pushed the darioAnongba/assets-embedded-backend branch from 3e67b69 to 4c4dee2 Compare November 13, 2026 19:34
@darioAnongba

Copy link
Copy Markdown
Collaborator Author

/gateway review

@lightninglabs-gateway

lightninglabs-gateway Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

❌ gateway review failed: code-review skill failed across all auth modes: You've hit your weekly limit · resets Nov 15, 6am (UTC)

See workflow logs for details.

Verifying a Taproot Asset proof means checking that each anchor block is
on the best chain at its claimed height. BlockHeaderSource is the
optional chain backend interface for that lookup, and the Esplora and
neutrino backends implement it.
The embedded asset engine keeps its keys, proof files and transfers in
the daemon's database, because a browser offers one exclusive database
connection and no files. asset_journal holds the deposit journal for
the same reason.
AssetEngineStore implements the store of tap-sdk's embedded engine on
the asset engine tables, and keeps the asset deposit journal. Lookups
that find nothing return after their transaction, so an unknown key
does not log as a failed transaction.
A backend that verifies proofs against its own chain view and trusted
groups needs no issuance fallback, so its verifier asks it once and
never writes to it.
@darioAnongba
darioAnongba changed the base branch from darioAnongba/asset-deposit-funding to main November 13, 2026 20:48
assets.backend=embedded runs tap-sdk's asset engine inside the daemon,
so a daemon on a local wallet verifies asset VTXOs and deposits assets
with no tapd or lnd beside it. The engine takes its keys from the
wallet seed, chain data from the chain backend and storage from the
daemon's database, and the deposit journal moves into the database.

The backend requires wallet.type lwwallet or btcwallet, whose seed the
daemon holds, and is refused outside regtest.
NewAssetReceiveKeys, ImportAssetProof and ListOwnedAssets let a caller
receive a Taproot Asset on chain into the daemon's asset wallet and
list what it holds. A daemon without tapd has no other way to take in
an asset. NewAssetFundingAddress returns a backing-wallet address for
the Bitcoin an asset deposit spends.
The asset RPCs go through tap-sdk, so they serve the tapd backend and
the embedded one. ImportAssetProof checks that the proof is of the asset
the caller names before it stores anything, which is also how the
embedded backend learns to trust a grouped asset. NewAssetFundingAddress
returns an address of the wallet that pays for deposits.
Mobile and browser hosts reach the daemon only through the wallet SDK's
facade. The assets_backend config key selects the daemon's asset
backend, and the asset verbs cover funding, receiving, listing,
depositing and boarding assets.
The daemon runs on a light wallet with no tapd or lnd of its own. It
receives an asset from a tapd, deposits part of it, keeps the change,
restarts, and boards the deposit. The tapd verifies the proof the
engine wrote.
@darioAnongba
darioAnongba force-pushed the darioAnongba/assets-embedded-backend branch from 4c4dee2 to 85ee434 Compare November 13, 2026 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant