bsv-sdk 0.2.0 → 0.3.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/lib/bsv/network/broadcast_response.rb +1 -2
  4. data/lib/bsv/primitives/bsm.rb +2 -6
  5. data/lib/bsv/primitives/curve.rb +1 -2
  6. data/lib/bsv/primitives/encrypted_message.rb +100 -0
  7. data/lib/bsv/primitives/extended_key.rb +1 -2
  8. data/lib/bsv/primitives/key_shares.rb +83 -0
  9. data/lib/bsv/primitives/mnemonic.rb +1 -3
  10. data/lib/bsv/primitives/point_in_finite_field.rb +72 -0
  11. data/lib/bsv/primitives/polynomial.rb +95 -0
  12. data/lib/bsv/primitives/private_key.rb +101 -5
  13. data/lib/bsv/primitives/signed_message.rb +104 -0
  14. data/lib/bsv/primitives/symmetric_key.rb +128 -0
  15. data/lib/bsv/primitives.rb +18 -12
  16. data/lib/bsv/script/interpreter/interpreter.rb +1 -3
  17. data/lib/bsv/script/interpreter/operations/bitwise.rb +1 -3
  18. data/lib/bsv/script/interpreter/operations/crypto.rb +3 -9
  19. data/lib/bsv/script/interpreter/operations/flow_control.rb +2 -6
  20. data/lib/bsv/script/interpreter/operations/splice.rb +1 -3
  21. data/lib/bsv/script/interpreter/script_number.rb +2 -7
  22. data/lib/bsv/script/script.rb +256 -1
  23. data/lib/bsv/transaction/beef.rb +8 -11
  24. data/lib/bsv/transaction/transaction.rb +131 -59
  25. data/lib/bsv/transaction/transaction_input.rb +1 -2
  26. data/lib/bsv/transaction/transaction_output.rb +1 -2
  27. data/lib/bsv/transaction/var_int.rb +4 -16
  28. data/lib/bsv/transaction.rb +14 -14
  29. data/lib/bsv/version.rb +1 -1
  30. data/lib/bsv/wallet_interface/errors/invalid_hmac_error.rb +11 -0
  31. data/lib/bsv/wallet_interface/errors/invalid_parameter_error.rb +14 -0
  32. data/lib/bsv/wallet_interface/errors/invalid_signature_error.rb +11 -0
  33. data/lib/bsv/wallet_interface/errors/unsupported_action_error.rb +11 -0
  34. data/lib/bsv/wallet_interface/errors/wallet_error.rb +14 -0
  35. data/lib/bsv/wallet_interface/interface.rb +384 -0
  36. data/lib/bsv/wallet_interface/key_deriver.rb +142 -0
  37. data/lib/bsv/wallet_interface/memory_store.rb +115 -0
  38. data/lib/bsv/wallet_interface/proto_wallet.rb +361 -0
  39. data/lib/bsv/wallet_interface/storage_adapter.rb +51 -0
  40. data/lib/bsv/wallet_interface/validators.rb +126 -0
  41. data/lib/bsv/wallet_interface/version.rb +7 -0
  42. data/lib/bsv/wallet_interface/wallet_client.rb +486 -0
  43. data/lib/bsv/wallet_interface.rb +25 -0
  44. data/lib/bsv-wallet.rb +4 -0
  45. metadata +24 -3
  46. /data/{LICENCE → LICENSE} +0 -0
