bsv-wallet 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c71d9a7e4b68e5d47c4d95e3a8bcd6c23c698a92ca3faa4809a9a7abf1171b8e
4
- data.tar.gz: f61618ef74ba89eae855dc710244f5a9208bff34a2244f4bb2ab6425d6774fea
3
+ metadata.gz: 7959ebc47fc5d89d3d0db18f4136c925e228f6ea483553decffd4b9e7de9defc
4
+ data.tar.gz: 2365a17193357b64d50c15a61aa12422b966b8f0155a6ab989b3bacb700a0929
5
5
  SHA512:
6
- metadata.gz: 9c9d6badbfaac1bb19ed0bf5745ccfe21aba5372822e692be72f1065df56175481277e8f1b41daf4c17dd0acc758e43a2dcf73d4e8c96147d982dafd7b7a7ca3
7
- data.tar.gz: 161733d4e9c277c55d4e3b1d89eab89bf156d066575c3f924e066c636d55f65606cd1e4df7afdbbdf0ff8cea615d5d6c09c30aafc63773294370c22659a3bf85
6
+ metadata.gz: 895d3c7a661e00b7d70dd833d12e4dd0e17ca2a8d0d8ba6a2c0ef622dfbac6bc0d6fb534a3fe06c14c0b1747981f1e0c9b8b61e9f164e3cc8fea222e5f9e70c1
7
+ data.tar.gz: 3086ff6e236c57d903c947ac7c230148104993837b3d2f46ddef3a09a9b43da42bab1a5ea6f1c7b375b105cc7e8feffe2c8defbd83a325ec7ca0775dbd1f2ea1
data/CHANGELOG.md CHANGED
@@ -5,6 +5,47 @@ All notable changes to the `bsv-wallet` gem are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
6
6
  and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 0.9.0 — 2026-04-16
9
+
10
+ ### Changed — **Breaking**
11
+
12
+ #### Action status taxonomy aligned with BRC-100 reference SDK (HLR #455)
13
+
14
+ This release realigns the action status values with the wallet-toolbox reference
15
+ implementation. The meaning of `'completed'` has changed — **consumers must
16
+ update any code that checks for `'completed'` as the post-broadcast success
17
+ state**.
18
+
19
+ | Status | Old meaning | New meaning |
20
+ |--------|-------------|-------------|
21
+ | `'nosend'` | No change | Transaction built but not broadcast (`no_send: true`) |
22
+ | `'sending'` | No change | Async queue accepted; worker has not yet attempted broadcast |
23
+ | `'unproven'` | *(new)* | Broadcast succeeded; awaiting merkle proof |
24
+ | `'completed'` | Broadcast succeeded | **Merkle proof received and stored** |
25
+ | `'failed'` | No change | Broadcast rejected or transaction invalid |
26
+
27
+ **Migration:**
28
+
29
+ - Code querying `list_actions(status: 'completed')` will return fewer results
30
+ until a proof-watcher is implemented (out of scope for this release). To find
31
+ successfully-broadcast actions that have not yet received a proof, query
32
+ `status: 'unproven'` instead.
33
+ - `create_action` and `sign_action` now raise `BSV::Wallet::WalletError` when
34
+ no broadcaster is configured and `options: { no_send: true }` is not set.
35
+ Previously these calls succeeded silently. To resolve: pass
36
+ `broadcaster: BSV::Network::ARC.default` to `WalletClient.new`, or pass
37
+ `options: { no_send: true }` to `create_action` to build without
38
+ broadcasting.
39
+ - `internalize_action` now sets status to `'completed'` only when the supplied
40
+ BEEF contains a merkle proof for the subject transaction. Plain BEEF (raw
41
+ transaction, no BUMP) results in status `'unproven'`.
42
+ - Wallets configured with a `SolidQueueAdapter` satisfy the broadcaster
43
+ requirement if the adapter carries an embedded `broadcaster:` — the
44
+ `WalletClient` itself does not need one.
45
+
46
+ **Related upstream incidents:** x402-rack #148, x402-rack #158, x402-doom #196.
47
+ **Tracking issue:** #455.
48
+
8
49
  ## 0.8.0 — 2026-04-15
