bsv-sdk 0.20.0 → 0.23.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +106 -0
  3. data/lib/bsv/mcp/tools/broadcast_p2pkh.rb +5 -3
  4. data/lib/bsv/network/protocols/arc.rb +4 -30
  5. data/lib/bsv/network/protocols/arcade.rb +163 -0
  6. data/lib/bsv/network/protocols/chaintracks.rb +27 -4
  7. data/lib/bsv/network/protocols/jungle_bus.rb +34 -0
  8. data/lib/bsv/network/protocols/woc_rest.rb +28 -1
  9. data/lib/bsv/network/protocols.rb +1 -0
  10. data/lib/bsv/network/providers/gorilla_pool.rb +18 -18
  11. data/lib/bsv/network/util.rb +44 -0
  12. data/lib/bsv/network.rb +1 -0
  13. data/lib/bsv/transaction/chain_tracker.rb +66 -13
  14. data/lib/bsv/transaction/chain_trackers.rb +0 -10
  15. data/lib/bsv/transaction/fee_models/live_policy.rb +10 -8
  16. data/lib/bsv/version.rb +1 -1
  17. data/lib/bsv/wallet/errors.rb +65 -21
  18. data/lib/bsv/wallet/proto_wallet/validators.rb +7 -49
  19. data/lib/bsv/wallet/proto_wallet.rb +14 -1
  20. data/lib/bsv/wallet/serializer/abort_action.rb +38 -0
  21. data/lib/bsv/wallet/serializer/acquire_certificate.rb +171 -0
  22. data/lib/bsv/wallet/serializer/certificate.rb +184 -0
  23. data/lib/bsv/wallet/serializer/common.rb +207 -0
  24. data/lib/bsv/wallet/serializer/create_action_args.rb +259 -0
  25. data/lib/bsv/wallet/serializer/create_action_result.rb +85 -0
  26. data/lib/bsv/wallet/serializer/create_hmac.rb +67 -0
  27. data/lib/bsv/wallet/serializer/create_signature.rb +90 -0
  28. data/lib/bsv/wallet/serializer/decrypt.rb +60 -0
  29. data/lib/bsv/wallet/serializer/discover_by_attributes.rb +61 -0
  30. data/lib/bsv/wallet/serializer/discover_by_identity_key.rb +49 -0
  31. data/lib/bsv/wallet/serializer/discover_certificates_result.rb +39 -0
  32. data/lib/bsv/wallet/serializer/encrypt.rb +60 -0
  33. data/lib/bsv/wallet/serializer/get_header_for_height.rb +71 -0
  34. data/lib/bsv/wallet/serializer/get_height.rb +46 -0
  35. data/lib/bsv/wallet/serializer/get_network.rb +65 -0
  36. data/lib/bsv/wallet/serializer/get_public_key.rb +86 -0
  37. data/lib/bsv/wallet/serializer/get_version.rb +44 -0
  38. data/lib/bsv/wallet/serializer/internalize_action.rb +151 -0
  39. data/lib/bsv/wallet/serializer/list_actions.rb +348 -0
  40. data/lib/bsv/wallet/serializer/list_certificates.rb +124 -0
  41. data/lib/bsv/wallet/serializer/list_outputs.rb +167 -0
  42. data/lib/bsv/wallet/serializer/prove_certificate.rb +146 -0
  43. data/lib/bsv/wallet/serializer/relinquish_certificate.rb +56 -0
  44. data/lib/bsv/wallet/serializer/relinquish_output.rb +44 -0
  45. data/lib/bsv/wallet/serializer/reveal_counterparty_key_linkage.rb +108 -0
  46. data/lib/bsv/wallet/serializer/reveal_specific_key_linkage.rb +116 -0
  47. data/lib/bsv/wallet/serializer/sign_action_args.rb +94 -0
  48. data/lib/bsv/wallet/serializer/sign_action_result.rb +49 -0
  49. data/lib/bsv/wallet/serializer/status.rb +85 -0
  50. data/lib/bsv/wallet/serializer/verify_hmac.rb +67 -0
  51. data/lib/bsv/wallet/serializer/verify_signature.rb +101 -0
  52. data/lib/bsv/wallet/serializer.rb +180 -0
  53. data/lib/bsv/wallet/substrates/http_wallet_json.rb +129 -0
  54. data/lib/bsv/wallet/substrates/http_wallet_wire.rb +99 -0
  55. data/lib/bsv/wallet/wallet_wire.rb +20 -0
  56. data/lib/bsv/wallet/wallet_wire_processor.rb +61 -0
  57. data/lib/bsv/wallet/wallet_wire_transceiver.rb +61 -0
  58. data/lib/bsv/wallet/wire/calls.rb +79 -0
  59. data/lib/bsv/wallet/wire/frame.rb +181 -0
  60. data/lib/bsv/wallet/wire/reader_writer.rb +402 -0
  61. data/lib/bsv/wallet/wire/validation.rb +213 -0
  62. data/lib/bsv/wallet/wire.rb +13 -0
  63. data/lib/bsv/wallet.rb +17 -0
  64. metadata +46 -2
  65. data/lib/bsv/transaction/chain_trackers/chaintracks.rb +0 -83
