Module: BSV::Wallet::Validators
- Defined in:
- lib/bsv/wallet_interface/validators.rb
Constant Summary collapse
- RESERVED_PROTOCOL_PREFIXES =
Reserved protocol name prefixes (BRC-44 and BRC-98). Names beginning with any of these strings are disallowed.
['admin', 'p '].freeze
- RESERVED_PROTOCOL_SUFFIX =
Suffix that is disallowed on protocol names.
' protocol'- RESERVED_BASKET_PREFIXES =
Reserved basket name prefixes. Basket names beginning with any of these strings are disallowed.
['admin', 'p '].freeze
- RESERVED_BASKET_SUFFIX =
Suffix that is disallowed on basket names.
' basket'- RESERVED_BASKET_NAME =
Basket name that is globally reserved and cannot be used.
'default'
Class Method Summary collapse
-
.validate_basket!(basket) ⇒ Object
Basket name rules (BRC-99): - 5-300 chars - lowercase letters, numbers, and spaces only - no consecutive spaces - must not end with ‘ basket’ - must not start with ‘admin’ - must not be ‘default’ - must not start with ‘p ’ (BRC-99 reserved).
-
.validate_counterparty!(counterparty) ⇒ Object
Counterparty: ‘self’, ‘anyone’, or 66-char hex (compressed pubkey).
-
.validate_description!(description, name = 'description') ⇒ Object
Description: 5-50 characters.
-
.validate_hex_string!(value, name = 'hex_string') ⇒ Object
Hex string: even-length hex characters only.
-
.validate_integer!(value, name, min: nil, max: nil) ⇒ Object
Integer within bounds.
-
.validate_key_id!(key_id) ⇒ Object
Key ID: 1-800 bytes.
-
.validate_label!(label) ⇒ Object
Label: 1-300 characters.
-
.validate_outpoint!(outpoint) ⇒ Object
Outpoint: “<64-hex-txid>.<non-negative-integer>”.
-
.validate_protocol_id!(protocol_id) ⇒ Object
BRC-100 protocol ID rules: - Array of [security_level, protocol_name] - security_level: Integer 0, 1, or 2 - protocol_name: 5-400 chars (up to 430 for ‘specific linkage revelation’ protocol) - lowercase letters, numbers, and spaces only - no consecutive spaces - must not end with ‘ protocol’ - must not start with ‘admin’ (BRC-44) - must not start with ‘p ’ (BRC-98 reserved).
-
.validate_pub_key_hex!(value, name = 'public_key') ⇒ Object
Compressed public key hex: exactly 66 hex characters.
-
.validate_satoshis!(value, name = 'satoshis') ⇒ Object
Satoshis: 1 to 2_100_000_000_000_000.
-
.validate_tag!(tag) ⇒ Object
Tag: 1-300 characters.
Class Method Details
.validate_basket!(basket) ⇒ Object
Basket name rules (BRC-99):
-
5-300 chars
-
lowercase letters, numbers, and spaces only
-
no consecutive spaces
-
must not end with ‘ basket’
-
must not start with ‘admin’
-
must not be ‘default’
-
must not start with ‘p ’ (BRC-99 reserved)
92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/bsv/wallet_interface/validators.rb', line 92 def validate_basket!(basket) raise InvalidParameterError.new('basket', 'a String') unless basket.is_a?(String) raise InvalidParameterError.new('basket', 'between 5 and 300 characters') if basket.length < 5 || basket.length > 300 raise InvalidParameterError.new('basket', 'lowercase letters, numbers, and spaces only') unless basket.match?(/\A[a-z0-9 ]+\z/) raise InvalidParameterError.new('basket', 'free of consecutive spaces') if basket.include?(' ') raise InvalidParameterError.new('basket', "not ending with \"#{RESERVED_BASKET_SUFFIX}\"") if basket.end_with?(RESERVED_BASKET_SUFFIX) RESERVED_BASKET_PREFIXES.each do |prefix| raise InvalidParameterError.new('basket', "not starting with \"#{prefix}\"") if basket.start_with?(prefix) end raise InvalidParameterError.new('basket', "not equal to \"#{RESERVED_BASKET_NAME}\"") if basket == RESERVED_BASKET_NAME end |
.validate_counterparty!(counterparty) ⇒ Object
Counterparty: ‘self’, ‘anyone’, or 66-char hex (compressed pubkey)
72 73 74 75 76 |
# File 'lib/bsv/wallet_interface/validators.rb', line 72 def validate_counterparty!(counterparty) return if %w[self anyone].include?(counterparty) validate_pub_key_hex!(counterparty, 'counterparty') end |
.validate_description!(description, name = 'description') ⇒ Object
Description: 5-50 characters
79 80 81 82 |
# File 'lib/bsv/wallet_interface/validators.rb', line 79 def validate_description!(description, name = 'description') raise InvalidParameterError.new(name, 'a String') unless description.is_a?(String) raise InvalidParameterError.new(name, 'between 5 and 50 characters') if description.length < 5 || description.length > 50 end |
.validate_hex_string!(value, name = 'hex_string') ⇒ Object
Hex string: even-length hex characters only
142 143 144 145 |
# File 'lib/bsv/wallet_interface/validators.rb', line 142 def validate_hex_string!(value, name = 'hex_string') raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String) raise InvalidParameterError.new(name, 'a valid hex string') unless value.match?(/\A[0-9a-f]*\z/) && value.length.even? end |
.validate_integer!(value, name, min: nil, max: nil) ⇒ Object
Integer within bounds
148 149 150 151 152 |
# File 'lib/bsv/wallet_interface/validators.rb', line 148 def validate_integer!(value, name, min: nil, max: nil) raise InvalidParameterError.new(name, 'an Integer') unless value.is_a?(Integer) raise InvalidParameterError.new(name, "at least #{min}") if min && value < min raise InvalidParameterError.new(name, "at most #{max}") if max && value > max end |
.validate_key_id!(key_id) ⇒ Object
Key ID: 1-800 bytes
64 65 66 67 68 69 |
# File 'lib/bsv/wallet_interface/validators.rb', line 64 def validate_key_id!(key_id) raise InvalidParameterError.new('key_id', 'a String') unless key_id.is_a?(String) byte_length = key_id.bytesize raise InvalidParameterError.new('key_id', 'between 1 and 800 bytes') if byte_length < 1 || byte_length > 800 end |
.validate_label!(label) ⇒ Object
Label: 1-300 characters
106 107 108 109 |
# File 'lib/bsv/wallet_interface/validators.rb', line 106 def validate_label!(label) raise InvalidParameterError.new('label', 'a String') unless label.is_a?(String) raise InvalidParameterError.new('label', 'between 1 and 300 characters') if label.empty? || label.length > 300 end |
.validate_outpoint!(outpoint) ⇒ Object
Outpoint: “<64-hex-txid>.<non-negative-integer>”
118 119 120 121 122 123 124 125 126 127 |
# File 'lib/bsv/wallet_interface/validators.rb', line 118 def validate_outpoint!(outpoint) raise InvalidParameterError.new('outpoint', 'a String') unless outpoint.is_a?(String) parts = outpoint.split('.') raise InvalidParameterError.new('outpoint', 'in format "<txid>.<index>"') unless parts.length == 2 txid, index = parts raise InvalidParameterError.new('outpoint txid', 'a 64-character hex string') unless txid.match?(/\A[0-9a-f]{64}\z/) raise InvalidParameterError.new('outpoint index', 'a non-negative integer') unless index.match?(/\A\d+\z/) end |
.validate_protocol_id!(protocol_id) ⇒ Object
BRC-100 protocol ID rules:
-
Array of [security_level, protocol_name]
-
security_level: Integer 0, 1, or 2
-
protocol_name: 5-400 chars (up to 430 for ‘specific linkage revelation’ protocol)
-
lowercase letters, numbers, and spaces only
-
no consecutive spaces
-
must not end with ‘ protocol’
-
must not start with ‘admin’ (BRC-44)
-
must not start with ‘p ’ (BRC-98 reserved)
The name is normalised (stripped and downcased) before validation so that ‘ MyProtocol ’ and ‘myprotocol’ are treated identically and do not silently fork to different key-derivation paths (F8.7).
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/bsv/wallet_interface/validators.rb', line 38 def validate_protocol_id!(protocol_id) unless protocol_id.is_a?(Array) && protocol_id.length == 2 raise InvalidParameterError.new('protocol_id', 'an Array of [security_level, protocol_name]') end level, name = protocol_id raise InvalidParameterError.new('protocol_id security level', '0, 1, or 2') unless [0, 1, 2].include?(level) raise InvalidParameterError.new('protocol_id name', 'a String') unless name.is_a?(String) name = name.strip.downcase max_length = name.start_with?('specific linkage revelation') ? 430 : 400 raise InvalidParameterError.new('protocol_id name', "between 5 and #{max_length} characters") if name.length < 5 || name.length > max_length raise InvalidParameterError.new('protocol_id name', 'lowercase letters, numbers, and spaces only') unless name.match?(/\A[a-z0-9 ]+\z/) raise InvalidParameterError.new('protocol_id name', 'free of consecutive spaces') if name.include?(' ') if name.end_with?(RESERVED_PROTOCOL_SUFFIX) raise InvalidParameterError.new('protocol_id name', "not ending with \"#{RESERVED_PROTOCOL_SUFFIX}\"") end RESERVED_PROTOCOL_PREFIXES.each do |prefix| raise InvalidParameterError.new('protocol_id name', "not starting with \"#{prefix}\"") if name.start_with?(prefix) end end |
.validate_pub_key_hex!(value, name = 'public_key') ⇒ Object
Compressed public key hex: exactly 66 hex characters
136 137 138 139 |
# File 'lib/bsv/wallet_interface/validators.rb', line 136 def validate_pub_key_hex!(value, name = 'public_key') raise InvalidParameterError.new(name, 'a String') unless value.is_a?(String) raise InvalidParameterError.new(name, 'a 66-character hex string (compressed public key)') unless value.match?(/\A[0-9a-f]{66}\z/) end |
.validate_satoshis!(value, name = 'satoshis') ⇒ Object
Satoshis: 1 to 2_100_000_000_000_000
130 131 132 133 |
# File 'lib/bsv/wallet_interface/validators.rb', line 130 def validate_satoshis!(value, name = 'satoshis') raise InvalidParameterError.new(name, 'an Integer') unless value.is_a?(Integer) raise InvalidParameterError.new(name, 'between 1 and 2100000000000000') if value < 1 || value > 2_100_000_000_000_000 end |
.validate_tag!(tag) ⇒ Object
Tag: 1-300 characters
112 113 114 115 |
# File 'lib/bsv/wallet_interface/validators.rb', line 112 def validate_tag!(tag) raise InvalidParameterError.new('tag', 'a String') unless tag.is_a?(String) raise InvalidParameterError.new('tag', 'between 1 and 300 characters') if tag.empty? || tag.length > 300 end |