Module: BSV::Wallet::Wire::Validation

Defined in:
lib/bsv/wallet/wire/validation.rb

Overview

Branded-type validators for BRC-100 parameters.

Each method raises InvalidParameterError on failure and returns nil on success. Port of ts-sdk/src/wallet/validationHelpers.ts.

The existing ProtoWallet::Validators module delegates here so there is a single source of truth for all parameter validation logic.

Constant Summary collapse

MAX_SATOSHIS =
21_000_000 * (10**8)

Class Method Summary collapse

Class Method Details

.acquisition_protocol!(name, value) ⇒ Object

Validates a certificate acquisition protocol: ‘direct’ or ‘issuance’.

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



205
206
207
208
209
# File 'lib/bsv/wallet/wire/validation.rb', line 205

def acquisition_protocol!(name, value)
  return if %w[direct issuance].include?(value)

  raise InvalidParameterError.new(name, "'direct' or 'issuance'")
end

.base64_string!(name, value) ⇒ Object

Validates that value is a Base64-encoded string.

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



39
40
41
42
43
44
45
# File 'lib/bsv/wallet/wire/validation.rb', line 39

def base64_string!(name, value)
  raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String)

  return if value.match?(%r{\A[A-Za-z0-9+/]*={0,2}\z})

  raise InvalidParameterError.new(name, 'a valid Base64 string')
end

.basket_string!(name, value) ⇒ Object

Validates a basket name (1..300 characters).

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



107
108
109
110
111
112
# File 'lib/bsv/wallet/wire/validation.rb', line 107

def basket_string!(name, value)
  raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String)

  len = value.length
  raise InvalidParameterError.new(name, 'between 1 and 300 characters') if len < 1 || len > 300
end

.description_5_to_50!(name, value) ⇒ Object

Validates a description string (5..50 printable characters).

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



85
86
87
88
89
90
# File 'lib/bsv/wallet/wire/validation.rb', line 85

def description_5_to_50!(name, value)
  raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String)

  len = value.length
  raise InvalidParameterError.new(name, 'between 5 and 50 characters') if len < 5 || len > 50
end

.hex_string!(name, value, length: nil) ⇒ Object

Validates that value is a hex string (even length, hex chars only).

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

  • length (Integer, nil) (defaults to: nil)

    expected number of hex chars (nil = any)

Raises:



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/bsv/wallet/wire/validation.rb', line 23

def hex_string!(name, value, length: nil)
  raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String)

  raise InvalidParameterError.new(name, 'a hex string (characters 0-9, a-f, A-F only)') unless value.match?(/\A[0-9a-fA-F]*\z/)

  raise InvalidParameterError.new(name, 'a hex string with even number of characters') if value.length.odd?

  return unless length && value.length != length

  raise InvalidParameterError.new(name, "a #{length}-character hex string, got #{value.length}")
end

.key_id_string_1_to_800!(name, value) ⇒ Object

Validates a BRC-43 key ID string (1..800 bytes).

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



171
172
173
174
175
176
# File 'lib/bsv/wallet/wire/validation.rb', line 171

def key_id_string_1_to_800!(name, value)
  raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String)

  byte_length = value.bytesize
  raise InvalidParameterError.new(name, 'between 1 and 800 bytes') if byte_length < 1 || byte_length > 800
end

.label_string!(name, value) ⇒ Object

Validates a label string (1..150 characters, no spaces).

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



96
97
98
99
100
101
# File 'lib/bsv/wallet/wire/validation.rb', line 96

def label_string!(name, value)
  raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String)

  len = value.length
  raise InvalidParameterError.new(name, 'between 1 and 150 characters') if len < 1 || len > 150
end

.originator_domain!(name, value) ⇒ Object

Validates an originator domain (1..250 bytes UTF-8). The originator must fit in a single-byte length field in the wire frame.

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



119
120
121
122
123
124
# File 'lib/bsv/wallet/wire/validation.rb', line 119

def originator_domain!(name, value)
  raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String)

  byte_len = value.bytesize
  raise InvalidParameterError.new(name, 'at most 250 bytes') if byte_len > 250
end

.outpoint_string!(name, value) ⇒ Object

