# `BSV.Tokens.Factory.Stas3`
[🔗](https://github.com/Bittoku/bsv_sdk_elixir/blob/main/lib/bsv/tokens/factory/stas3.ex#L1)

STAS3 transaction factories.

Pure functions that build complete, signed transactions for STAS 3 token
operations: two-tx issuance, base spend, freeze, unfreeze, and swap.

# `base_config`

```elixir
@type base_config() :: %{
  token_inputs: [BSV.Tokens.TokenInput.t()],
  fee_txid: binary(),
  fee_vout: non_neg_integer(),
  fee_satoshis: non_neg_integer(),
  fee_locking_script: BSV.Script.t(),
  fee_private_key: BSV.PrivateKey.t(),
  destinations: [BSV.Tokens.Stas3OutputParams.t()],
  spend_type: BSV.Tokens.Stas3SpendType.t(),
  fee_rate: non_neg_integer()
}
```

# `issue_config`

```elixir
@type issue_config() :: %{
  scheme: BSV.Tokens.Scheme.t(),
  funding_txid: binary(),
  funding_vout: non_neg_integer(),
  funding_satoshis: non_neg_integer(),
  funding_locking_script: BSV.Script.t(),
  funding_private_key: BSV.PrivateKey.t() | nil,
  funding_key: BSV.Tokens.SigningKey.t() | nil,
  outputs: [
    %{satoshis: non_neg_integer(), owner_pkh: &lt;&lt;_::160&gt;&gt;, freezable: boolean()}
  ],
  fee_rate: non_neg_integer()
}
```

# `build_stas3_base_tx`

```elixir
@spec build_stas3_base_tx(base_config()) ::
  {:ok, BSV.Transaction.t()} | {:error, term()}
```

Build a generic STAS3 spend transaction.

# `build_stas3_confiscate_tx`

```elixir
@spec build_stas3_confiscate_tx(base_config()) ::
  {:ok, BSV.Transaction.t()} | {:error, term()}
```

Build a STAS3 confiscation transaction.

Confiscates token UTXOs using spending type 3 (confiscation authority path).
Frozen inputs CAN be confiscated. The scheme must have confiscation enabled
and service fields must include the confiscation authority.

## Parameters
  * `config` - A `base_config()` map. The spend_type will be overridden
    to `:confiscation`.

## Returns
  * `{:ok, transaction}` on success
  * `{:error, reason}` on validation failure

# `build_stas3_freeze_tx`

```elixir
@spec build_stas3_freeze_tx(base_config()) ::
  {:ok, BSV.Transaction.t()} | {:error, term()}
```

Build a STAS3 freeze transaction.

# `build_stas3_issue_txs`

```elixir
@spec build_stas3_issue_txs(issue_config()) ::
  {:ok, %{contract_tx: BSV.Transaction.t(), issue_tx: BSV.Transaction.t()}}
  | {:error, term()}
```

Build the two-transaction STAS3 issuance flow.

# `build_stas3_merge_tx`

```elixir
@spec build_stas3_merge_tx(base_config()) ::
  {:ok, BSV.Transaction.t()} | {:error, term()}
```

Build a STAS3 merge transaction.

Merges exactly 2 STAS inputs into 1-2 STAS outputs. This is a semantic wrapper
around `build_stas3_base_tx/1` that enforces merge-specific constraints.

## Parameters
  * `config` - A `base_config()` map with:
    * `:token_inputs` - Exactly 2 token inputs
    * `:destinations` - 1-2 STAS3 output destinations
    * Other fields as per `base_config()`

## Returns
  * `{:ok, transaction}` on success
  * `{:error, reason}` on validation failure

# `build_stas3_redeem_tx`

```elixir
@spec build_stas3_redeem_tx(map()) :: {:ok, BSV.Transaction.t()} | {:error, term()}
```

Build a STAS3 redeem transaction.

Redeems STAS tokens back to regular P2PKH satoshis. Only the issuer can redeem.
This is NOT a wrapper around `build_stas3_base_tx/1` because the primary output
is P2PKH rather than STAS3.

## Parameters
  * `config` - A map with:
    * `:token_input` - A single `TokenInput` (the STAS UTXO to redeem)
    * `:fee_txid`, `:fee_vout`, `:fee_satoshis`, `:fee_locking_script`,
      `:fee_private_key` - Funding input for fees
    * `:redeem_satoshis` - Amount to redeem as P2PKH output
    * `:redeem_pkh` - The 20-byte pubkey hash for the P2PKH redeem output
    * `:remaining_destinations` - Optional list of `Stas3OutputParams` for
      remaining STAS outputs (default `[]`)
    * `:fee_rate` - Fee rate in sat/KB

## Rules
  * Token input owner must be the issuer (owner_pkh == redemption_pkh from script)
  * Frozen inputs cannot be redeemed
  * Conservation: stas_in == redeem_satoshis + sum(remaining STAS outputs)
  * Uses spending type 1 (regular)

## Returns
  * `{:ok, transaction}` on success
  * `{:error, reason}` on validation failure

# `build_stas3_split_tx`

```elixir
@spec build_stas3_split_tx(base_config()) ::
  {:ok, BSV.Transaction.t()} | {:error, term()}
```

Build a STAS3 split transaction.

Splits a single STAS input into 1-4 STAS outputs. This is a semantic wrapper
around `build_stas3_base_tx/1` that enforces split-specific constraints:
exactly 1 STAS input and 1-4 destinations.

## Parameters
  * `config` - A `base_config()` map with:
    * `:token_inputs` - Exactly 1 token input
    * `:destinations` - 1-4 STAS3 output destinations
    * Other fields as per `base_config()`

## Returns
  * `{:ok, transaction}` on success
  * `{:error, reason}` on validation failure

# `build_stas3_swap_flow_tx`

```elixir
@spec build_stas3_swap_flow_tx(base_config()) ::
  {:ok, BSV.Transaction.t()} | {:error, term()}
```

Build a STAS3 swap flow transaction with auto-detected mode.

Reads each input's locking script to detect swap action data:
- Both inputs have swap action data → swap-swap (spending type 4)
- Otherwise → transfer-swap (spending type 1)

## Parameters
  * `config` - A `base_config()` map with exactly 2 token inputs.

## Returns
  * `{:ok, transaction}` on success
  * `{:error, reason}` on validation failure

# `build_stas3_swap_swap_tx`

```elixir
@spec build_stas3_swap_swap_tx(base_config()) ::
  {:ok, BSV.Transaction.t()} | {:error, term()}
```

Build a STAS3 swap-swap transaction.

Both sides are swap requests (spending type 4). Requires exactly 2 STAS inputs,
both carrying swap action data. Rejects frozen inputs.

Outputs can be 2-4 STAS outputs:
- Outputs 0-1: principal swap legs (neutral action data)
- Output 2: optional remainder for leg 1
- Output 3: optional remainder for leg 2

## Parameters
  * `config` - A `base_config()` map with exactly 2 token inputs and 2-4 destinations.

## Returns
  * `{:ok, transaction}` on success
  * `{:error, reason}` on validation failure (wrong input count, frozen inputs)

# `build_stas3_transfer_swap_tx`

```elixir
@spec build_stas3_transfer_swap_tx(base_config()) ::
  {:ok, BSV.Transaction.t()} | {:error, term()}
```

Build a STAS3 transfer-swap transaction.

One side transfers (spending type 1), the other side's swap request is consumed.
Requires exactly 2 STAS inputs. Rejects frozen inputs.

Outputs can be 2-4 STAS outputs:
- Outputs 0-1: principal swap legs (neutral action data)
- Output 2: optional remainder for leg 1
- Output 3: optional remainder for leg 2

## Parameters
  * `config` - A `base_config()` map with exactly 2 token inputs and 2-4 destinations.

## Returns
  * `{:ok, transaction}` on success
  * `{:error, reason}` on validation failure (wrong input count, frozen inputs)

# `build_stas3_unfreeze_tx`

```elixir
@spec build_stas3_unfreeze_tx(base_config()) ::
  {:ok, BSV.Transaction.t()} | {:error, term()}
```

Build a STAS3 unfreeze transaction.

# `resolve_stas3_swap_mode`

```elixir
@spec resolve_stas3_swap_mode([BSV.Tokens.TokenInput.t()]) ::
  :swap_swap | :transfer_swap
```

Detect whether a swap is transfer-swap or swap-swap based on input locking scripts.

Reads each input's locking script and checks for swap action data:
- Both inputs have swap action data → `:swap_swap`
- Otherwise → `:transfer_swap`

## Parameters
  * `token_inputs` - List of exactly 2 `TokenInput` structs

## Returns
  * `:swap_swap` or `:transfer_swap`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