@@ -0,0 +1,486 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'base64'
5
+
6
+ module BSV
7
+ module Wallet
8
+ # BRC-100 transaction operations for the wallet interface.
9
+ #
10
+ # Implements the 7 transaction-related BRC-100 methods on top of
11
+ # {ProtoWallet}: create_action, sign_action, abort_action, list_actions,
12
+ # list_outputs, relinquish_output, and internalize_action.
13
+ #
14
+ # Transactions are built using the SDK's {BSV::Transaction::Transaction}
15
+ # class. Completed actions and tracked outputs are persisted via a
16
+ # {StorageAdapter} (defaults to {MemoryStore}).
17
+ #
18
+ # @example Create a simple transaction
19
+ # client = BSV::Wallet::WalletClient.new(private_key)
20
+ # result = client.create_action({
21
+ # description: 'Pay invoice',
22
+ # outputs: [{ locking_script: '76a914...88ac', satoshis: 1000,
23
+ # output_description: 'Payment' }]
24
+ # })
25
+ class WalletClient < ProtoWallet
26
+ # @return [StorageAdapter] the underlying persistence adapter
27
+ attr_reader :storage
28
+
29
+ # @param key [BSV::Primitives::PrivateKey, String, KeyDeriver] signing key
30
+ # @param storage [StorageAdapter] persistence adapter (default: MemoryStore)
31
+ def initialize(key, storage: MemoryStore.new)
32
+ super(key)
33
+ @storage = storage
34
+ @pending = {}
35
+ end
36
+
37
+ # --- Transaction Operations ---
38
+
39
+ # Creates a new Bitcoin transaction.
40
+ #
41
+ # If all inputs carry unlocking_script values, the transaction is
42
+ # finalised immediately and returned with :txid and :tx (BEEF bytes).
43
+ # If any input specifies only unlocking_script_length, the transaction
44
+ # is held pending and returned as a signable_transaction for external
45
+ # signing via {#sign_action}.
46
+ #
47
+ # @param args [Hash] transaction parameters
48
+ # @param _originator [String, nil] FQDN of the originating application
49
+ # @return [Hash] finalised result or signable_transaction
50
+ def create_action(args, _originator: nil)
51
+ validate_create_action!(args)
52
+ beef = parse_input_beef(args[:input_beef])
53
+ tx = build_transaction(args, beef)
54
+
55
+ if needs_signing?(args[:inputs])
56
+ create_signable(tx, args, beef)
57
+ else
58
+ finalize_action(tx, args)
59
+ end
60
+ end
61
+
62
+ # Signs a previously created signable transaction.
63
+ #
64
+ # @param args [Hash]
65
+ # @option args [Hash] :spends map of input index (Integer or String) to
66
+ # { unlocking_script: hex, sequence_number: Integer }
67
+ # @option args [String] :reference base64 reference from create_action
68
+ # @param _originator [String, nil] FQDN of the originating application
69
+ # @return [Hash] with :txid and :tx (BEEF bytes)
70
+ def sign_action(args, _originator: nil)
71
+ reference = args[:reference]
72
+ pending = @pending[reference]
73
+ raise WalletError, 'Transaction not found for the given reference' unless pending
74
+
75
+ tx = pending[:tx]
76
+ apply_spends(tx, args[:spends])
77
+ @pending.delete(reference)
78
+ finalize_action(tx, pending[:args])
79
+ end
80
+
81
+ # Aborts a pending signable transaction.
82
+ #
83
+ # @param args [Hash]
84
+ # @option args [String] :reference base64 reference to abort
85
+ # @param _originator [String, nil] FQDN of the originating application
86
+ # @return [Hash] { aborted: true }
87
+ def abort_action(args, _originator: nil)
88
+ reference = args[:reference]
89
+ raise WalletError, 'Transaction not found for the given reference' unless @pending.key?(reference)
90
+
91
+ @pending.delete(reference)
92
+ { aborted: true }
93
+ end
94
+
95
+ # Lists stored actions matching the given labels.
96
+ #
97
+ # @param args [Hash]
98
+ # @option args [Array<String>] :labels (required) labels to filter by
99
+ # @option args [String] :label_query_mode 'any' (default) or 'all'
100
+ # @option args [Integer] :limit max results (default 10)
101
+ # @option args [Integer] :offset results to skip (default 0)
102
+ # @param _originator [String, nil] FQDN of the originating application
103
+ # @return [Hash] { total_actions: Integer, actions: Array }
104
+ def list_actions(args, _originator: nil)
105
+ validate_list_actions!(args)
106
+ query = build_action_query(args)
107
+ total = @storage.count_actions(query)
108
+ actions = @storage.find_actions(query)
109
+ { total_actions: total, actions: actions }
110
+ end
111
+
112
+ # Lists spendable outputs in a basket.
113
+ #
114
+ # @param args [Hash]
115
+ # @option args [String] :basket (required) basket name
116
+ # @option args [Array<String>] :tags optional tag filter
117
+ # @option args [String] :tag_query_mode 'any' (default) or 'all'
118
+ # @option args [Integer] :limit max results (default 10)
119
+ # @option args [Integer] :offset results to skip (default 0)
120
+ # @param _originator [String, nil] FQDN of the originating application
121
+ # @return [Hash] { total_outputs: Integer, outputs: Array }
122
+ def list_outputs(args, _originator: nil)
123
+ validate_list_outputs!(args)
124
+ query = build_output_query(args)
125
+ total = @storage.count_outputs(query)
126
+ outputs = @storage.find_outputs(query)
127
+ { total_outputs: total, outputs: outputs }
128
+ end
129
+
130
+ # Removes an output from basket tracking.
131
+ #
132
+ # @param args [Hash]
133
+ # @option args [String] :basket basket name
134
+ # @option args [String] :output outpoint string
135
+ # @param _originator [String, nil] FQDN of the originating application
136
+ # @return [Hash] { relinquished: true }
137
+ def relinquish_output(args, _originator: nil)
138
+ Validators.validate_basket!(args[:basket])
139
+ Validators.validate_outpoint!(args[:output])
140
+ raise WalletError, 'Output not found' unless @storage.delete_output(args[:output])
141
+
142
+ { relinquished: true }
143
+ end
144
+
145
+ # Accepts an incoming transaction for wallet internalization.
146
+ #
147
+ # Parses the BEEF, locates the subject transaction, processes each
148
+ # specified output according to its protocol (wallet payment or basket
149
+ # insertion), and stores the action.
150
+ #
151
+ # @param args [Hash]
152
+ # @option args [Array<Integer>] :tx Atomic BEEF-formatted transaction as byte array
153
+ # @option args [Array<Hash>] :outputs output metadata
154
+ # @option args [String] :description 5-50 char description
155
+ # @option args [Array<String>] :labels optional labels
156
+ # @param _originator [String, nil] FQDN of the originating application
157
+ # @return [Hash] { accepted: true }
158
+ def internalize_action(args, _originator: nil)
159
+ validate_internalize_action!(args)
160
+ beef_binary = args[:tx].pack('C*')
161
+ beef = BSV::Transaction::Beef.from_binary(beef_binary)
162
+ tx = extract_subject_transaction(beef)
163
+
164
+ process_internalize_outputs(tx, args[:outputs])
165
+ store_action(tx, args, status: 'completed')
166
+ { accepted: true }
167
+ end
168
+
169
+ private
170
+
171
+ # --- Validation ---
172
+
173
+ def validate_create_action!(args)
174
+ Validators.validate_description!(args[:description])
175
+ inputs_present = args[:inputs] && !args[:inputs].empty?
176
+ outputs_present = args[:outputs] && !args[:outputs].empty?
177
+ raise InvalidParameterError.new('inputs/outputs', 'at least one input or output') unless inputs_present || outputs_present
178
+
179
+ validate_action_inputs!(args[:inputs]) if args[:inputs]
180
+ validate_action_outputs!(args[:outputs]) if args[:outputs]
181
+ args[:labels]&.each { |l| Validators.validate_label!(l) }
182
+ end
183
+
184
+ def validate_action_inputs!(inputs)
185
+ inputs.each do |input|
186
+ Validators.validate_outpoint!(input[:outpoint])
187
+ Validators.validate_description!(input[:input_description], 'input_description')
188
+ unless input[:unlocking_script] || input[:unlocking_script_length]
189
+ raise InvalidParameterError.new('unlocking_script',
190
+ 'provided, or unlocking_script_length must be set')
191
+ end
192
+ end
193
+ end
194
+
195
+ def validate_action_outputs!(outputs)
196
+ outputs.each do |output|
197
+ Validators.validate_hex_string!(output[:locking_script], 'locking_script')
198
+ Validators.validate_satoshis!(output[:satoshis])
199
+ Validators.validate_description!(output[:output_description], 'output_description')
200
+ Validators.validate_basket!(output[:basket]) if output[:basket]
201
+ output[:tags]&.each { |t| Validators.validate_tag!(t) }
202
+ end
203
+ end
204
+
205
+ def validate_list_actions!(args)
206
+ raise InvalidParameterError.new('labels', 'a non-empty Array') unless args[:labels].is_a?(Array) && !args[:labels].empty?
207
+
208
+ args[:labels].each { |l| Validators.validate_label!(l) }
209
+ end
210
+
211
+ def validate_list_outputs!(args)
212
+ Validators.validate_basket!(args[:basket])
213
+ args[:tags]&.each { |t| Validators.validate_tag!(t) }
214
+ end
215
+
216
+ def validate_internalize_action!(args)
217
+ raise InvalidParameterError.new('tx', 'a byte array') unless args[:tx].is_a?(Array)
218
+ raise InvalidParameterError.new('outputs', 'a non-empty Array') unless args[:outputs].is_a?(Array) && !args[:outputs].empty?
219
+
220
+ Validators.validate_description!(args[:description])
221
+ args[:labels]&.each { |l| Validators.validate_label!(l) }
222
+ end
223
+
224
+ # --- Transaction building ---
225
+
226
+ def parse_input_beef(input_beef)
227
+ return unless input_beef
228
+
229
+ BSV::Transaction::Beef.from_binary(input_beef.pack('C*'))
230
+ end
231
+
232
+ def build_transaction(args, beef)
233
+ version = args.fetch(:version, 1)
234
+ lock_time = args.fetch(:lock_time, 0)
235
+ tx = BSV::Transaction::Transaction.new(version: version, lock_time: lock_time)
236
+
237
+ build_inputs(tx, args[:inputs], beef) if args[:inputs]
238
+ build_outputs(tx, args[:outputs]) if args[:outputs]
239
+
240
+ # Randomise output order unless explicitly disabled
241
+ shuffle_outputs(tx) if args[:inputs] && args[:outputs] && args.dig(:options, :randomize_outputs) != false
242
+
243
+ tx
244
+ end
245
+
246
+ def build_inputs(tx, inputs, beef)
247
+ inputs.each do |spec|
248
+ txid_hex, index_str = spec[:outpoint].split('.')
249
+ output_index = index_str.to_i
250
+ seq = spec[:sequence_number] || 0xFFFFFFFF
251
+
252
+ input = BSV::Transaction::TransactionInput.new(
253
+ prev_tx_id: BSV::Transaction::TransactionInput.txid_from_hex(txid_hex),
254
+ prev_tx_out_index: output_index,
255
+ sequence: seq
256
+ )
257
+
258
+ wire_source(input, txid_hex, output_index, beef) if beef
259
+
260
+ input.unlocking_script = BSV::Script::Script.from_hex(spec[:unlocking_script]) if spec[:unlocking_script]
261
+
262
+ tx.add_input(input)
263
+ end
264
+ end
265
+
266
+ def wire_source(input, txid_hex, output_index, beef)
267
+ # find_transaction expects display byte order (32 raw bytes)
268
+ txid_display = [txid_hex].pack('H*')
269
+ source_beef_tx = beef.transactions.find { |bt| bt.transaction&.txid == txid_display }
270
+ return unless source_beef_tx
271
+
272
+ source_tx = source_beef_tx.transaction
273
+ input.source_transaction = source_tx
274
+ return unless source_tx.outputs[output_index]
275
+
276
+ input.source_satoshis = source_tx.outputs[output_index].satoshis
277
+ input.source_locking_script = source_tx.outputs[output_index].locking_script
278
+ end
279
+
280
+ def build_outputs(tx, outputs)
281
+ outputs.each do |spec|
282
+ output = BSV::Transaction::TransactionOutput.new(
283
+ satoshis: spec[:satoshis],
284
+ locking_script: BSV::Script::Script.from_hex(spec[:locking_script])
285
+ )
286
+ # Tag the output with its spec so store_tracked_outputs can find the
287
+ # correct post-shuffle index, even when multiple outputs share the
288
+ # same locking script and satoshis.
289
+ output.instance_variable_set(:@_spec, spec)
290
+ tx.add_output(output)
291
+ end
292
+ end
293
+
294
+ def shuffle_outputs(tx)
295
+ shuffled = tx.outputs.shuffle
296
+ tx.outputs.clear
297
+ shuffled.each { |o| tx.add_output(o) }
298
+ end
299
+
300
+ def needs_signing?(inputs)
301
+ return false unless inputs
302
+
303
+ inputs.any? { |i| i[:unlocking_script_length] && !i[:unlocking_script] }
304
+ end
305
+
306
+ # --- Finalisation ---
307
+
308
+ def create_signable(tx, args, beef)
309
+ reference = Base64.strict_encode64(SecureRandom.random_bytes(32))
310
+ @pending[reference] = { tx: tx, args: args, beef: beef }
311
+ tx_bytes = tx.to_binary
312
+ { signable_transaction: { tx: tx_bytes.unpack('C*'), reference: reference } }
313
+ end
314
+
315
+ def finalize_action(tx, args)
316
+ txid = tx.txid_hex
317
+ status = args.dig(:options, :no_send) ? 'nosend' : 'completed'
318
+
319
+ store_action(tx, args, status: status)
320
+ store_tracked_outputs(txid, tx, args[:outputs])
321
+
322
+ beef_binary = tx.to_beef
323
+ result = { txid: txid, tx: beef_binary.unpack('C*') }
324
+ result[:no_send_change] = [] if args.dig(:options, :no_send)
325
+ result
326
+ end
327
+
328
+ def apply_spends(tx, spends)
329
+ spends.each do |index, spend|
330
+ idx = index.is_a?(String) ? index.to_i : index
331
+ raise WalletError, "Input index #{idx} out of range" unless tx.inputs[idx]
332
+
333
+ tx.inputs[idx].unlocking_script = BSV::Script::Script.from_hex(spend[:unlocking_script])
334
+ # sequence is attr_reader only; re-set via instance_variable_set if provided
335
+ tx.inputs[idx].instance_variable_set(:@sequence, spend[:sequence_number]) if spend[:sequence_number]
336
+ end
337
+ end
338
+
339
+ # --- Storage helpers ---
340
+
341
+ def store_action(tx, args, status: 'completed')
342
+ @storage.store_action({
343
+ txid: tx.txid_hex,
344
+ status: status,
345
+ description: args[:description],
346
+ labels: args[:labels] || [],
347
+ is_outgoing: true,
348
+ satoshis: tx.total_output_satoshis,
349
+ version: tx.version,
350
+ lock_time: tx.lock_time,
351
+ created_at: Time.now.utc.iso8601
352
+ })
353
+ end
354
+
355
+ def store_tracked_outputs(txid, tx, output_specs)
356
+ return unless output_specs
357
+
358
+ output_specs.each do |spec|
359
+ next unless spec[:basket]
360
+
361
+ # Find the actual post-shuffle index by matching the TransactionOutput object.
362
+ # build_outputs stores a reference on each output via instance_variable_set(:@_spec)
363
+ # so we can reliably map even when multiple outputs share the same script/satoshis.
364
+ actual_idx = tx.outputs.index { |o| o.instance_variable_get(:@_spec).equal?(spec) }
365
+ next unless actual_idx
366
+
367
+ @storage.store_output({
368
+ outpoint: "#{txid}.#{actual_idx}",
369
+ satoshis: spec[:satoshis],
370
+ locking_script: spec[:locking_script],
371
+ basket: spec[:basket],
372
+ tags: spec[:tags] || [],
373
+ custom_instructions: spec[:custom_instructions],
374
+ spendable: true
375
+ })
376
+ end
377
+ end
378
+
379
+ def build_action_query(args)
380
+ {
381
+ labels: args[:labels],
382
+ label_query_mode: args[:label_query_mode] || 'any',
383
+ limit: args[:limit] || 10,
384
+ offset: args[:offset] || 0
385
+ }
386
+ end
387
+
388
+ def build_output_query(args)
389
+ query = {
390
+ basket: args[:basket],
391
+ limit: args[:limit] || 10,
392
+ offset: args[:offset] || 0
393
+ }
394
+ query[:tags] = args[:tags] if args[:tags]
395
+ query[:tag_query_mode] = args[:tag_query_mode] if args[:tag_query_mode]
396
+ query
397
+ end
398
+
399
+ # --- Internalize helpers ---
400
+
401
+ def extract_subject_transaction(beef)
402
+ return find_by_subject_txid(beef) if beef.subject_txid
403
+
404
+ last_beef_tx = beef.transactions.reverse.find(&:transaction)
405
+ raise WalletError, 'No transaction found in BEEF' unless last_beef_tx
406
+
407
+ last_beef_tx.transaction
408
+ end
409
+
410
+ def find_by_subject_txid(beef)
411
+ beef.find_atomic_transaction(beef.subject_txid) ||
412
+ raise(WalletError, 'Subject transaction not found in BEEF')
413
+ end
414
+
415
+ def process_internalize_outputs(tx, output_specs)
416
+ txid = tx.txid_hex
417
+
418
+ output_specs.each do |spec|
419
+ output_index = spec[:output_index]
420
+ tx_output = tx.outputs[output_index]
421
+ raise WalletError, "Output index #{output_index} not found in transaction" unless tx_output
422
+
423
+ case spec[:protocol]
424
+ when 'wallet payment'
425
+ internalize_payment(txid, output_index, tx_output, spec[:payment_remittance])
426
+ when 'basket insertion'
427
+ internalize_basket(txid, output_index, tx_output, spec[:insertion_remittance])
428
+ else
429
+ raise InvalidParameterError.new('protocol', '"wallet payment" or "basket insertion"')
430
+ end
431
+ end
432
+ end
433
+
434
+ def internalize_payment(txid, output_index, tx_output, remittance)
435
+ unless remittance
436
+ raise InvalidParameterError.new('payment_remittance',
437
+ 'present for wallet payment protocol')
438
+ end
439
+
440
+ sender_key = remittance[:sender_identity_key]
441
+ prefix = remittance[:derivation_prefix]
442
+ suffix = remittance[:derivation_suffix]
443
+
444
+ # BRC-29: derive the expected P2PKH key for this payment
445
+ derived_pub = @key_deriver.derive_public_key(
446
+ [2, '3241645161d8'],
447
+ "#{prefix} #{suffix}",
448
+ sender_key,
449
+ for_self: true
450
+ )
451
+ expected_script = BSV::Script::Script.p2pkh_lock(derived_pub.hash160)
452
+
453
+ raise WalletError, 'Output script does not match derived payment key' unless tx_output.locking_script.to_binary == expected_script.to_binary
454
+
455
+ @storage.store_output({
456
+ outpoint: "#{txid}.#{output_index}",
457
+ satoshis: tx_output.satoshis,
458
+ locking_script: tx_output.locking_script.to_hex,
459
+ spendable: true,
460
+ sender_identity_key: sender_key,
461
+ derivation_prefix: prefix,
462
+ derivation_suffix: suffix
463
+ })
464
+ end
465
+
466
+ def internalize_basket(txid, output_index, tx_output, remittance)
467
+ unless remittance
468
+ raise InvalidParameterError.new('insertion_remittance',
469
+ 'present for basket insertion protocol')
470
+ end
471
+
472
+ Validators.validate_basket!(remittance[:basket])
473
+
474
+ @storage.store_output({
475
+ outpoint: "#{txid}.#{output_index}",
476
+ satoshis: tx_output.satoshis,
477
+ locking_script: tx_output.locking_script.to_hex,
478
+ basket: remittance[:basket],
479
+ tags: remittance[:tags] || [],
480
+ custom_instructions: remittance[:custom_instructions],
481
+ spendable: true
482
+ })
483
+ end
484
+ end
485
+ end
486
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSV
4
+ module WalletInterface
5
+ autoload :VERSION, 'bsv/wallet_interface/version'
6
+ end
7
+
8
+ module Wallet
9
+ # BRC-100 Interface
10
+ autoload :Interface, 'bsv/wallet_interface/interface'
11
+ autoload :KeyDeriver, 'bsv/wallet_interface/key_deriver'
12
+ autoload :ProtoWallet, 'bsv/wallet_interface/proto_wallet'
13
+ autoload :Validators, 'bsv/wallet_interface/validators'
14
+ autoload :StorageAdapter, 'bsv/wallet_interface/storage_adapter'
15
+ autoload :MemoryStore, 'bsv/wallet_interface/memory_store'
16
+ autoload :WalletClient, 'bsv/wallet_interface/wallet_client'
17
+
18
+ # Error classes
19
+ autoload :WalletError, 'bsv/wallet_interface/errors/wallet_error'
20
+ autoload :InvalidParameterError, 'bsv/wallet_interface/errors/invalid_parameter_error'
21
+ autoload :InvalidHmacError, 'bsv/wallet_interface/errors/invalid_hmac_error'
22
+ autoload :InvalidSignatureError, 'bsv/wallet_interface/errors/invalid_signature_error'
23
+ autoload :UnsupportedActionError, 'bsv/wallet_interface/errors/unsupported_action_error'
24
+ end
25
+ end
data/lib/bsv-wallet.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bsv-sdk'
4
+ require_relative 'bsv/wallet_interface'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bsv-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Bettison
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-03-07 00:00:00.000000000 Z
10
+ date: 2026-03-27 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: A Ruby library for interacting with the BSV Blockchain — keys, scripts,
13
13
  transactions, and more.
