Module: OpenReceive::Server::WalletInfo

Defined in:
lib/openreceive/server/wallet_info.rb

Overview

NIP-47 wallet service info normalization (the kind 13194 info payload), ported from the JS summarizeWalletCapabilities and locked to the shared spec/test-vectors/nwc-info.json vectors: method-name normalization, encryption-mode choice, spend-capability detection, and receive readiness must be identical in both engines.

Constant Summary collapse

REQUIRED_RECEIVE_METHODS =
%w[make_invoice list_transactions].freeze
SPEND_METHODS =
%w[pay_invoice multi_pay_invoice pay_keysend multi_pay_keysend].freeze

Class Method Summary collapse

Class Method Details

.choose_encryption_mode(encryption_modes) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
# File 'lib/openreceive/server/wallet_info.rb', line 42

def choose_encryption_mode(encryption_modes)
  normalized = encryption_modes.map { |mode| mode.downcase.gsub(/[- ]/, "_") }
  if (normalized & %w[nip44_v2 nip44 nip_44]).any?
    "nip44_v2"
  elsif normalized.empty? || normalized.include?("nip04") || normalized.include?("nip_04")
    # No advertised list at all: assume the NIP-47 baseline (NIP-04).
    "nip04"
  end
  # An advertised list containing no mode we speak returns nil so
  # preflight can fail loudly instead of failing cryptically at RPC time.
end

.normalize_method_name(value) ⇒ Object



64
65
66
# File 'lib/openreceive/server/wallet_info.rb', line 64

def normalize_method_name(value)
  value.strip.gsub(/([a-z0-9])([A-Z])/, '\1_\2').gsub(/[-\s]+/, "_").downcase
end

.string_list(value) ⇒ Object



54
55
56
57
58
59
60
61
62
# File 'lib/openreceive/server/wallet_info.rb', line 54

def string_list(value)
  if value.is_a?(Array)
    value.select { |item| item.is_a?(String) }.map(&:strip).reject(&:empty?)
  elsif value.is_a?(String)
    value.split(/[,\s]+/).map(&:strip).reject(&:empty?)
  else
    []
  end
end

.summarize(raw_info) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/openreceive/server/wallet_info.rb', line 18

def summarize(raw_info)
  unwrapped = OpenReceive::Nwc.unwrap(raw_info)
  info = OpenReceive.stringify(unwrapped)
  raw_methods = %w[methods capabilities supported_methods supportedMethods]
                .map { |key| info[key] }
                .find { |value| !value.nil? }
  raw_methods = unwrapped if raw_methods.nil? && unwrapped.is_a?(String)
  methods = string_list(raw_methods).map { |name| normalize_method_name(name) }
  encryption = choose_encryption_mode(
    string_list(info["encryption"].nil? ? info["encryptions"] : info["encryption"])
  )
  spend_methods = methods.select { |name| SPEND_METHODS.include?(name) }
  missing_methods = REQUIRED_RECEIVE_METHODS.reject { |name| methods.include?(name) }
  {
    "methods" => methods,
    "encryption" => encryption,
    "spend_capability_advertised" => !spend_methods.empty?,
    "receive_checkout_ready" => missing_methods.empty?,
    "warnings" => spend_methods.map do |name|
      "Wallet advertises spend method '#{name}'; OpenReceive checkout will not expose it."
    end
  }
end