9
50
 
10
51
  ### Added
@@ -68,6 +68,21 @@ module BSV
68
68
  false
69
69
  end
70
70
 
71
+ # Returns +false+ by default — adapters without a broadcaster cannot
72
+ # broadcast on-chain.
73
+ #
74
+ # Override in adapters that hold a broadcaster reference so that
75
+ # +WalletClient+ can determine broadcast availability from the queue
76
+ # alone. This is the correct delegation point because users may pass a
77
+ # broadcaster-equipped queue (e.g.
78
+ # +SolidQueueAdapter.new(broadcaster: arc)+) without also passing
79
+ # +broadcaster:+ directly to +WalletClient+.
80
+ #
81
+ # @return [Boolean]
82
+ def broadcast_enabled?
83
+ false
84
+ end
85
+
71
86
  # Returns the broadcast status for a previously enqueued transaction.
72
87
  #
73
88
  # @param _txid [String] hex transaction identifier
@@ -30,6 +30,17 @@ module BSV
30
30
  false
31
31
  end
32
32
 
33
+ # Returns +true+ when a broadcaster has been configured.
34
+ #
35
+ # +WalletClient+ delegates its own +broadcast_enabled?+ to this method
36
+ # so the check works correctly when the broadcaster is embedded in the
37
+ # queue rather than passed directly to the wallet.
38
+ #
39
+ # @return [Boolean]
40
+ def broadcast_enabled?
41
+ !@broadcaster.nil?
42
+ end
43
+
33
44
  # Returns the broadcast status for a previously enqueued transaction.
34
45
  #
35
46
  # Delegates to storage and returns the action status field, or +nil+ if
@@ -96,8 +107,10 @@ module BSV
96
107
  }
97
108
  end
98
109
 
99
- # Broadcast succeeded — promote all pending state to final.
100
- promote(input_outpoints, change_outpoints, txid)
110
+ # Broadcast succeeded — promote all pending state; set status to
111
+ # 'unproven' (transaction is on-chain but lacks a merkle proof).
112
+ # 'completed' is reserved for transactions confirmed by a proof-watcher.
113
+ promote(input_outpoints, change_outpoints, txid, status: 'unproven')
101
114
 
102
115
  result = {
103
116
  txid: txid,
@@ -109,14 +122,24 @@ module BSV
109
122
  result
110
123
  end
111
124
 
112
- # Promotes UTXO state without broadcasting — backwards-compatible fallback
113
- # used when no broadcaster is configured.
125
+ # Promotes UTXO state without broadcasting.
114
126
  #
115
- # If +accept_delayed_broadcast+ is set the action status is +unproven+;
116
- # otherwise it is +completed+.
127
+ # This path is reached when no broadcaster is configured. It is only
128
+ # valid when +accept_delayed_broadcast+ is set on the create_action
129
+ # call — the caller explicitly accepts that the transaction will be
130
+ # broadcast out-of-band. Action status is set to +unproven+.
131
+ #
132
+ # +completed+ is reserved for transactions that have received a merkle
133
+ # proof (set by +internalize_action+ or a future proof-watcher).
134
+ #
135
+ # Defensive guard: raises +WalletError+ if reached without
136
+ # +accept_delayed_broadcast+. The normal entry point for this guard is
137
+ # the +create_action+ validation added in Task 1 (#456), but this guard
138
+ # protects against other code paths that bypass it.
117
139
  #
118
140
  # @param payload [Hash] broadcast payload
119
141
  # @return [Hash] result hash containing +:txid+ and +:tx+
142
+ # @raise [BSV::Wallet::WalletError] if +accept_delayed_broadcast+ is not set
120
143
  def promote_without_broadcast(payload)
121
144
  txid = payload[:txid]
122
145
  beef_binary = payload[:beef_binary]
@@ -124,8 +147,14 @@ module BSV
124
147
  change_outpoints = payload[:change_outpoints]
125
148
  delayed = payload[:accept_delayed_broadcast]
126
149
 
127
- final_status = delayed ? 'unproven' : 'completed'
128
- promote(input_outpoints, change_outpoints, txid, status: final_status)
150
+ unless delayed
151
+ raise BSV::Wallet::WalletError,
152
+ 'InlineQueue cannot promote without a broadcaster unless ' \
153
+ 'accept_delayed_broadcast is set. This indicates a bypass of ' \
154
+ 'the create_action guard — report as a bug.'
155
+ end
156
+
157
+ promote(input_outpoints, change_outpoints, txid, status: 'unproven')
129
158
 
130
159
  { txid: txid, tx: beef_binary.unpack('C*') }
131
160
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module BSV
4
4
  module Wallet
5
- VERSION = '0.8.0'
5
+ VERSION = '0.9.0'
6
6
  end
7
7
  end
@@ -94,9 +94,13 @@ module BSV
94
94
  )
