bsv-wallet 0.8.0 → 0.9.1

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: 0eee112e765a4b52ce2e04895d79c1b25c0d3f26a57d56eb0cac72005dce34f0
4
+ data.tar.gz: 003f406ef0001d9495013d17adf802dc8c5c98ddcd85ebed0dd2c4a5aa6c1c27
5
5
  SHA512:
6
- metadata.gz: 9c9d6badbfaac1bb19ed0bf5745ccfe21aba5372822e692be72f1065df56175481277e8f1b41daf4c17dd0acc758e43a2dcf73d4e8c96147d982dafd7b7a7ca3
7
- data.tar.gz: 161733d4e9c277c55d4e3b1d89eab89bf156d066575c3f924e066c636d55f65606cd1e4df7afdbbdf0ff8cea615d5d6c09c30aafc63773294370c22659a3bf85
6
+ metadata.gz: f9ca8b1c01639c0a898d8772caa893d06a17e10d41e2a80d51aec66c3c1e33b5d384e2f2ad0e717455d08444ae40dce4b661ea0c87e5ff287747be7ca9048e8f
7
+ data.tar.gz: 7a4abf0597b7c3b16a166e6a1d4bf7557a9de120a635a396b1b1fe10c5816ae723d53a6d66b7ac8c11cd6388a2d60346a23d7afd4845c746aba6284ca9bdfda1
data/CHANGELOG.md CHANGED
@@ -5,6 +5,59 @@ 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.1 — 2026-04-16
9
+
10
+ ### Changed
11
+
12
+ - Raised `bsv-sdk` dependency floor to `>= 0.12.1` to pick up BEEF ancestry correctness fixes ([bsv-sdk#467](https://github.com/sgbett/bsv-ruby-sdk/issues/467), [bsv-sdk#468](https://github.com/sgbett/bsv-ruby-sdk/issues/468), HLR #466). Consumer impact: recently-received UTXOs that previously could not be re-broadcast now can — the wallet's `create_action` flow relies on `Transaction.from_beef` producing fully-wired ancestry, which the old SDK didn't do.
13
+
14
+ ### Fixed
15
+
16
+ - Removed redundant `store_transaction` call in `internalize_action` — `store_proofs_from_beef` already persists every transaction in the BEEF bundle, so the subject tx was being written twice. No behaviour change; minor cleanup. (#469)
17
+
18
+ **Related:** [wallet-toolbox#149](https://github.com/bsv-blockchain/wallet-toolbox/issues/149) — same architectural gap reported upstream.
19
+
20
+ ## 0.9.0 — 2026-04-16
21
+
22
+ ### Changed — **Breaking**
23
+
24
+ #### Action status taxonomy aligned with BRC-100 reference SDK (HLR #455)
25
+
26
+ This release realigns the action status values with the wallet-toolbox reference
27
+ implementation. The meaning of `'completed'` has changed — **consumers must
28
+ update any code that checks for `'completed'` as the post-broadcast success
29
+ state**.
30
+
31
+ | Status | Old meaning | New meaning |
32
+ |--------|-------------|-------------|
33
+ | `'nosend'` | No change | Transaction built but not broadcast (`no_send: true`) |
34
+ | `'sending'` | No change | Async queue accepted; worker has not yet attempted broadcast |
35
+ | `'unproven'` | *(new)* | Broadcast succeeded; awaiting merkle proof |
36
+ | `'completed'` | Broadcast succeeded | **Merkle proof received and stored** |
37
+ | `'failed'` | No change | Broadcast rejected or transaction invalid |
38
+
39
+ **Migration:**
40
+
41
+ - Code querying `list_actions(status: 'completed')` will return fewer results
42
+ until a proof-watcher is implemented (out of scope for this release). To find
43
+ successfully-broadcast actions that have not yet received a proof, query
44
+ `status: 'unproven'` instead.
45
+ - `create_action` and `sign_action` now raise `BSV::Wallet::WalletError` when
46
+ no broadcaster is configured and `options: { no_send: true }` is not set.
47
+ Previously these calls succeeded silently. To resolve: pass
48
+ `broadcaster: BSV::Network::ARC.default` to `WalletClient.new`, or pass
49
+ `options: { no_send: true }` to `create_action` to build without
50
+ broadcasting.
51
+ - `internalize_action` now sets status to `'completed'` only when the supplied
52
+ BEEF contains a merkle proof for the subject transaction. Plain BEEF (raw
53
+ transaction, no BUMP) results in status `'unproven'`.
54
+ - Wallets configured with a `SolidQueueAdapter` satisfy the broadcaster
55
+ requirement if the adapter carries an embedded `broadcaster:` — the
56
+ `WalletClient` itself does not need one.
57
+
58
+ **Related upstream incidents:** x402-rack #148, x402-rack #158, x402-doom #196.
59
+ **Tracking issue:** #455.
60
+
8
61
  ## 0.8.0 — 2026-04-15
9
62
 
10
63
  ### 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.1'
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
 
@@ -301,9 +311,9 @@ module BSV
301
311
  tx = extract_subject_transaction(beef)
302
312
 
303
313
  store_proofs_from_beef(beef)
304
- @storage.store_transaction(tx.txid_hex, tx.to_hex)
305
314
  process_internalize_outputs(tx, args[:outputs])
306
- store_action(tx, args, status: 'completed')
315
+ has_proof = !beef.find_bump(tx.txid).nil?
316
+ store_action(tx, args, status: has_proof ? 'completed' : 'unproven')
307
317
  { accepted: true }
308
318
  end
309
319
 
@@ -1068,6 +1078,25 @@ module BSV
1068
1078
 
1069
1079
  # --- Validation ---
1070
1080
 
1081
+ # Raises +WalletError+ when a broadcast is required but unavailable.
1082
+ #
1083
+ # Broadcast is required whenever +no_send+ is absent or false. Callers
1084
+ # that do not intend to broadcast on-chain must pass
1085
+ # +options: { no_send: true }+ to opt out.
1086
+ #
1087
+ # @param args [Hash] action arguments (merged, as seen at call site)
1088
+ # @raise [WalletError] if broadcast is needed but +broadcast_enabled?+ is false
1089
+ def validate_broadcast_configuration!(args)
1090
+ no_send = args.dig(:options, :no_send)
1091
+ return if no_send
1092
+ return if broadcast_enabled?
1093
+
1094
+ raise WalletError,
1095
+ 'create_action requires a broadcaster for on-chain broadcast. ' \
1096
+ 'Pass broadcaster: BSV::Network::ARC.default to WalletClient.new, ' \
1097
+ 'or options: { no_send: true } to build a transaction without broadcasting.'
1098
+ end
1099
+
1071
1100
  def validate_create_action!(args)
1072
1101
  Validators.validate_description!(args[:description])
1073
1102
  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.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Bettison
@@ -29,7 +29,7 @@ dependencies:
29
29
  requirements:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 0.11.0
32
+ version: 0.12.1
33
33
  - - "<"
34
34
  - !ruby/object:Gem::Version
35
35
  version: '1.0'
@@ -39,7 +39,7 @@ dependencies:
39
39
  requirements:
40
40
  - - ">="
41
41
  - !ruby/object:Gem::Version
42
- version: 0.11.0
42
+ version: 0.12.1
43
43
  - - "<"
44
44
  - !ruby/object:Gem::Version
45
45
  version: '1.0'