Validates an outpoint string in the form “<64-hex-txid>.<vout>”.

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/bsv/wallet/wire/validation.rb', line 51

def outpoint_string!(name, value)
  raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String)

  parts = value.split('.', 2)
  raise InvalidParameterError.new(name, 'an outpoint string in the format <64-hex-txid>.<vout>') unless parts.length == 2

  txid_hex, vout_str = parts

  raise InvalidParameterError.new(name, 'an outpoint with a 64-character hex transaction ID') unless txid_hex.match?(/\A[0-9a-fA-F]{64}\z/)

  raise InvalidParameterError.new(name, 'an outpoint with a non-negative integer output index') unless vout_str.match?(/\A\d+\z/)

  vout = vout_str.to_i
  return unless vout > 0xFFFFFFFF

  raise InvalidParameterError.new(name, 'an outpoint with a vout that fits in a uint32 (0..4294967295)')
end

.positive_integer_or_zero!(name, value) ⇒ Object

Validates a non-negative integer.

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



142
143
144
145
146
# File 'lib/bsv/wallet/wire/validation.rb', line 142

def positive_integer_or_zero!(name, value)
  return if value.is_a?(Integer) && !value.negative?

  raise InvalidParameterError.new(name, 'a non-negative integer')
end

.protocol_string_5_to_400!(name, value) ⇒ Object

Validates a BRC-43 protocol name string (5..400 chars, lowercase).

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/bsv/wallet/wire/validation.rb', line 152

def protocol_string_5_to_400!(name, value)
  raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String)

  normalized = value.strip.downcase
  max_length = normalized.start_with?('specific linkage revelation') ? 430 : 400

  raise InvalidParameterError.new(name, "between 5 and #{max_length} characters") if normalized.length < 5 || normalized.length > max_length

  raise InvalidParameterError.new(name, 'lowercase letters, numbers, and spaces only') unless normalized.match?(/\A[a-z0-9 ]+\z/)

  return unless normalized.include?('  ')

  raise InvalidParameterError.new(name, 'free of consecutive spaces')
end

.pub_key_hex!(name, value) ⇒ Object

Validates a compressed public key in hex form (66 chars, 02/03 prefix).

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



73
74
75
76
77
78
79
# File 'lib/bsv/wallet/wire/validation.rb', line 73

def pub_key_hex!(name, value)
  raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String)

  return if value.match?(/\A0[23][0-9a-fA-F]{64}\z/)

  raise InvalidParameterError.new(name, 'a 66-character compressed public key hex string (02 or 03 prefix)')
end

.satoshi_value!(name, value) ⇒ Object

Validates a satoshi amount (0..21_000_000 * 10^8).

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



130
131
132
133
134
135
136
# File 'lib/bsv/wallet/wire/validation.rb', line 130

def satoshi_value!(name, value)
  raise InvalidParameterError.new(name, 'a non-negative integer') unless value.is_a?(Integer)

  return unless value.negative? || value > MAX_SATOSHIS

  raise InvalidParameterError.new(name, "between 0 and #{MAX_SATOSHIS} satoshis")
end

.wallet_counterparty!(name, value) ⇒ Object

Validates a wallet counterparty: ‘self’, ‘anyone’, or a 66-char hex pubkey.

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate



182
183
184
185
186
# File 'lib/bsv/wallet/wire/validation.rb', line 182

def wallet_counterparty!(name, value)
  return if %w[self anyone].include?(value)

  pub_key_hex!(name, value)
end

.wallet_protocol!(name, value) ⇒ Object

Validates a BRC-43 protocol ID: [security_level (0-2), protocol_name (5-400 chars)].

Parameters:

  • name (String)

    parameter name for error messages

  • value (Object)

    the value to validate

Raises:



192
193
194
195
196
197
198
199
# File 'lib/bsv/wallet/wire/validation.rb', line 192

def wallet_protocol!(name, value)
  raise InvalidParameterError.new(name, 'an Array of [security_level, protocol_name]') unless value.is_a?(Array) && value.length == 2

  level, proto_name = value
  raise InvalidParameterError.new(name, 'a security level of 0, 1, or 2') unless [0, 1, 2].include?(level)

  protocol_string_5_to_400!("#{name} protocol name", proto_name)
end