95
95
  end
96
96
 
97
- # Returns true when a broadcaster has been configured.
97
+ # Returns +true+ when broadcast is available.
98
+ #
99
+ # Delegates to the broadcast queue so that queue-embedded broadcasters
100
+ # (e.g. +SolidQueueAdapter.new(broadcaster: arc)+) are recognised even
101
+ # when no +broadcaster:+ was passed directly to +WalletClient+.
98
102
  def broadcast_enabled?
99
- !@broadcaster.nil?
103
+ @broadcast_queue.broadcast_enabled?
100
104
  end
101
105
 
102
106
  # --- Transaction Operations ---
@@ -123,6 +127,7 @@ module BSV
123
127
  return @substrate.create_action(args, originator: originator) if @substrate
124
128
 
125
129
  validate_create_action!(args)
130
+ validate_broadcast_configuration!(args)
126
131
 
127
132
  send_with_txids = Array(args.dig(:options, :send_with))
128
133
 
@@ -185,6 +190,11 @@ module BSV
185
190
  else
186
191
  pending[:args]
187
192
  end
193
+
194
+ # Re-validate broadcast configuration on merged args — options may have
195
+ # been flipped between create_action and sign_action (e.g. no_send toggled).
196
+ validate_broadcast_configuration!(merged_args)
197
+
188
198
  finalize_action(tx, merged_args)
189
199
  end
190
200
 
@@ -303,7 +313,8 @@ module BSV
303
313
  store_proofs_from_beef(beef)
304
314
  @storage.store_transaction(tx.txid_hex, tx.to_hex)
305
315
  process_internalize_outputs(tx, args[:outputs])
306
- store_action(tx, args, status: 'completed')
316
+ has_proof = !beef.find_bump(tx.txid).nil?
317
+ store_action(tx, args, status: has_proof ? 'completed' : 'unproven')
307
318
  { accepted: true }
308
319
  end
309
320
 
@@ -1068,6 +1079,25 @@ module BSV
1068
1079
 
1069
1080
  # --- Validation ---
1070
1081
 
1082
+ # Raises +WalletError+ when a broadcast is required but unavailable.
1083
+ #
1084
+ # Broadcast is required whenever +no_send+ is absent or false. Callers
1085
+ # that do not intend to broadcast on-chain must pass
1086
+ # +options: { no_send: true }+ to opt out.
1087
+ #
1088
+ # @param args [Hash] action arguments (merged, as seen at call site)
1089
+ # @raise [WalletError] if broadcast is needed but +broadcast_enabled?+ is false
1090
+ def validate_broadcast_configuration!(args)
1091
+ no_send = args.dig(:options, :no_send)
1092
+ return if no_send
1093
+ return if broadcast_enabled?
1094
+
1095
+ raise WalletError,
1096
+ 'create_action requires a broadcaster for on-chain broadcast. ' \
1097
+ 'Pass broadcaster: BSV::Network::ARC.default to WalletClient.new, ' \
1098
+ 'or options: { no_send: true } to build a transaction without broadcasting.'
1099
+ end
1100
+
1071
1101
  def validate_create_action!(args)
1072
1102
  Validators.validate_description!(args[:description])
1073
1103
  inputs_present = args[:inputs] && !args[:inputs].empty?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bsv-wallet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Bettison