@@ -0,0 +1,124 @@
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 +list_certificates+ call (call byte 18).
9
+ #
10
+ # Args wire layout:
11
+ # [varint: certifier_count] per certifier: [33-byte pubkey]
12
+ # [varint: type_count] per type: [32-byte raw type]
13
+ # [optional_uint32: limit]
14
+ # [optional_uint32: offset]
15
+ # [privileged params]
16
+ #
17
+ # Result wire layout:
18
+ # [varint: total_certificates]
19
+ # per certificate:
20
+ # [varint-int: serialised Certificate bytes]
21
+ # [1 byte: keyring present flag (0/1)]
22
+ # If keyring present:
23
+ # [varint: keyring_count] per entry: [varint-str key][varint-int base64 bytes]
24
+ # [varint-int: verifier bytes]
25
+ module ListCertificates
26
+ CERT_TYPE_SIZE = 32
27
+ PUBKEY_SIZE = 33
28
+
29
+ module_function
30
+
31
+ def serialize_args(args)
32
+ w = Wire::Writer.new
33
+
34
+ certifiers = args[:certifiers] || []
35
+ w.write_varint(certifiers.length)
36
+ certifiers.each { |c| w.write_bytes([c.to_s].pack('H*')) }
37
+
38
+ types = args[:types] || []
39
+ w.write_varint(types.length)
40
+ types.each do |t|
41
+ type_bytes = Base64.strict_decode64(t.to_s)
42
+ w.write_bytes(type_bytes.ljust(CERT_TYPE_SIZE, "\x00").byteslice(0, CERT_TYPE_SIZE))
43
+ end
44
+
45
+ w.write_optional_uint32(args[:limit])
46
+ w.write_optional_uint32(args[:offset])
47
+ Common.write_privileged_params(w, args[:privileged], args[:privileged_reason])
48
+ w.buf
49
+ end
50
+
51
+ def deserialize_args(bytes)
52
+ r = Wire::Reader.new(bytes)
53
+
54
+ certifier_count = r.read_varint
55
+ certifiers = certifier_count.times.map { r.read_bytes(PUBKEY_SIZE).unpack1('H*') }
56
+
57
+ type_count = r.read_varint
58
+ types = type_count.times.map { Base64.strict_encode64(r.read_bytes(CERT_TYPE_SIZE)) }
59
+
60
+ limit = r.read_optional_uint32
61
+ offset = r.read_optional_uint32
62
+ privileged, privileged_reason = Common.read_privileged_params(r)
63
+
64
+ { certifiers: certifiers, types: types, limit: limit, offset: offset,
65
+ privileged: privileged, privileged_reason: privileged_reason }
66
+ end
67
+
68
+ def serialize_result(result)
69
+ w = Wire::Writer.new
70
+ certs = result[:certificates] || []
71
+ w.write_varint(certs.length)
72
+
73
+ certs.each do |cert_result|
74
+ cert = cert_result[:certificate] || cert_result
75
+ cert_bytes = Certificate.serialize_certificate(cert, include_signature: true)
76
+ w.write_int_bytes(cert_bytes)
77
+
78
+ keyring = cert_result[:keyring]
79
+ if keyring
80
+ w.write_byte(1)
81
+ w.write_varint(keyring.length)
82
+ keyring.keys.sort.each do |k|
83
+ w.write_str_with_varint_len(k)
84
+ w.write_int_from_base64(keyring[k].to_s)
85
+ end
86
+ else
87
+ w.write_byte(0)
88
+ end
89
+
90
+ verifier = cert_result[:verifier]
91
+ w.write_int_bytes(verifier ? verifier.b : ''.b)
92
+ end
93
+
94
+ w.buf
95
+ end
96
+
97
+ def deserialize_result(bytes)
98
+ r = Wire::Reader.new(bytes)
99
+ total = r.read_varint
100
+
101
+ certificates = total.times.map do
102
+ cert_bytes = r.read_int_bytes
103
+ cert = Certificate.deserialize_certificate(cert_bytes)
104
+
105
+ keyring = nil
106
+ if r.read_byte == 1
107
+ keyring_len = r.read_varint
108
+ keyring = {}
109
+ keyring_len.times do
110
+ k = r.read_str_with_varint_len
111
+ keyring[k] = r.read_base64_int
112
+ end
113
+ end
114
+
115
+ verifier = r.read_int_bytes
116
+ { certificate: cert, keyring: keyring, verifier: verifier.empty? ? nil : verifier }
117
+ end
118
+
119
+ { total_certificates: total, certificates: certificates }
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSV
4
+ module Wallet
5
+ module Serializer
6
+ # BRC-103 wire codec for the +list_outputs+ call (call byte 6).
7
+ #
8
+ # Args wire layout:
9
+ # [varint-str: basket]
10
+ # [string-slice: tags] nil → NegativeOne
11
+ # [1 byte: tag_query_mode] 1=all, 2=any, 0xFF=nil
12
+ # [1 byte: include] 1=locking_scripts, 2=entire_transactions, 0xFF=nil
13
+ # [optional_bool: include_custom_instructions]
14
+ # [optional_bool: include_tags]
15
+ # [optional_bool: include_labels]
16
+ # [optional_uint32: limit]
17
+ # [optional_uint32: offset]
18
+ # [optional_bool: seek_permission]
19
+ #
20
+ # Result wire layout:
21
+ # [varint: total_outputs]
22
+ # [varint: beef_len, or NegativeOne if nil][beef bytes]
23
+ # per output:
24
+ # [32-byte wire txid][varint vout]
25
+ # [varint: satoshis]
26
+ # [varint: locking_script_len, or NegativeOne][script bytes]
27
+ # [varint-str: custom_instructions] 0-length string if nil
28
+ # [string-slice: tags]
29
+ # [string-slice: labels]
30
+ module ListOutputs
31
+ TAG_QUERY_MODE_ALL = 1
32
+ TAG_QUERY_MODE_ANY = 2
33
+ INCLUDE_LOCKING_SCRIPTS = 1
34
+ INCLUDE_ENTIRE_TRANSACTIONS = 2
35
+ NEGATIVE_ONE_BYTE = 0xFF
36
+
37
+ module_function
38
+
39
+ def serialize_args(args)
40
+ w = Wire::Writer.new
41
+ w.write_str_with_varint_len(args.fetch(:basket, ''))
42
+ w.write_string_slice(args[:tags])
43
+
44
+ mode_byte = case args[:tag_query_mode]
45
+ when :all then TAG_QUERY_MODE_ALL
46
+ when :any then TAG_QUERY_MODE_ANY
47
+ else NEGATIVE_ONE_BYTE
48
+ end
49
+ w.write_byte(mode_byte)
50
+
51
+ include_byte = case args[:include]
52
+ when :locking_scripts then INCLUDE_LOCKING_SCRIPTS
53
+ when :entire_transactions then INCLUDE_ENTIRE_TRANSACTIONS
54
+ else NEGATIVE_ONE_BYTE
55
+ end
56
+ w.write_byte(include_byte)
57
+
58
+ w.write_optional_bool(args[:include_custom_instructions])
59
+ w.write_optional_bool(args[:include_tags])
60
+ w.write_optional_bool(args[:include_labels])
61
+ w.write_optional_uint32(args[:limit])
62
+ w.write_optional_uint32(args[:offset])
63
+ w.write_optional_bool(args[:seek_permission])
64
+ w.buf
65
+ end
66
+
67
+ def deserialize_args(bytes)
68
+ r = Wire::Reader.new(bytes)
69
+ basket = r.read_str_with_varint_len
70
+ tags = r.read_string_slice
71
+
72
+ mode = case r.read_byte
73
+ when TAG_QUERY_MODE_ALL then :all
74
+ when TAG_QUERY_MODE_ANY then :any
75
+ end
76
+
77
+ inc = case r.read_byte
78
+ when INCLUDE_LOCKING_SCRIPTS then :locking_scripts
79
+ when INCLUDE_ENTIRE_TRANSACTIONS then :entire_transactions
80
+ end
81
+
82
+ {
83
+ basket: basket,
84
+ tags: tags,
85
+ tag_query_mode: mode,
86
+ include: inc,
87
+ include_custom_instructions: r.read_optional_bool,
88
+ include_tags: r.read_optional_bool,
89
+ include_labels: r.read_optional_bool,
90
+ limit: r.read_optional_uint32,
91
+ offset: r.read_optional_uint32,
92
+ seek_permission: r.read_optional_bool
93
+ }
94
+ end
95
+
96
+ def serialize_result(result)
97
+ w = Wire::Writer.new
98
+ outputs = result[:outputs] || []
99
+ w.write_varint(outputs.length)
100
+
101
+ beef = result[:beef]
102
+ if beef
103
+ w.write_int_bytes(beef.b)
104
+ else
105
+ w.write_negative_one
106
+ end
107
+
108
+ outputs.each do |output|
109
+ outpoint = output[:outpoint] || ''
110
+ txid_hex, vout = outpoint.to_s.split('.', 2)
111
+ w.write_outpoint(txid_hex.to_s, vout.to_i)
112
+ w.write_varint(output[:satoshis].to_i)
113
+ locking_script = output[:locking_script]
114
+ if locking_script && !locking_script.empty?
115
+ w.write_int_bytes(locking_script.b)
116
+ else
117
+ w.write_negative_one
118
+ end
119
+ w.write_optional_string(output[:custom_instructions])
120
+ w.write_string_slice(output[:tags])
121
+ w.write_string_slice(output[:labels])
122
+ end
123
+ w.buf
124
+ end
125
+
126
+ def deserialize_result(bytes)
127
+ r = Wire::Reader.new(bytes)
128
+ total_outputs = r.read_varint
129
+
130
+ beef_len = r.read_varint
131
+ beef = if beef_len == 0xFFFF_FFFF_FFFF_FFFF
132
+ nil
133
+ else
134
+ r.read_bytes(beef_len)
135
+ end
136
+
137
+ outputs = total_outputs.times.map do
138
+ outpoint_data = r.read_outpoint
139
+ outpoint = "#{outpoint_data[:txid_hex]}.#{outpoint_data[:vout]}"
140
+ satoshis = r.read_varint
141
+ locking_script_len = r.read_varint
142
+ locking_script = if locking_script_len == 0xFFFF_FFFF_FFFF_FFFF
143
+ nil
144
+ else
145
+ r.read_bytes(locking_script_len)
146
+ end
147
+ custom_instructions = r.read_optional_string
148
+ tags = r.read_string_slice
149
+ labels = r.read_string_slice
150
+
151
+ {
152
+ outpoint: outpoint,
153
+ satoshis: satoshis,
154
+ locking_script: locking_script,
155
+ custom_instructions: custom_instructions,
156
+ tags: tags,
157
+ labels: labels,
158
+ spendable: true
159
+ }
160
+ end
161
+
162
+ { total_outputs: total_outputs, beef: beef, outputs: outputs }
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -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