bsv-sdk 0.19.1 → 0.22.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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +89 -0
  3. data/README.md +2 -2
  4. data/lib/bsv/auth/transport.rb +1 -1
  5. data/lib/bsv/mcp/tools/broadcast_p2pkh.rb +5 -3
  6. data/lib/bsv/network/protocol.rb +4 -5
  7. data/lib/bsv/network/protocols/arc.rb +4 -30
  8. data/lib/bsv/network/protocols/arcade.rb +163 -0
  9. data/lib/bsv/network/protocols/chaintracks.rb +6 -3
  10. data/lib/bsv/network/protocols/jungle_bus.rb +6 -0
  11. data/lib/bsv/network/protocols.rb +1 -0
  12. data/lib/bsv/network/provider.rb +7 -9
  13. data/lib/bsv/network/providers/gorilla_pool.rb +18 -18
  14. data/lib/bsv/network/util.rb +44 -0
  15. data/lib/bsv/network.rb +1 -0
  16. data/lib/bsv/overlay/lookup_resolver.rb +0 -1
  17. data/lib/bsv/overlay/topic_broadcaster.rb +0 -1
  18. data/lib/bsv/primitives/curve.rb +1 -11
  19. data/lib/bsv/primitives/ecies.rb +1 -8
  20. data/lib/bsv/primitives/hex.rb +1 -1
  21. data/lib/bsv/script/script.rb +1 -1
  22. data/lib/bsv/transaction/beef.rb +0 -2
  23. data/lib/bsv/transaction/chain_tracker.rb +74 -13
  24. data/lib/bsv/transaction/chain_trackers/whats_on_chain.rb +3 -3
  25. data/lib/bsv/transaction/chain_trackers.rb +0 -10
  26. data/lib/bsv/transaction/fee_models/live_policy.rb +10 -8
  27. data/lib/bsv/transaction/merkle_path.rb +0 -2
  28. data/lib/bsv/version.rb +1 -1
  29. data/lib/bsv/wallet/errors.rb +65 -21
  30. data/lib/bsv/wallet/proto_wallet/validators.rb +7 -49
  31. data/lib/bsv/wallet/proto_wallet.rb +15 -8
  32. data/lib/bsv/wallet/serializer/abort_action.rb +38 -0
  33. data/lib/bsv/wallet/serializer/acquire_certificate.rb +171 -0
  34. data/lib/bsv/wallet/serializer/certificate.rb +184 -0
  35. data/lib/bsv/wallet/serializer/common.rb +207 -0
  36. data/lib/bsv/wallet/serializer/create_action_args.rb +259 -0
  37. data/lib/bsv/wallet/serializer/create_action_result.rb +85 -0
  38. data/lib/bsv/wallet/serializer/create_hmac.rb +67 -0
  39. data/lib/bsv/wallet/serializer/create_signature.rb +90 -0
  40. data/lib/bsv/wallet/serializer/decrypt.rb +60 -0
  41. data/lib/bsv/wallet/serializer/discover_by_attributes.rb +61 -0
  42. data/lib/bsv/wallet/serializer/discover_by_identity_key.rb +49 -0
  43. data/lib/bsv/wallet/serializer/discover_certificates_result.rb +39 -0
  44. data/lib/bsv/wallet/serializer/encrypt.rb +60 -0
  45. data/lib/bsv/wallet/serializer/get_header_for_height.rb +71 -0
  46. data/lib/bsv/wallet/serializer/get_height.rb +46 -0
  47. data/lib/bsv/wallet/serializer/get_network.rb +65 -0
  48. data/lib/bsv/wallet/serializer/get_public_key.rb +86 -0
  49. data/lib/bsv/wallet/serializer/get_version.rb +44 -0
  50. data/lib/bsv/wallet/serializer/internalize_action.rb +151 -0
  51. data/lib/bsv/wallet/serializer/list_actions.rb +348 -0
  52. data/lib/bsv/wallet/serializer/list_certificates.rb +124 -0
  53. data/lib/bsv/wallet/serializer/list_outputs.rb +167 -0
  54. data/lib/bsv/wallet/serializer/prove_certificate.rb +146 -0
  55. data/lib/bsv/wallet/serializer/relinquish_certificate.rb +56 -0
  56. data/lib/bsv/wallet/serializer/relinquish_output.rb +44 -0
  57. data/lib/bsv/wallet/serializer/reveal_counterparty_key_linkage.rb +108 -0
  58. data/lib/bsv/wallet/serializer/reveal_specific_key_linkage.rb +116 -0
  59. data/lib/bsv/wallet/serializer/sign_action_args.rb +94 -0
  60. data/lib/bsv/wallet/serializer/sign_action_result.rb +49 -0
  61. data/lib/bsv/wallet/serializer/status.rb +85 -0
  62. data/lib/bsv/wallet/serializer/verify_hmac.rb +67 -0
  63. data/lib/bsv/wallet/serializer/verify_signature.rb +101 -0
  64. data/lib/bsv/wallet/serializer.rb +180 -0
  65. data/lib/bsv/wallet/substrates/http_wallet_json.rb +129 -0
  66. data/lib/bsv/wallet/substrates/http_wallet_wire.rb +99 -0
  67. data/lib/bsv/wallet/wallet_wire.rb +20 -0
  68. data/lib/bsv/wallet/wallet_wire_processor.rb +61 -0
  69. data/lib/bsv/wallet/wallet_wire_transceiver.rb +61 -0
  70. data/lib/bsv/wallet/wire/calls.rb +79 -0
  71. data/lib/bsv/wallet/wire/frame.rb +181 -0
  72. data/lib/bsv/wallet/wire/reader_writer.rb +402 -0
  73. data/lib/bsv/wallet/wire/validation.rb +213 -0
  74. data/lib/bsv/wallet/wire.rb +13 -0
  75. data/lib/bsv/wallet.rb +17 -0
  76. metadata +47 -3
  77. data/lib/bsv/transaction/chain_trackers/chaintracks.rb +0 -83
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ module BSV
6
+ module Wallet
7
+ module Serializer
8
+ # BRC-103 wire codec for the +prove_certificate+ call (call byte 19).
9
+ #
10
+ # Args wire layout (matches go-sdk SerializeProveCertificateArgs):
11
+ # [32 bytes: cert.type]
12
+ # [33 bytes: cert.subject pubkey]
13
+ # [32 bytes: cert.serial_number]
14
+ # [33 bytes: cert.certifier pubkey]
15
+ # [36 bytes: cert.revocation_outpoint]
16
+ # [varint-int: cert.signature bytes] (0-length if nil)
17
+ # [varint: field_count] per field: [varint-int name_bytes][varint-int value_bytes]
18
+ # [varint: fields_to_reveal_count] per field: [varint-int name_bytes]
19
+ # [33 bytes: verifier pubkey]
20
+ # [privileged params]
21
+ #
22
+ # Result wire layout:
23
+ # [varint: keyring_count] per entry: [varint-int key_bytes][varint-int base64 bytes]
24
+ module ProveCertificate
25
+ CERT_TYPE_SIZE = 32
26
+ SERIAL_SIZE = 32
27
+ PUBKEY_SIZE = 33
28
+
29
+ module_function
30
+
31
+ def serialize_args(args)
32
+ w = Wire::Writer.new
33
+ cert = args[:certificate] || {}
34
+
35
+ type_bytes = Base64.strict_decode64(cert[:type].to_s)
36
+ w.write_bytes(type_bytes.ljust(CERT_TYPE_SIZE, "\x00").byteslice(0, CERT_TYPE_SIZE))
37
+ w.write_bytes([cert[:subject].to_s].pack('H*'))
38
+
39
+ serial_bytes = Base64.strict_decode64(cert[:serial_number].to_s)
40
+ w.write_bytes(serial_bytes.ljust(SERIAL_SIZE, "\x00").byteslice(0, SERIAL_SIZE))
41
+ w.write_bytes([cert[:certifier].to_s].pack('H*'))
42
+
43
+ outpoint_str = cert[:revocation_outpoint].to_s
44
+ if outpoint_str.empty? || outpoint_str == '.'
45
+ w.write_outpoint(Certificate::NULL_TXID_HEX, 0)
46
+ else
47
+ txid_hex, vout = outpoint_str.split('.', 2)
48
+ w.write_outpoint(txid_hex.to_s, vout.to_i)
49
+ end
50
+
51
+ sig = cert[:signature]
52
+ if sig && !sig.to_s.empty?
53
+ w.write_int_bytes([sig.to_s].pack('H*'))
54
+ else
55
+ w.write_int_bytes(''.b)
56
+ end
57
+
58
+ fields = cert[:fields] || {}
59
+ w.write_varint(fields.length)
60
+ fields.keys.sort.each do |k|
61
+ w.write_int_bytes(k.b)
62
+ w.write_int_bytes(fields[k].to_s.b)
63
+ end
64
+
65
+ fields_to_reveal = args[:fields_to_reveal] || []
66
+ w.write_varint(fields_to_reveal.length)
67
+ fields_to_reveal.each { |f| w.write_int_bytes(f.to_s.b) }
68
+
69
+ w.write_bytes([args[:verifier].to_s].pack('H*'))
70
+
71
+ Common.write_privileged_params(w, args[:privileged], args[:privileged_reason])
72
+ w.buf
73
+ end
74
+
75
+ def deserialize_args(bytes)
76
+ r = Wire::Reader.new(bytes)
77
+
78
+ type_raw = r.read_bytes(CERT_TYPE_SIZE)
79
+ subject = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
80
+ serial_raw = r.read_bytes(SERIAL_SIZE)
81
+ certifier = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
82
+
83
+ outpoint_data = r.read_outpoint
84
+ revocation_outpoint = "#{outpoint_data[:txid_hex]}.#{outpoint_data[:vout]}"
85
+
86
+ sig_bytes = r.read_int_bytes
87
+ signature = sig_bytes.empty? ? nil : sig_bytes.unpack1('H*')
88
+
89
+ field_count = r.read_varint
90
+ fields = {}
91
+ field_count.times do
92
+ k = r.read_int_bytes.force_encoding('UTF-8')
93
+ v = r.read_int_bytes.force_encoding('UTF-8')
94
+ fields[k] = v
95
+ end
96
+
97
+ fields_to_reveal_count = r.read_varint
98
+ fields_to_reveal = fields_to_reveal_count.times.map do
99
+ r.read_int_bytes.force_encoding('UTF-8')
100
+ end
101
+
102
+ verifier = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
103
+ privileged, privileged_reason = Common.read_privileged_params(r)
104
+
105
+ {
106
+ certificate: {
107
+ type: Base64.strict_encode64(type_raw),
108
+ subject: subject,
109
+ serial_number: Base64.strict_encode64(serial_raw),
110
+ certifier: certifier,
111
+ revocation_outpoint: revocation_outpoint,
112
+ signature: signature,
113
+ fields: fields
114
+ },
115
+ fields_to_reveal: fields_to_reveal,
116
+ verifier: verifier,
117
+ privileged: privileged,
118
+ privileged_reason: privileged_reason
119
+ }
120
+ end
121
+
122
+ def serialize_result(result)
123
+ w = Wire::Writer.new
124
+ keyring = result[:keyring_for_verifier] || {}
125
+ w.write_varint(keyring.length)
126
+ keyring.keys.sort.each do |k|
127
+ w.write_int_bytes(k.to_s.b)
128
+ w.write_int_from_base64(keyring[k].to_s)
129
+ end
130
+ w.buf
131
+ end
132
+
133
+ def deserialize_result(bytes)
134
+ r = Wire::Reader.new(bytes)
135
+ count = r.read_varint
136
+ keyring = {}
137
+ count.times do
138
+ k = r.read_int_bytes.force_encoding('UTF-8')
139
+ keyring[k] = r.read_base64_int
140
+ end
141
+ { keyring_for_verifier: keyring }
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ module BSV
6
+ module Wallet
7
+ module Serializer
8
+ # BRC-103 wire codec for the +relinquish_certificate+ call (call byte 20).
9
+ #
10
+ # Args wire layout:
11
+ # [32 bytes: type]
12
+ # [32 bytes: serial_number]
13
+ # [33 bytes: certifier pubkey]
14
+ #
15
+ # Result wire layout:
16
+ # [empty — relinquished is implicit from the frame error byte]
17
+ module RelinquishCertificate
18
+ CERT_TYPE_SIZE = 32
19
+ SERIAL_SIZE = 32
20
+ PUBKEY_SIZE = 33
21
+
22
+ module_function
23
+
24
+ def serialize_args(args)
25
+ w = Wire::Writer.new
26
+ type_bytes = Base64.strict_decode64(args[:type].to_s)
27
+ w.write_bytes(type_bytes.ljust(CERT_TYPE_SIZE, "\x00").byteslice(0, CERT_TYPE_SIZE))
28
+ serial_bytes = Base64.strict_decode64(args[:serial_number].to_s)
29
+ w.write_bytes(serial_bytes.ljust(SERIAL_SIZE, "\x00").byteslice(0, SERIAL_SIZE))
30
+ w.write_bytes([args[:certifier].to_s].pack('H*'))
31
+ w.buf
32
+ end
33
+
34
+ def deserialize_args(bytes)
35
+ r = Wire::Reader.new(bytes)
36
+ type_raw = r.read_bytes(CERT_TYPE_SIZE)
37
+ serial_raw = r.read_bytes(SERIAL_SIZE)
38
+ certifier = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
39
+ {
40
+ type: Base64.strict_encode64(type_raw),
41
+ serial_number: Base64.strict_encode64(serial_raw),
42
+ certifier: certifier
43
+ }
44
+ end
45
+
46
+ def serialize_result(_result)
47
+ ''.b
48
+ end
49
+
50
+ def deserialize_result(_bytes)
51
+ { relinquished: true }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSV
4
+ module Wallet
5
+ module Serializer
6
+ # BRC-103 wire codec for the +relinquish_output+ call (call byte 7).
7
+ #
8
+ # Args wire layout:
9
+ # [varint-str: basket]
10
+ # [32-byte wire txid][varint vout]
11
+ #
12
+ # Result wire layout:
13
+ # [empty — relinquished is implicit from the frame error byte]
14
+ module RelinquishOutput
15
+ module_function
16
+
17
+ def serialize_args(args)
18
+ Wire::Validation.outpoint_string!('output', args[:output].to_s)
19
+ txid_hex, vout = args[:output].to_s.split('.', 2)
20
+ w = Wire::Writer.new
21
+ w.write_str_with_varint_len(args.fetch(:basket, ''))
22
+ w.write_outpoint(txid_hex, vout.to_i)
23
+ w.buf
24
+ end
25
+
26
+ def deserialize_args(bytes)
27
+ r = Wire::Reader.new(bytes)
28
+ basket = r.read_str_with_varint_len
29
+ outpoint_data = r.read_outpoint
30
+ output = "#{outpoint_data[:txid_hex]}.#{outpoint_data[:vout]}"
31
+ { basket: basket, output: output }
32
+ end
33
+
34
+ def serialize_result(_result)
35
+ ''.b
36
+ end
37
+
38
+ def deserialize_result(_bytes)
39
+ { relinquished: true }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSV
4
+ module Wallet
5
+ module Serializer
6
+ # BRC-103 wire codec for the +reveal_counterparty_key_linkage+ call (call byte 9).
7
+ #
8
+ # Port of go-sdk/wallet/serializer/reveal_counterparty_key_linkage.go.
9
+ module RevealCounterpartyKeyLinkage
10
+ PUBKEY_SIZE = 33
11
+
12
+ # Args wire layout:
13
+ # [privileged params]
14
+ # [33 bytes: counterparty compressed pubkey]
15
+ # [33 bytes: verifier compressed pubkey]
16
+ module Args
17
+ module_function
18
+
19
+ def serialize(args)
20
+ counterparty = args[:counterparty]
21
+ verifier = args[:verifier]
22
+ raise BSV::Wallet::InvalidParameterError.new('counterparty', 'a 33-byte binary pubkey or 66-char hex') unless counterparty
23
+ raise BSV::Wallet::InvalidParameterError.new('verifier', 'a 33-byte binary pubkey or 66-char hex') unless verifier
24
+
25
+ w = BSV::Wallet::Wire::Writer.new
26
+ Common.write_privileged_params(w, args[:privileged], args[:privileged_reason])
27
+ w.write_bytes(pubkey_bytes(counterparty))
28
+ w.write_bytes(pubkey_bytes(verifier))
29
+ w.buf
30
+ end
31
+
32
+ def deserialize(bytes)
33
+ r = BSV::Wallet::Wire::Reader.new(bytes)
34
+ privileged, reason = Common.read_privileged_params(r)
35
+ counterparty = r.read_bytes(PUBKEY_SIZE)
36
+ verifier = r.read_bytes(PUBKEY_SIZE)
37
+ {
38
+ privileged: privileged,
39
+ privileged_reason: reason,
40
+ counterparty: counterparty,
41
+ verifier: verifier
42
+ }
43
+ end
44
+
45
+ def pubkey_bytes(value)
46
+ return value.b if value.is_a?(String) && value.bytesize == PUBKEY_SIZE
47
+
48
+ [value.to_s].pack('H*')
49
+ end
50
+ private_class_method :pubkey_bytes
51
+ end
52
+
53
+ # Result wire layout:
54
+ # [33 bytes: prover pubkey]
55
+ # [33 bytes: verifier pubkey]
56
+ # [33 bytes: counterparty pubkey]
57
+ # [VarInt revelation_time_len][revelation_time bytes]
58
+ # [VarInt encrypted_linkage_len][encrypted_linkage bytes]
59
+ # [VarInt encrypted_linkage_proof_len][encrypted_linkage_proof bytes]
60
+ module Result
61
+ module_function
62
+
63
+ def serialize(result)
64
+ w = BSV::Wallet::Wire::Writer.new
65
+ w.write_bytes(pubkey_bytes(result[:prover]))
66
+ w.write_bytes(pubkey_bytes(result[:verifier]))
67
+ w.write_bytes(pubkey_bytes(result[:counterparty]))
68
+ w.write_str_with_varint_len(result[:revelation_time].to_s)
69
+ encrypted_linkage = Common.to_binary(result[:encrypted_linkage])
70
+ w.write_varint(encrypted_linkage.bytesize)
71
+ w.write_bytes(encrypted_linkage)
72
+ encrypted_linkage_proof = Common.to_binary(result[:encrypted_linkage_proof])
73
+ w.write_varint(encrypted_linkage_proof.bytesize)
74
+ w.write_bytes(encrypted_linkage_proof)
75
+ w.buf
76
+ end
77
+
78
+ def deserialize(bytes)
79
+ r = BSV::Wallet::Wire::Reader.new(bytes)
80
+ prover = r.read_bytes(PUBKEY_SIZE)
81
+ verifier = r.read_bytes(PUBKEY_SIZE)
82
+ counterparty = r.read_bytes(PUBKEY_SIZE)
83
+ revelation_time = r.read_str_with_varint_len
84
+ el_len = r.read_varint
85
+ encrypted_linkage = r.read_bytes(el_len)
86
+ elp_len = r.read_varint
87
+ encrypted_linkage_proof = r.read_bytes(elp_len)
88
+ {
89
+ prover: prover,
90
+ verifier: verifier,
91
+ counterparty: counterparty,
92
+ revelation_time: revelation_time,
93
+ encrypted_linkage: encrypted_linkage,
94
+ encrypted_linkage_proof: encrypted_linkage_proof
95
+ }
96
+ end
97
+
98
+ def pubkey_bytes(value)
99
+ return value.b if value.is_a?(String) && value.bytesize == PUBKEY_SIZE
100
+
101
+ [value.to_s].pack('H*')
102
+ end
103
+ private_class_method :pubkey_bytes
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSV
4
+ module Wallet
5
+ module Serializer
6
+ # BRC-103 wire codec for the +reveal_specific_key_linkage+ call (call byte 10).
7
+ #
8
+ # Port of go-sdk/wallet/serializer/reveal_specific_key_linkage.go.
9
+ module RevealSpecificKeyLinkage
10
+ PUBKEY_SIZE = 33
11
+
12
+ # Args wire layout:
13
+ # [key-related params: protocol + key_id + counterparty + privileged]
14
+ # [33 bytes: verifier compressed pubkey]
15
+ module Args
16
+ module_function
17
+
18
+ def serialize(args)
19
+ verifier = args[:verifier]
20
+ raise BSV::Wallet::InvalidParameterError.new('verifier', 'a 33-byte binary pubkey or 66-char hex') unless verifier
21
+
22
+ w = BSV::Wallet::Wire::Writer.new
23
+ Common.write_key_related_params(
24
+ w,
25
+ protocol_id: args[:protocol_id],
26
+ key_id: args[:key_id],
27
+ counterparty: args[:counterparty],
28
+ privileged: args[:privileged],
29
+ privileged_reason: args[:privileged_reason]
30
+ )
31
+ w.write_bytes(pubkey_bytes(verifier))
32
+ w.buf
33
+ end
34
+
35
+ def deserialize(bytes)
36
+ r = BSV::Wallet::Wire::Reader.new(bytes)
37
+ params = Common.read_key_related_params(r)
38
+ verifier = r.read_bytes(PUBKEY_SIZE)
39
+ params.merge(verifier: verifier)
40
+ end
41
+
42
+ def pubkey_bytes(value)
43
+ return value.b if value.is_a?(String) && value.bytesize == PUBKEY_SIZE
44
+
45
+ [value.to_s].pack('H*')
46
+ end
47
+ private_class_method :pubkey_bytes
48
+ end
49
+
50
+ # Result wire layout:
51
+ # [33 bytes: prover pubkey]
52
+ # [33 bytes: verifier pubkey]
53
+ # [33 bytes: counterparty pubkey]
54
+ # [1 byte: security_level][VarInt protocol_name_len][protocol_name bytes]
55
+ # [VarInt key_id_len][key_id bytes]
56
+ # [VarInt encrypted_linkage_len][encrypted_linkage bytes]
57
+ # [VarInt encrypted_linkage_proof_len][encrypted_linkage_proof bytes]
58
+ # [1 byte: proof_type]
59
+ module Result
60
+ module_function
61
+
62
+ def serialize(result)
63
+ w = BSV::Wallet::Wire::Writer.new
64
+ w.write_bytes(pubkey_bytes(result[:prover]))
65
+ w.write_bytes(pubkey_bytes(result[:verifier]))
66
+ w.write_bytes(pubkey_bytes(result[:counterparty]))
67
+ Common.write_protocol(w, result[:protocol_id])
68
+ key_id_bytes = result[:key_id].to_s.b
69
+ w.write_varint(key_id_bytes.bytesize)
70
+ w.write_bytes(key_id_bytes)
71
+ encrypted_linkage = Common.to_binary(result[:encrypted_linkage])
72
+ w.write_varint(encrypted_linkage.bytesize)
73
+ w.write_bytes(encrypted_linkage)
74
+ encrypted_linkage_proof = Common.to_binary(result[:encrypted_linkage_proof])
75
+ w.write_varint(encrypted_linkage_proof.bytesize)
76
+ w.write_bytes(encrypted_linkage_proof)
77
+ w.write_byte(result[:proof_type].to_i)
78
+ w.buf
79
+ end
80
+
81
+ def deserialize(bytes)
82
+ r = BSV::Wallet::Wire::Reader.new(bytes)
83
+ prover = r.read_bytes(PUBKEY_SIZE)
84
+ verifier = r.read_bytes(PUBKEY_SIZE)
85
+ counterparty = r.read_bytes(PUBKEY_SIZE)
86
+ protocol_id = Common.read_protocol(r)
87
+ key_id_len = r.read_varint
88
+ key_id = r.read_bytes(key_id_len).force_encoding('UTF-8')
89
+ el_len = r.read_varint
90
+ encrypted_linkage = r.read_bytes(el_len)
91
+ elp_len = r.read_varint
92
+ encrypted_linkage_proof = r.read_bytes(elp_len)
93
+ proof_type = r.read_byte
94
+ {
95
+ prover: prover,
96
+ verifier: verifier,
97
+ counterparty: counterparty,
98
+ protocol_id: protocol_id,
99
+ key_id: key_id,
100
+ encrypted_linkage: encrypted_linkage,
101
+ encrypted_linkage_proof: encrypted_linkage_proof,
102
+ proof_type: proof_type
103
+ }
104
+ end
105
+
106
+ def pubkey_bytes(value)
107
+ return value.b if value.is_a?(String) && value.bytesize == PUBKEY_SIZE
108
+
109
+ [value.to_s].pack('H*')
110
+ end
111
+ private_class_method :pubkey_bytes
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSV
4
+ module Wallet
5
+ module Serializer
6
+ # BRC-103 serialiser for sign_action args (call byte 2).
7
+ #
8
+ # Wire layout (port of go-sdk/wallet/serializer/sign_action_args.go):
9
+ # [varint] spends count
10
+ # For each spend (sorted by input_index):
11
+ # [varint] input_index
12
+ # [int_bytes] unlocking_script
13
+ # [optional_uint32] sequence_number
14
+ # [int_bytes] reference
15
+ # [1 byte] options present flag (0=absent, 1=present)
16
+ # If options present:
17
+ # [optional_bool] accept_delayed_broadcast
18
+ # [optional_bool] return_txid_only
19
+ # [optional_bool] no_send
20
+ # [txid_slice] send_with
21
+ module SignActionArgs
22
+ module_function
23
+
24
+ # @param args [Hash]
25
+ # @return [String] binary
26
+ def serialize(args)
27
+ w = Wire::Writer.new
28
+
29
+ spends = args[:spends] || {}
30
+ w.write_varint(spends.length)
31
+ spends.keys.sort.each do |idx|
32
+ spend = spends[idx]
33
+ w.write_varint(idx)
34
+ w.write_int_bytes(spend[:unlocking_script])
35
+ w.write_optional_uint32(spend[:sequence_number])
36
+ end
37
+
38
+ w.write_int_bytes(args[:reference])
39
+
40
+ opts = args[:options]
41
+ if opts
42
+ w.write_byte(1)
43
+ w.write_optional_bool(opts[:accept_delayed_broadcast])
44
+ w.write_optional_bool(opts[:return_txid_only])
45
+ w.write_optional_bool(opts[:no_send])
46
+ w.write_txid_slice(opts[:send_with])
47
+ else
48
+ w.write_byte(0)
49
+ end
50
+
51
+ w.buf
52
+ end
53
+
54
+ # @param bytes [String] binary
55
+ # @return [Hash]
56
+ def deserialize(bytes)
57
+ r = Wire::Reader.new(bytes)
58
+
59
+ spend_count = r.read_varint
60
+ spends = {}
61
+ spend_count.times do
62
+ idx = r.read_varint
63
+ script = r.read_int_bytes
64
+ seq = r.read_optional_uint32
65
+ spend = { unlocking_script: script }
66
+ spend[:sequence_number] = seq unless seq.nil?
67
+ spends[idx] = spend
68
+ end
69
+
70
+ reference = r.read_int_bytes
71
+
72
+ options_present = r.read_byte
73
+ options = if options_present == 1
74
+ opts = {}
75
+ v = r.read_optional_bool
76
+ opts[:accept_delayed_broadcast] = v unless v.nil?
77
+ v = r.read_optional_bool
78
+ opts[:return_txid_only] = v unless v.nil?
79
+ v = r.read_optional_bool
80
+ opts[:no_send] = v unless v.nil?
81
+ sw = r.read_txid_slice
82
+ opts[:send_with] = sw unless sw.nil?
83
+ opts
84
+ end
85
+
86
+ result = { spends: spends }
87
+ result[:reference] = reference unless reference.nil? || reference.empty?
88
+ result[:options] = options unless options.nil?
89
+ result
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSV
4
+ module Wallet
5
+ module Serializer
6
+ # BRC-103 serialiser for sign_action result (call byte 2).
7
+ #
8
+ # Wire layout (port of go-sdk/wallet/serializer/sign_action_result.go):
9
+ # [flag + 32 bytes] txid with flag byte: 0=absent, 1=present (wire-order)
10
+ # [flag + int_bytes] tx (BEEF bytes) with flag byte: 0=absent, 1=present + varint_len
11
+ # [send_with_results] varint count + txid (32 bytes) + status_byte each
12
+ module SignActionResult
13
+ module_function
14
+
15
+ # @param result [Hash]
16
+ # @return [String] binary
17
+ def serialize(result)
18
+ w = Wire::Writer.new
19
+
20
+ txid_bytes = result[:txid] ? [result[:txid]].pack('H*').reverse : nil
21
+ w.write_optional_bytes_with_flag(txid_bytes, fixed_size: 32)
22
+ w.write_optional_bytes_with_flag(result[:tx])
23
+
24
+ Common.write_send_with_results(w, result[:send_with_results])
25
+
26
+ w.buf
27
+ end
28
+
29
+ # @param bytes [String] binary
30
+ # @return [Hash]
31
+ def deserialize(bytes)
32
+ r = Wire::Reader.new(bytes)
33
+
34
+ txid_raw = r.read_optional_bytes_with_flag(fixed_size: 32)
35
+ txid_hex = txid_raw&.reverse&.unpack1('H*')
36
+ tx = r.read_optional_bytes_with_flag
37
+
38
+ send_with_results = Common.read_send_with_results(r)
39
+
40
+ result = {}
41
+ result[:txid] = txid_hex unless txid_hex.nil?
42
+ result[:tx] = tx unless tx.nil?
43
+ result[:send_with_results] = send_with_results unless send_with_results.nil?
44
+ result
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSV
4
+ module Wallet
5
+ module Serializer
6
+ # BRC-103 serialisers for is_authenticated (call byte 23) and
7
+ # wait_for_authentication (call byte 24).
8
+ #
9
+ # Both calls take no args payload (originator is in the frame header).
10
+ #
11
+ # Result wire format:
12
+ # is_authenticated: [1 byte] 0x01 = true, 0x00 = false
13
+ # wait_for_authentication: empty payload → always returns authenticated: true
14
+ #
15
+ # Port of go-sdk/wallet/serializer/authenticated.go.
16
+ module IsAuthenticated
17
+ module Args
18
+ module_function
19
+
20
+ def serialize(_args = {})
21
+ ''.b
22
+ end
23
+
24
+ def deserialize(_bytes)
25
+ {}
26
+ end
27
+ end
28
+
29
+ module Result
30
+ module_function
31
+
32
+ # @param result [Hash] { authenticated: Boolean }
33
+ # @return [String] 1-byte binary
34
+ def serialize(result)
35
+ [result[:authenticated] ? 1 : 0].pack('C')
36
+ end
37
+
38
+ # @param bytes [String] binary — must be exactly 1 byte
39
+ # @return [Hash] { authenticated: Boolean }
40
+ def deserialize(bytes)
41
+ data = bytes.b
42
+ unless data.bytesize == 1
43
+ raise BSV::Wallet::InvalidParameterError.new(
44
+ 'is_authenticated result',
45
+ 'exactly 1 byte'
46
+ )
47
+ end
48
+
49
+ { authenticated: data.getbyte(0) == 1 }
50
+ end
51
+ end
52
+ end
53
+
54
+ module WaitForAuthentication
55
+ module Args
56
+ module_function
57
+
58
+ def serialize(_args = {})
59
+ ''.b
60
+ end
61
+
62
+ def deserialize(_bytes)
63
+ {}
64
+ end
65
+ end
66
+
67
+ module Result
68
+ module_function
69
+
70
+ # @param _result [Hash] ignored — always serialises as empty payload
71
+ # @return [String] empty binary
72
+ def serialize(_result = {})
73
+ ''.b
74
+ end
75
+
76
+ # @param _bytes [String] ignored — always returns authenticated: true
77
+ # @return [Hash] { authenticated: true }
78
+ def deserialize(_bytes = nil)
79
+ { authenticated: true }
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end