BIP: ???
  Layer: Applications
  Title: Taproot Assets PSBT
  Author: Oliver Gugger 
          Olaoluwa Osuntokun 
  Comments-Summary: No comments yet.
  Comments-URI: https://git
  Status: Draft
  Type: Standards Track
  Created: 2023-02-24
  License: BSD-2-Clause
==Abstract== This document describes the custom fields used in the [[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki|Partially Signed Bitcoin Transaction (PSBT, BIP-0174)]] format for Taproot Asset state transition transactions. ==Copyright== This document is licensed under the 2-clause BSD license. ==Design== A Taproot Asset state transition transaction is also referred to as a "virtual transaction" or asset transfer transaction. The word "virtual" is used to distinguish between these asset transfers that only happen in the off-chain, asset overlay context as opposed to "anchor" transactions, which are BTC level on-chain transaction that commit many asset level transfers to the Bitcoin chain. A virtual transaction has many similarities to its Bitcoin wire transaction counterpart in that it spends one or more asset inputs (asset UTXOs or asset "coins") and creates one or more new asset outputs. The main difference to a Bitcoin transaction is that a virtual asset transaction does not place the witness that satisfies each input's previous output script in the input itself but instead uses the prev_asset_witnesses field of the dedicated output that houses the split root asset. This allows a many-in-many-out virtual transaction to be compressed into a 1-in-1-out transaction (as described in [[./bip-tap-vm.mediawiki|bip-tap-vm]]) for validation in the Taproot Asset Virtual Machine. To assemble the full witness stack that satisfies each input's previous output script the transaction might need to be signed by multiple parties and/or devices. This requires the virtual transaction to be passed around among multiple participants, each adding their part (e.g. signatures) to it. Given the similarities of virtual transactions to existing Bitcoin transactions, the PSBT format was chosen as the exchange format for virtual asset state transfers as well, with a set of new PSBT s as defined in this document. ==Specification== A virtual transaction can only contain inputs and outputs of assets that are fungible among each other. Assets are considered fungible if they either have the same genesis ID (were minted in the same tranche) or reference the same group_key (were minted in different tranches). Within a virtual transaction multiple inputs (asset coins) that have the '''same genesis ID''' can be merged and split the same way Bitcoin inputs can be merged and split again. Fungible assets with '''different genesis IDs''' (but same group_key) can be used together in the same virtual transaction in order to satisfy a payment request, but merging two fungible assets (with distinct asset IDs) into the _same_ asset UTXO is disallowed. See the [[./bip-tap-vm.mediawiki|bip-tap-vm]] for more details. The construction of the virtual transaction outputs must follow different rules depending on whether the output is received in an interactive or non-interactive way by the recipient: TODO(guggero): Describe how fungible assets are handled in a non-interactive way once that is defined. When splitting an asset UTXO a split commitment is created (as described in [[./bip-tap-vm.mediawiki|bip-tap-vm]]). The split root is placed in one of the outputs (often being the change output going back to the sender of the asset) and marked with the `IsSplitRoot` flag. If the remaining change of a split is 0, the script_key of the split root asset output should be the well-known NUMS point (using the string "taproot-assets" and the traditional "hash and increment" approach to generating the point) to prove the output cannot be spent further. This so-called "split tombstone" is required for non-interactive sends (send to Taproot Asset address) of the full value of a coin. These zero-value tombstone outputs can be pruned in an interactive scenario in which the recipient is a ware of the full root asset leaf (including the TX witness) and can construct the commitment tree root correctly. ==Custom PSBT fields for Taproot Asset virtual transactions== [[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki|BIP-0174]] defines roughly 6 global, 24 input and 7 output keytypes. This leaves enough room for new BIPs to specify additional types without a big risk of collision. The proprietary type 0xFX does not apply to this case as that is meant for application/vendor specific data, not fields declared in a BIP. To further reduce the risk of colliding with key types of other (in-flight) BIPs we start at the (arbitrarily chosen) value 0x70 for each section of new key types. ===Global types=== {| ! Name ! ! ! Description ! ! Description |- | Virtual Transaction Marker | PSBT_GLOBAL_TAP_IS_VIRTUAL_TX = 0x70 | None | No key data | | The static marker of 0x01 to identify this transaction as a Taproot Asset virtual transaction. |- | Taproot Asset Chain HRP | PSBT_GLOBAL_TAP_CHAIN_HRP = 0x71 | None | No key data | | The Human Readable Prefix of the Taproot Asset chain identifier as specified in [[./bip-tap-addr.mediawiki|bip-tap-addr]]. |- | Taproot Asset PSBT Version | PSBT_GLOBAL_TAP_PSBT_VERSION = 0x72 | None | No key data | | The version of the Taproot Asset PSBT format. Currently 0x00 is the only known and supported version. |} ===Input types=== {| ! Name ! ! ! Description ! ! Description |- | Previous Asset Leaf | PSBT_IN_TAP_PREV_ID = 0x70 | None | No key data | | The previous asset leaf (identified by prev_outpoint || asset_id || asset_script_hash) in TLV format as defined in [[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]]. |- | Anchor Output Value | PSBT_IN_TAP_ANCHOR_VALUE = 0x71 | None | No key data | <64-bit big endian int value> | The value in satoshis of the BTC level anchor output that committed to the asset input being spent. |- | Anchor Output pkScript | PSBT_IN_TAP_ANCHOR_PK_SCRIPT = 0x72 | None | No key data | | The pkScript of the BTC level anchor output that committed to the asset input being spent. |- | Anchor Output Sighash Type | PSBT_IN_TAP_ANCHOR_SIGHASH_TYPE = 0x73 | None | No key data | <64-bit big endian int sighash type> | The 64-bit big endian unsigned integer specifying the sighash type to be used for the BTC level anchor output that committed to the asset input being spent. |- | Anchor Output Taproot Internal Key | PSBT_IN_TAP_ANCHOR_TAP_INTERNAL_KEY = 0x74 | None | No key data | <32-byte xonlypubkey> | The X-only pubkey used as the internal key of the BTC level anchor output that committed to the asset input being spent. |- | Anchor Output Taproot Merkle Root | PSBT_IN_TAP_ANCHOR_TAP_MERKLE_ROOT = 0x75 | None | No key data | <32-byte hash> | The 32 byte Merkle root hash of the BTC level anchor output that committed to the asset input being spent. |- | Anchor Output BIP-0032 Derivation Path | PSBT_IN_TAP_ANCHOR_BIP32_DERIVATION = 0x76 | | The public key | <4 byte fingerprint> <32-bit little endian uint path element>* | The master key fingerprint as defined by BIP-0032 concatenated with the derivation path of the public key that was used for the BTC level anchor output that committed to the asset input being spent. The derivation path is represented as 32 bit unsigned integer indexes concatenated with each other. Public keys are those that will be needed to sign this input. |- | Anchor Output Taproot Key BIP 32 Derivation Path | PSBT_IN_TAP_ANCHOR_TAP_BIP32_DERIVATION = 0x77 | <32 byte xonlypubkey> | A 32 byte X-only public key involved in this input. It may be the output key, the internal key, or a key present in a leaf script. | <32 byte leaf hash>* <4 byte fingerprint> <32-bit little endian uint path element>* | A compact size unsigned integer representing the number of leaf hashes, followed by a list of leaf hashes, followed by the 4 byte master key fingerprint concatenated with the derivation path of the public key. The derivation path is represented as 32-bit little endian unsigned integer indexes concatenated with each other. Public keys are those needed to spend this output. The leaf hashes are of the leaves which involve this public key. The internal key does not have leaf hashes, so can be indicated with a hashes len of 0. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed. |- | Anchor Output Tapscript Sibling | PSBT_IN_TAP_ANCHOR_TAPSCRIPT_SIBLING = 0x78 | None | No key data | | The preimage of the tapscript sibling that is on the same level as the Taproot Asset commitment that was committed to in the anchor. If this is not present, then the Taproot Asset commitment is the only script leaf in the tree. |- | Taproot Asset Asset | PSBT_IN_TAP_ASSET = 0x79 | None | No key data | | The full input asset leaf that is being spent, in TLV format as defined in [[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]]. |- | Taproot Asset Proof | PSBT_IN_TAP_ASSET_PROOF = 0x7a | None | No key data | | The last proof of the input asset being spent, in TLV format as defined in [[./bip-tap-proof-file.mediawiki#file-serialization| bip-tap-proof-file File Serialization]]. |} ===Output types=== {| ! Name ! ! ! Description ! ! Description |- | Type | PSBT_OUT_TAP_TYPE = 0x70 | None | No key data | | A uint8 value indicating the type of the virtual output. Valid values are: 0x00 (Simple), 0x01 (SplitRoot), 0x02 (PassiveAssetsOnly), 0x03 (PassiveSplitRoot), see description below. |- | Is Interactive | PSBT_OUT_TAP_IS_INTERACTIVE = 0x71 | None | No key data | | A boolean value indicating whether the recipient of the output is aware of the full asset leaf they are receiving (=interactive) or not (=non-interactive). In the non-interactive case, the recipient will expect this output to be a split output. |- | Anchor Output Index | PSBT_OUT_TAP_ANCHOR_OUTPUT_INDEX = 0x72 | None | No key data | <64-bit big endian int value> | The Bitcoin level anchor transaction output index this asset output is going to be committed to. |- | Anchor Output Taproot Internal Key | PSBT_OUT_TAP_ANCHOR_TAP_INTERNAL_KEY = 0x73 | None | No key data | <32-byte xonlypubkey> | The X-only pubkey used as the internal key of the BTC level anchor output that will be committing to the asset output. |- | Anchor Output BIP-0032 Derivation Path | PSBT_OUT_TAP_ANCHOR_BIP32_DERIVATION = 0x74 | | The public key | <4 byte fingerprint> <32-bit little endian uint path element>* | The master key fingerprint as defined by BIP-0032 concatenated with the derivation path of the public key that will be used for the BTC level anchor output that is committing to the asset output. The derivation path is represented as 32 bit unsigned integer indexes concatenated with each other. Public keys are those that will be needed to sign this input. |- | Anchor Output Taproot Key BIP-0032 Derivation Path | PSBT_OUT_TAP_ANCHOR_TAP_BIP32_DERIVATION = 0x75 | <32 byte xonlypubkey> | A 32 byte X-only public key involved in this input. It may be the output key, the internal key, or a key present in a leaf script. | <32 byte leaf hash>* <4 byte fingerprint> <32-bit little endian uint path element>* | A compact size unsigned integer representing the number of leaf hashes, followed by a list of leaf hashes, followed by the 4 byte master key fingerprint concatenated with the derivation path of the public key. The derivation path is represented as 32-bit little endian unsigned integer indexes concatenated with each other. Public keys are those needed to spend this output. The leaf hashes are of the leaves which involve this public key. The internal key does not have leaf hashes, so can be indicated with a hashes len of 0. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed. |- | Taproot Asset | PSBT_OUT_TAP_ASSET = 0x76 | None | No key data | | The full output asset leaf being created, in TLV format as defined in [[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]]. |- | Taproot Asset Split Asset | PSBT_OUT_TAP_SPLIT_ASSET = 0x77 | None | No key data | | In case the asset serialized in the PSBT_OUT_TAP_ASSET is a split root (PSBT_OUT_TAP_IS_SPLIT_ROOT=0x01), this field houses the created split asset at the root locator that contains the split commitment witness. This is used for validation only and isn't committed to in any tree. If present the split asset is encoded in TLV format as defined in [[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]]. |- | Anchor Output Tapscript Sibling | PSBT_OUT_TAP_ANCHOR_TAPSCRIPT_SIBLING = 0x78 | None | No key data | | The preimage of the tapscript sibling that is on the same level as the Taproot Asset commitment that was committed to in the anchor. If this is not present, then the Taproot Asset commitment is the only script leaf in the tree. |- | Taproot Asset Version | PSBT_OUT_TAP_ASSET_VERSION = 0x79 | None | No key data | | The asset version to be used for the specified TAP output. |} ===Values for PSBT_OUT_TAP_TYPE=== The PSBT_OUT_TAP_TYPE field describes the type of virtual output. This type has an influence on how an asset needs to be signed or whether there is an asset at all in an output. The following values are defined: ==Committing Taproot Asset virtual transactions into a BTC level anchor transaction== The above section defined new fields for representing a virtual asset transaction. This section explains how one or multiple virtual asset transactions can be mapped to and be committed to in a single Bitcoin level on-chain "anchor" transaction. The following steps should be taken for committing one or more Taproot Asset virtual transactions onto a single BTC anchor transaction: # Sign the virtual transaction as described in [[./bip-tap.mediawiki|bip-tap]]. # Validate that each input in each virtual transaction has the necessary anchor information set (PSBT_IN_TAP_ANCHOR_*). # Validate that each output in each virtual transaction has the necessary anchor information set (PSBT_OUT_TAP_ANCHOR_*). # Validate that each virtual input's anchor information referencing the same previous outpoint (PSBT_IN_TAP_PREV_ID.prev_outpoint) is the same as all fields should refer to the same on-chain unspent output. # Validate that each virtual output's anchor information referencing the same anchor output index (PSBT_OUT_TAP_ANCHOR_OUTPUT_INDEX) is the same as all fields should refer to the same on-chain output being created. # For each input, add the last transition proof of the input asset to the BTC anchor PSBT input (field PSBT_IN_TAP_PROOF). # For each unique anchor output index, create an output on the BTC anchor transaction: ## Merge all assets into a single Taproot Asset tree. ## If a Tapscript sibling is present for the BTC anchor output, verify it is not a Taproot Asset commitment. ## Calculate the merkle root hash from the merged Taproot Asset tree and the optional Tapscript sibling. ## Calculate the Taproot output key from the internal key and the merkle root hash, update the pkScript of the BTC anchor output. # Create a single transition proof for each of the virtual transaction outputs and add them to the BTC anchor output, keyed by each asset's script_key (field PSBT_OUT_TAP_PROOF). Once the BTC level anchor transaction has the extra information attached, it can then be passed to all signers to produce the necessary signatures for getting it finalized. ==Custom PSBT fields for BTC level anchor transactions== ===Input types=== {| ! Name ! ! ! Description ! ! Description |- | Taproot Asset Proof | PSBT_IN_TAP_PROOF = 0x70 | <32 byte xonlyscriptkey> | The 32 byte X-only script key of the input asset being spent. | | The last proof of the input asset being spent, in TLV format as defined in [[./bip-tap-proof-file.mediawiki#file-serialization|bip-tap-proof-file File Serialization]]. |} ===Output types=== {| ! Name ! ! ! Description ! ! Description |- | Taproot Asset Proof | PSBT_OUT_TAP_PROOF = 0x70 | <32 byte xonlyscriptkey> | The 32 byte X-only script key of the input asset being spent. | | The new transition proof(s) for the new asset(s) created in this output. |} ==Test Vectors== Test vectors for [[Custom PSBT fields for Taproot Asset virtual transactions]] can be found here: * [[bip-tap-psbt/psbt_encoding_generated.json|PSBT encoding test vectors]] * [[bip-tap-psbt/psbt_encoding_error_cases.json|PSBT encoding error test vectors]] The test vectors are automatically generated by [https://github.com/lightninglabs/taproot-assets/tree/main/tappsbt unit tests in the Taproot Assets GitHub repository]. ==Reference Implementation== github.com/lightninglabs/taproot-assets/tree/main/tappsbt