@@ -16,10 +16,11 @@ extensions: []
16
16
  extra_rdoc_files: []
17
17
  files:
18
18
  - CHANGELOG.md
19
- - LICENCE
19
+ - LICENSE
20
20
  - README.md
21
21
  - lib/bsv-attest.rb
22
22
  - lib/bsv-sdk.rb
23
+ - lib/bsv-wallet.rb
23
24
  - lib/bsv/attest.rb
24
25
  - lib/bsv/attest/configuration.rb
25
26
  - lib/bsv/attest/response.rb
@@ -39,13 +40,19 @@ files:
39
40
  - lib/bsv/primitives/digest.rb
40
41
  - lib/bsv/primitives/ecdsa.rb
41
42
  - lib/bsv/primitives/ecies.rb
43
+ - lib/bsv/primitives/encrypted_message.rb
42
44
  - lib/bsv/primitives/extended_key.rb
45
+ - lib/bsv/primitives/key_shares.rb
43
46
  - lib/bsv/primitives/mnemonic.rb
44
47
  - lib/bsv/primitives/mnemonic/wordlist.rb
48
+ - lib/bsv/primitives/point_in_finite_field.rb
49
+ - lib/bsv/primitives/polynomial.rb
45
50
  - lib/bsv/primitives/private_key.rb
