multi: add Taproot Asset OOR and onboarding prototype - #1033
multi: add Taproot Asset OOR and onboarding prototype#1033darioAnongba wants to merge 14 commits into
Conversation
Add a versioned sealed-package container and bind optional Taproot Asset roots to OOR input and recipient policies. Persist input and start-message roots so durable retries can reconstruct the same composed scripts.
Extend submit and offline-receive messages with optional asset roots and the versioned sealed-package container. Keep Bitcoin-only payloads backward compatible and validate asset bytes at the typed request boundary.
Accept externally committed OOR graphs, validate them before signing, and retain sealed Taproot Asset packages through durable actor messages, FSM states, snapshots, and byte-identical submit retries.
Store the optional Taproot Asset commitment root with each VTXO and derive composed policy scripts and spend control blocks for OOR, forfeit, and unilateral exit paths. Exclude asset-bearing rows from generic Bitcoin coin selection until rounds carry asset transitions.
Carry recipient commitment roots and sealed asset transition packages through offline receive, durable actor snapshots, VTXO materialization, and OOR artifact persistence. Preserve Bitcoin-only package behavior while requiring asset-aware stores for asset sessions.
Add a proof-selected public intent and a restart-safe preparer seam so Wavelength can commit an asset graph before its durable OOR actor signs it. Keep Bitcoin-only sends unchanged and reject unsupported change, missing adapters, and tampered results before actor submission.
Adapt the merged tap-sdk custom-anchor boundary to the Wavelength OOR graph. Verify the selected tapd inventory, commit both transitions, and persist outcome-aware replay state before the actor can sign.
Keep tapd credentials in the client daemon and install the adapter only after explicit configuration. Preserve embedded config isolation and document the PoC recovery and custody boundaries.
Document why ordinary round boarding cannot create the first asset-bearing VTXO and record the fully rebased client validation results.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fdb8aeea9c
ℹ️ 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".
| state.Registered = true | ||
| state.ConfirmationHeight = registration.ConfirmationHeight |
There was a problem hiding this comment.
Persist registration intent before calling the operator
If the operator successfully admits the anchor but the daemon crashes (or storeState fails) before Registered is persisted, the next retry enters this branch and invokes RegisterTaprootAssetVTXO again. That RPC carries no idempotency key, so an operator that rejects an already-admitted outpoint will make the published asset permanently fail onboarding instead of letting the client materialize it locally. Journal an in-progress registration phase before the external call and provide a way to reconcile or idempotently replay the resulting admission.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Code Review
This pull request introduces an experimental prototype for onboarding Taproot Assets into Wavelength VTXOs, adding new RPC endpoints (RegisterTaprootAssetVTXO and OnboardTaprootAsset), CLI commands, and database migrations to store Taproot Asset roots and transfer packages. It also updates the out-of-round (OOR) transfer logic to support asset-bearing transactions. Feedback on the changes highlights a potential issue in the VTXO insertion query (db/sqlc/queries/round.sql), where the taproot_asset_root is updated on conflict; since this root defines the output script, it should remain immutable to prevent inconsistencies with the on-chain state.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| commitment_txid = CASE WHEN excluded.commitment_txid IS NOT NULL AND length(excluded.commitment_txid) > 0 THEN excluded.commitment_txid ELSE vtxos.commitment_txid END, | ||
| last_update_time = excluded.last_update_time; | ||
| commitment_txid = CASE WHEN excluded.commitment_txid IS NOT NULL AND length(excluded.commitment_txid) > 0 THEN excluded.commitment_txid ELSE vtxos.commitment_txid END, | ||
| taproot_asset_root = CASE WHEN excluded.taproot_asset_root IS NOT NULL AND length(excluded.taproot_asset_root) > 0 THEN excluded.taproot_asset_root ELSE vtxos.taproot_asset_root END, |
There was a problem hiding this comment.
The taproot_asset_root is part of the definition of the VTXO's output script and should be immutable once the VTXO is created. Updating it on conflict could lead to inconsistencies with the on-chain state, as the output script of a confirmed transaction cannot change. This field should be treated like other immutable properties (e.g., amount, expiry) and not be updated on conflict.
|
@darioAnongba, remember to re-request review from reviewers when ready |
|
Superseded by #1062, which aggregates the full Taproot Asset OOR prototype stack (all files touched here are covered there). |
Summary
This is stack 1 of the Wavelength Taproot Assets PoC. It establishes the base single-input, send-all flow. Carrier-funded onboarding and managed carrier selection are separate follow-up PRs.
Architecture
Wavelength owns tapd access, proof selection, custom-anchor orchestration, signing, idempotency, and reconciliation. The operator receives only sealed packages, public policy data, and Bitcoin graph artifacts. Bitcoin-only paths remain unchanged.
Validation
A live cross-repository regtest is intentionally left to the Lumos harness follow-up.
Prototype limits
The base slice moves one complete isolated asset anchor, uses one asset input and one recipient with exact carrier sats, requires a shared LND wallet between tapd and waved for onboarding, and persists unconfirmed proof paths without claiming an asset-only UX.