Skip to main content
The Vtxo type represents a virtual UTXO in the Ark protocol. VTXOs are off-chain constructs that can be spent cooperatively with the server or unilaterally exited on-chain.

Overview

VTXOs form the fundamental unit of value in Ark. Each VTXO contains:
  • An output policy defining spending conditions
  • An amount of Bitcoin
  • A chain anchor linking to on-chain confirmation
  • Genesis data describing how the VTXO was created
The correctness of methods on Vtxo is conditional on the VTXO being valid. Always validate VTXOs upon receipt using validate().

Core Type: Vtxo

lib/src/vtxo/mod.rs
pub struct Vtxo<P = VtxoPolicy> {
    policy: P,
    amount: Amount,
    expiry_height: BlockHeight,
    server_pubkey: PublicKey,
    exit_delta: BlockDelta,
    anchor_point: OutPoint,
    genesis: Vec<GenesisItem>,
    point: OutPoint,
}

Key Methods

Identification

pub fn id(&self) -> VtxoId
Get the unique identifier for this VTXO (same as point() but encoded as bytes).
pub fn point(&self) -> OutPoint
The outpoint from which to build forfeit or arkoor transactions.

Value and Ownership

pub fn amount(&self) -> Amount
The amount of Bitcoin in this VTXO.
pub fn user_pubkey(&self) -> PublicKey
Returns the user public key associated with this VTXO.
pub fn arkoor_pubkey(&self) -> Option<PublicKey>
The public key used to cosign arkoor (out-of-round) transactions. Returns None if the policy is not arkoor-compatible.

Chain Anchoring

pub fn chain_anchor(&self) -> OutPoint
The UTXO that must be confirmed on-chain for this VTXO to be valid. This is the root of the VTXO’s exit transaction tree.

Policy and Expiry

pub fn policy(&self) -> &P
Access the output policy of this VTXO.
pub fn policy_type(&self) -> VtxoPolicyKind
Get the type of policy (Pubkey, ServerHtlcSend, ServerHtlcRecv, etc.).
pub fn expiry_height(&self) -> BlockHeight
The block height at which the VTXO expires and the server can sweep funds.
pub fn exit_delta(&self) -> BlockDelta
The relative timelock block delta required for unilateral exits.
pub fn exit_depth(&self) -> u16
Returns the total exit depth (number of transactions) including OOR transitions.

Transaction Construction

pub fn output_taproot(&self) -> TaprootSpendInfo
The taproot spend info for the output of this VTXO.
pub fn output_script_pubkey(&self) -> ScriptBuf
The scriptPubkey of the VTXO output.
pub fn txout(&self) -> TxOut
The transaction output (eventual UTXO) of this VTXO.
pub fn transactions(&self) -> VtxoTxIter<'_, P>
Iterator that constructs all exit transactions for this VTXO, starting from the chain anchor.

Validation

pub fn validate(&self, chain_anchor_tx: &Transaction) -> Result<(), VtxoValidationError>
Fully validate this VTXO and its entire transaction chain, including all signatures.
pub fn validate_unsigned(&self, chain_anchor_tx: &Transaction) -> Result<(), VtxoValidationError>
Validate VTXO structure without checking signatures.
pub fn has_all_witnesses(&self) -> bool
Whether all transaction witnesses are present. Returns false for unsigned or unfinished VTXOs.
pub fn is_standard(&self) -> bool
Check if this VTXO is standard for relay purposes:
  • Its own output is standard
  • All sibling outputs in the exit path are standard
  • Each part of the exit path has a P2A (pay-to-anchor) output

VtxoId

A unique 36-byte identifier for a VTXO.
lib/src/vtxo/mod.rs
pub struct VtxoId([u8; 36]);
Methods:
pub fn from_slice(b: &[u8]) -> Result<VtxoId, VtxoIdParseError>
Construct from a byte slice (must be exactly 36 bytes).
pub fn utxo(self) -> OutPoint
Convert to the underlying OutPoint.
pub fn to_bytes(self) -> [u8; 36]
Get the raw 36-byte representation.

VtxoSpec