46
51
  - lib/bsv/primitives/public_key.rb
47
52
  - lib/bsv/primitives/schnorr.rb
48
53
  - lib/bsv/primitives/signature.rb
54
+ - lib/bsv/primitives/signed_message.rb
55
+ - lib/bsv/primitives/symmetric_key.rb
49
56
  - lib/bsv/script.rb
50
57
  - lib/bsv/script/builder.rb
51
58
  - lib/bsv/script/chunk.rb
@@ -83,6 +90,20 @@ files:
83
90
  - lib/bsv/wallet.rb
84
91
  - lib/bsv/wallet/insufficient_funds_error.rb
85
92
  - lib/bsv/wallet/wallet.rb
93
+ - lib/bsv/wallet_interface.rb
94
+ - lib/bsv/wallet_interface/errors/invalid_hmac_error.rb
95
+ - lib/bsv/wallet_interface/errors/invalid_parameter_error.rb
96
+ - lib/bsv/wallet_interface/errors/invalid_signature_error.rb
97
+ - lib/bsv/wallet_interface/errors/unsupported_action_error.rb
98
+ - lib/bsv/wallet_interface/errors/wallet_error.rb
99
+ - lib/bsv/wallet_interface/interface.rb
100
+ - lib/bsv/wallet_interface/key_deriver.rb
101
+ - lib/bsv/wallet_interface/memory_store.rb
102
+ - lib/bsv/wallet_interface/proto_wallet.rb
103
+ - lib/bsv/wallet_interface/storage_adapter.rb
104
+ - lib/bsv/wallet_interface/validators.rb
105
+ - lib/bsv/wallet_interface/version.rb
106
+ - lib/bsv/wallet_interface/wallet_client.rb
86
107
  homepage: https://github.com/sgbett/bsv-ruby-sdk
87
108
  licenses:
88
109
  - LicenseRef-OpenBSV
File without changes