# Class BSV::Network::Broadcaster <a id="class-BSV-Network-Broadcaster"></a>

**Inherits:** `Object`

Wallet-side broadcast orchestration above SDK providers.

Owns provider selection for broadcast and persisted affinity keyed on the
wallet-computed wtxid. Composes an internal `Services` instance so backoff,
retry, fallback, rate-limiting, and response normalisation ride along
unchanged -- this class layers selection only.

Providers passed here must implement <code>:broadcast</code> and
<code>:get_tx_status</code> in Arcade-shape -- callback_token kwarg,
X-CallbackToken header, and the SSE-aligned response payload. WhatsOnChain's
protocol declares the <code>:broadcast</code> capability but its
+call_broadcast(tx)+ has no kwargs and its tx_status semantics are different;
don't mix it in here. Use it as a chain query provider in `Services`, not a
Broadcaster candidate.

**@example**
```ruby
broadcaster = BSV::Network::Broadcaster.new(providers: [gorilla_pool], store: store)
broadcaster.broadcast(raw_tx, wtxid: wtxid)
```

## Attributes
### `providers` [R] <a id="attribute-i-providers"></a> <a id="providers-instance_method"></a>
Returns the value of attribute providers.

## Public Instance Methods
### `broadcast(payload, wtxid:, callback_token: = nil)` <a id="method-i-broadcast"></a> <a id="broadcast-instance_method"></a>
Broadcast a transaction payload through the affinity-preferred or first
broadcast-capable provider, with fallback on retryable errors.

On success, persists the responding provider's name to
<code>broadcasts.provider</code> keyed on the supplied wtxid -- the affinity
survives daemon restart and is keyed off the wallet's wtxid (so the Arcade
+"submitted"+ response with no `txid` still records).

The optional `callback_token` is forwarded to the underlying provider as the
<code>X-CallbackToken</code> HTTP header (see #266 + plan §4.1). Both ARC and
Arcade protocols already accept this as a per-call kwarg in the SDK, so the
value flows straight through +Provider#call+ to the protocol's
`call_broadcast` without any additional plumbing here. Lenient default (nil):
tests that do not run an SSE listener can broadcast without the header at the
cost of forgoing status push -- production callers (CLI.boot, walletd) always
supply one.
- **@param** `payload` [Object] payload accepted by the underlying provider's
+:broadcast+ command (raw bytes for the daemon path, +Transaction::Tx+
for the inline path -- no narrowing).
- **@param** `wtxid` [String] 32-byte binary wire-order wtxid the wallet
computed pre-broadcast. Required.
- **@param** `callback_token` [String, nil] Arcade callbackToken to send
as +X-CallbackToken+. When set, the SSE listener subscribed to
the same token receives the resulting status frame.
- **@return** [BSV::Network::ProtocolResponse]

### `get_tx_status(wtxid:, dtxid:)` <a id="method-i-get_tx_status"></a> <a id="get_tx_status-instance_method"></a>
Query tx status through the affinity-preferred or first capable provider, with
fallback on retryable errors.

The wallet's bookkeeping key is the binary wtxid; the wire query uses the
display-order `dtxid` hex string. The SDK's protocol +call_get_tx_status(txid,
**)+ takes the dtxid as a **positional** argument (Ruby 3 keyword-arg
strictness; passing it as <code>txid:</code> raises "unknown keyword: :txid").
- **@param** `wtxid` [String] 32-byte binary wire-order wtxid (affinity key)
- **@param** `dtxid` [String] 64-char display-order hex (sent to ARC)
- **@return** [BSV::Network::ProtocolResponse]

### `initialize(providers:, store: = nil)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `providers` [Array<BSV::Network::Provider>] providers in priority order
- **@param** `store` [BSV::Wallet::Store, nil] store for affinity persistence
- **@raise** [ArgumentError]
- **@return** [Broadcaster] a new instance of Broadcaster

### `provider_for(wtxid)` <a id="method-i-provider_for"></a> <a id="provider_for-instance_method"></a>
Provider that previously handled a broadcast for the given wtxid.

Reads <code>broadcasts.provider</code> via the store, then resolves the name
to a `Provider` instance from +@providers+. Returns `nil` when no affinity is
recorded, the store is not configured, or the provider named in the column is
no longer registered (config drift across restart) -- callers then fall
through to capability-only routing.
- **@param** `wtxid` [String] 32-byte binary wire-order wtxid
- **@return** [BSV::Network::Provider, nil]
