Skip to content

Latest commit

 

History

History
182 lines (149 loc) · 9.42 KB

bip-tap-addr.mediawiki

File metadata and controls

182 lines (149 loc) · 9.42 KB

 BIP: ???
  Layer: Applications
  Title: Taproot Asset On Chain Addresses
  Author: Olaoluwa Osuntokun <laolu32@gmail.com>
  Comments-Summary: No comments yet.
  Comments-URI: https://git
  Status: Draft
  Type: Standards Track
  Created: 2021-12-10
  License: BSD-2-Clause

Table of Contents

Abstract

This document describes a way to map a single-asset Taproot Asset send to a familiar bech32m address, as well as a way to map that address into a valid Taproot Asset script tree that can be included in a broadcast transaction to complete a transfer. Once the transaction has been broadcast, the receiver can use the previous outpoint of the confirmed transaction to lookup the complete asset proof in their chosen Universe.

Copyright

This document is licensed under the 2-clause BSD license.

Motivation

The Taproot Asset protocol needs an easy way to allow users to send each other assets on-chain, without requiring several rounds of interaction to exchange and validate proofs. By using the existing bech32m address serialization standard, such addresses look distinct, while also looking familiar enough based on the character set encoding. The described address format also addresses a number of possible foot guns, by making it impossible to send the wrong asset (based on an address) amongst other protections.

Specification

A Taproot Asset is uniquely defined by its asset_genesis as well as the asset_script_key that serves as a predicate that must be satisfied for transfers. These values, along with an internal Taproot key used when creating the Bitcoin output that holds the Taproot Asset, are encoded into a single address.

Encoding an Address

Let the human readable prefix (as specified by BIP 173) be:

  • tapbc for mainnet
  • taptb for testnet
  • taprt for regtest
  • taptb for the public signet
  • tapsb for simnet
We refer to this value as the taproot_asset_hrp

Given the 32-byte asset_id, 33-byte compressed asset_script_key, and 33-byte compressed internal public key, 8-byte amount to send, an address is encoded as:

  • bech32m(hrp=taproot_asset_hrp, addr_tlv_payload)
where addr_tlv_payload is a TLV payload composed of the following types:
  • type: 0 (taproot_asset_version)
    • value:
      • [u8:version]
  • type: 2 (asset_id)
    • value:
      • [32*byte:asset_id]
  • type: 3 (asset_key_family)
    • value:
      • [33*byte:family_key]
  • type: 4 (asset_script_key)
    • value:
      • [33*byte:script_key]
  • type: 6 (internal_key)
    • value:
      • [33*byte:taproot_internal_key]
  • type: 7 (taproot_sibling_preimage)
    • value:
      • [...*byte:tapscript_preimage]
  • type: 8 (amt)
    • value:
      • [BigSize:amt_to_send]
  • type: 10 (proof_courier_addr)
    • value:
      • [...*byte:proof_courier_addr]
Inspired by Lightning's BOLT specification, we adopt the "it's OK to be odd" semantics here as well. This enables receivers to specify to the caller certain information that MUST be known in order to properly complete a transfer.

The only odd keys specified in the current version are the asset_key_family type and the asset_type field. The asset_key_family field isn't always needed for assets that don't allow for continual re-issuance. Similarly, if the asset_type field isn't specified, then one can assume a normal asset is being sent.

The proof_courier_addr is a mandatory URI (RFC 3986) that indicates what proof courier to use when sending the proofs from the sender to the recipient. The scheme (protocol) indicates the type of courier transport to use, current valid values are hashmail:// for Hashmail based couriers and universerpc:// for gRPC based transfer via a universe server.

Decoding and Sending To An Address

Given a valid Taproot Asset address, decompose the contents into the referenced asset_id, asset_script_key, and internal_key. Look up the full asset_genesis with the asset_id in the appropriate Universe.

Construct a new blank Taproot Asset leaf according to the default Asset Leaf Format with the following values being set explicitly (and all other values being their default/zero values):

  • taproot_asset_version: 0
  • asset_genesis: asset_genesis
  • amt: amt_to_send
  • asset_script_version: 0
  • asset_script_key: asset_script_key
  • asset_key_family: asset_key_family
Create a valid tapscript root, using leaf version 0x0c with the sole leaf being the serialized TLV blob specified above.

Create the top-level taproot public key script, as a segwit v1 witness program, as specified in BIP 341, using the included key as the internal key.

With the target taproot public key script constructed, the asset is sent to the receiver with the execution of the following steps:

  1. Construct a valid transaction that spends an input that holds the referenced asset_id and exactly amt units of the asset.
  2. Create a new Taproot Asset output commitment based on the input commitment (this will be the change output), that now only commits to S-A units of asset_id, where S is the input amount, and A is the amount specified in the encoded Taproot Asset address.
    1. This new leaf MUST have a split_commitment specified that commits to the position (keyed by sha256(output_index || asset_id || asset_script_key) within the transaction of the newly created asset leaf for the receiver. This split commitment is omitted by the sender when serializing the leaf for inclusion in the asset tree, otherwise the tree wouldn't be predictable on the receiver side. This has a corresponding rule in the bip-tap-vm during the input mapping of the inclusion proof validation.
    2. Add an additional output that sends a de minimis (in practice this MUST be above dust) amount to the top-level taproot public key computed earlier.
    3. Broadcast and sign the transaction, submitting the resulting Taproot Asset state transition proof to a Universe of choice, also known by the receiver.
  3. Post the resulting state transition proof to the specified Universe. The submitted proof must contain the optional auxiliary value of the full split_commitment the receiver requires to spend the asset.

Non-interactive full value send

Sending assets to an address is inherently a non-interactive process as there is no active communication between the sender and recipient other than the exchange of the address in the first place. Because of the above mentioned requirement that an asset leaf created to send to an address MUST have a split_commitment, a special case exists if there is no change going back to the sender (an asset output is fully consumed by the transfer to an address): A special tombstone output with a value of 0 must be created for the split root asset (the root_asset of the split) that holds the transfer witness. 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. Such a tombstone output can then be pruned from the tree when the UTXO is spent further. More details about interactive and non-interactive sends and tombstone outputs can be found in the bip-tap-psbt.

Spending The Received Asset

In order to spend (or simply confirm receipt) of the received asset, the receiver should:

  1. Re-derive the taproot public key script created above that sends to their specified Taproot Asset leaf.
  2. Wait for a transaction creating the output to be confirmed in the blockchain.
    1. In practice this may be via light client protocols such as BIP 157/158, or simply a full node with an address index, or import public key.
  3. For each previous outpoint referenced in the transaction:
    1. Look up the previous outpoint as a key into the chosen canonical Universe/Multiverse.
      1. If the key is found, verify the inclusion proof of the value (as described in bip-tap-proof-file), and extract the split_commitment inclusion proof for the output.
  4. Walk the Universe tree backwards in time to incrementally construct the full provenance proof needed to spend the asset.

Test Vectors

Test vectors for Encoding an Address can be found here:

The test vectors are automatically generated by unit tests in the Taproot Assets GitHub repository.

Reference Implementation

github.com/lightninglabs/taproot-assets/tree/main/address