BSV.Tokens.SwapDescriptor (bsv_sdk v1.5.0)

Copy Markdown View Source

STAS 3.0 v0.1 §6.3 swap descriptor — the canonical, recursive form of the var2 payload pushed by an atomic-swap STAS UTXO (action byte 0x01).

Wire layout (minimum 61 bytes):

offset  0  : action            = 0x01           1 B
offset  1  : requestedScriptHash (SHA256)      32 B
offset 33  : receiveAddr        (HASH160)      20 B
offset 53  : rateNumerator       u32 LE         4 B
offset 57  : rateDenominator     u32 LE         4 B
offset 61  : next                              variable, optional

The next field, when present, is the var2 value that the maker requires the taker to install on the maker's remainder UTXO after the swap is fully or partially consumed (spec §6.3, §9.5). It can be:

  • absent (zero bytes after the 61-byte head) → next = nil
  • a passive var2 push (action byte 0x00 + arbitrary) → {:passive, bytes}
  • the frozen marker (single byte 0x02) → :frozen
  • another swap descriptor BUT with the leading 0x01 action byte STRIPPED (per spec §6.3: "Encoding is the same as the top-level descriptor, minus including the leading action byte.") → {:swap, %SwapDescriptor{}}

This module implements both encoding (to_var2_bytes/1) and decoding (parse/1) of the full recursive structure. The legacy 61-byte non-recursive form continues to round-trip correctly: to_var2_bytes/1 of a descriptor with next: nil produces exactly the same bytes that BSV.Tokens.Script.Stas3Builder.encode_swap_action_data/1 would have produced for the equivalent swap_fields() map.

Conversion helpers (from_swap_fields/2, to_swap_fields/1) bridge to the legacy BSV.Tokens.ActionData.swap_fields() map shape used elsewhere in the codebase.

Summary

Functions

Build a SwapDescriptor from the legacy BSV.Tokens.ActionData.swap_fields() map (which uses :requested_pkh rather than :receive_addr). The next field is taken from the second argument, defaulting to nil for full backward compatibility with the 61-byte form.

Parse a full var2 payload (must include the leading 0x01 action byte) into a SwapDescriptor.

Project a SwapDescriptor down to the legacy BSV.Tokens.ActionData.swap_fields() map (drops the recursive next field). Useful when an existing API only consumes the 61-byte form.

Encode a SwapDescriptor to its full var2 payload, INCLUDING the leading 0x01 action byte.

Types

next_value()

@type next_value() :: nil | :frozen | {:passive, binary()} | {:swap, t()}

t()

@type t() :: %BSV.Tokens.SwapDescriptor{
  next: next_value(),
  rate_denominator: non_neg_integer(),
  rate_numerator: non_neg_integer(),
  receive_addr: <<_::160>>,
  requested_script_hash: <<_::256>>
}

Functions

from_swap_fields(map, next \\ nil)

@spec from_swap_fields(BSV.Tokens.ActionData.swap_fields(), next_value()) :: t()

Build a SwapDescriptor from the legacy BSV.Tokens.ActionData.swap_fields() map (which uses :requested_pkh rather than :receive_addr). The next field is taken from the second argument, defaulting to nil for full backward compatibility with the 61-byte form.

parse(arg1)

@spec parse(binary()) :: {:ok, t()} | {:error, term()}

Parse a full var2 payload (must include the leading 0x01 action byte) into a SwapDescriptor.

Recursively decodes the next chain until either:

  • the remaining bytes are exhausted (next = nil),
  • a 0x00 passive marker is consumed (next = {:passive, rest}),
  • a single-byte 0x02 frozen marker is consumed (next = :frozen),
  • another swap body (no leading 0x01) is consumed (next = {:swap, %SwapDescriptor{}}).

Returns {:ok, descriptor} on success or {:error, reason} on malformed input (truncated header, frozen marker followed by extra bytes, or a nested-swap header that does not contain 60 bytes).

to_swap_fields(d)

@spec to_swap_fields(t()) :: BSV.Tokens.ActionData.swap_fields()

Project a SwapDescriptor down to the legacy BSV.Tokens.ActionData.swap_fields() map (drops the recursive next field). Useful when an existing API only consumes the 61-byte form.

to_var2_bytes(d)

@spec to_var2_bytes(t()) :: binary()

Encode a SwapDescriptor to its full var2 payload, INCLUDING the leading 0x01 action byte.

Returns the raw binary (61+ bytes) suitable for use as the var2 push body in a STAS 3.0 locking script.