Specifies a VTXO independent of its origin.
lib/src/vtxo/mod.rs
pub struct VtxoSpec<P = VtxoPolicy> {
    pub policy: P,
    pub amount: Amount,
    pub expiry_height: BlockHeight,
    pub server_pubkey: PublicKey,
    pub exit_delta: BlockDelta,
}
Methods:
pub fn output_taproot(&self) -> TaprootSpendInfo
The taproot spend info for this VTXO’s output.
pub fn output_script_pubkey(&self) -> ScriptBuf
The scriptPubkey of this VTXO’s output.
pub fn txout(&self) -> TxOut
The transaction output for this VTXO.

VtxoRequest

A request to create a VTXO with a specific policy and amount.
lib/src/lib.rs
pub struct VtxoRequest {
    pub policy: VtxoPolicy,
    pub amount: Amount,
}
Used when requesting VTXOs in rounds or other operations.

ServerVtxo

Type alias for server-internal VTXOs that may have policies without user pubkeys.
lib/src/vtxo/mod.rs
pub type ServerVtxo = Vtxo<ServerVtxoPolicy>;
Server VTXOs can represent intermediate states like checkpoints or expiry-only outputs.

Genesis Data

Each VTXO contains genesis data describing how it was created.

GenesisItem

lib/src/vtxo/genesis.rs
pub struct GenesisItem {
    pub transition: GenesisTransition,
    pub output_idx: u8,
    pub other_outputs: Vec<TxOut>,
    pub fee_amount: Amount,
}
Represents one level in the VTXO’s exit transaction chain. Fields:
  • transition: The type of transition (Cosigned, Arkoor, HashLockedCosigned)
  • output_idx: Which output in the transaction goes to the next level
  • other_outputs: Sibling outputs needed to reconstruct the transaction
  • fee_amount: Fee for the P2A output (usually zero except for boarding)

GenesisTransition

lib/src/vtxo/genesis.rs
pub enum GenesisTransition {
    Cosigned(CosignedGenesis),
    HashLockedCosigned(HashLockedCosignedGenesis),
    Arkoor(ArkoorGenesis),
}

Protocol Encoding

VTXOs use a stable binary encoding for network transmission and storage. Current version: 2 (version 1 lacked fee amounts in genesis items)
const VTXO_ENCODING_VERSION: u16 = 2;

Encoding Format

  1. Version (u16)
  2. Amount (u64, satoshis)
  3. Expiry height (u32)
  4. Server pubkey (33 bytes)
  5. Exit delta (u16)
  6. Anchor point (36 bytes)
  7. Genesis items (compact size + items)
  8. Policy (variable)
  9. Point (36 bytes)
Each genesis item encodes:
  • Transition type and data
  • Number of outputs (u8)
  • Output index (u8)
  • Other outputs (variable)
  • Fee amount (u64, satoshis)

Usage Examples

Validating a VTXO

let vtxo: Vtxo = // ... received from server or peer
let chain_anchor_tx: Transaction = // ... fetch from chain

// Validate the entire VTXO
vtxo.validate(&chain_anchor_tx)?;

// Check key properties
assert!(vtxo.is_standard());
assert!(vtxo.has_all_witnesses());
assert_eq!(vtxo.amount(), Amount::from_sat(100_000));

Constructing Exit Transactions

// Iterate through all exit transactions
for tx_item in vtxo.transactions() {
    println!("Exit tx: {}", tx_item.tx.compute_txid());
    println!("Output index: {}", tx_item.output_idx);
}

// Get the final VTXO output
let final_output = vtxo.txout();
println!("Final scriptPubkey: {}", final_output.script_pubkey);

Checking VTXO Properties

// Check policy compatibility
if let Some(arkoor_pk) = vtxo.arkoor_pubkey() {
    println!("VTXO can be spent out-of-round with key: {}", arkoor_pk);
}

// Check expiry
let current_height = 850_000;
if current_height >= vtxo.expiry_height() {
    println!("VTXO has expired, server can sweep");
}

// Check exit depth
println!("Exit requires {} transactions", vtxo.exit_depth());

Important Notes

VTXOs can be large objects due to genesis data. Avoid excessive cloning - use references or Rc/Arc when needed.
Always call validate() on received VTXOs before trusting their data. Invalid VTXOs may return incorrect values from methods.
The point() and id() methods are used for equality comparison - two VTXOs with the same point are considered equal regardless of other fields.

Build docs developers (and LLMs) love