Files
sure/app/models/kraken_account/asset_normalizer.rb
ghost be598aecf0 feat(providers): add Kraken exchange sync (#1759)
* feat(providers): add Kraken exchange sync

Adds family-scoped Kraken API-key connections, read-only balance and trade import, account setup/linking flows, provider status wiring, and focused test coverage.

Closes #1758

* test(providers): avoid Kraken sample secret false positive

* fix(providers): address Kraken review findings

* fix(providers): address Kraken review cleanup

* test(imports): stabilize transaction import ordering
2026-05-12 00:22:37 +02:00

68 lines
1.7 KiB
Ruby

# frozen_string_literal: true
class KrakenAccount::AssetNormalizer
SUFFIX_PATTERN = /(\.[A-Z])\z/
FIAT_PREFIXES = {
"ZUSD" => "USD",
"ZEUR" => "EUR",
"ZGBP" => "GBP",
"ZCAD" => "CAD",
"ZAUD" => "AUD",
"ZCHF" => "CHF",
"ZJPY" => "JPY"
}.freeze
SYMBOL_FALLBACKS = {
"XBT" => "BTC",
"XXBT" => "BTC",
"XETH" => "ETH",
"ZUSD" => "USD"
}.freeze
def initialize(asset_metadata = {})
@asset_metadata = asset_metadata || {}
end
def normalize(raw_asset)
raw = raw_asset.to_s.upcase
suffix = raw[SUFFIX_PATTERN, 1]
raw_base = suffix ? raw.delete_suffix(suffix) : raw
metadata = metadata_for(raw, raw_base)
base_symbol = metadata_symbol(metadata, raw_base)
normalized_base = normalize_base_symbol(base_symbol)
symbol = suffix.present? ? "#{normalized_base}#{suffix}" : normalized_base
{
raw_asset: raw,
raw_base: raw_base,
symbol: symbol,
price_symbol: normalized_base,
suffix: suffix,
metadata: metadata
}
end
private
attr_reader :asset_metadata
def metadata_for(raw, raw_base)
asset_metadata[raw] || asset_metadata[raw_base] || asset_metadata.values.find do |metadata|
candidate = metadata_symbol(metadata, raw_base)
[ raw, raw_base ].include?(candidate.to_s.upcase)
end
end
def metadata_symbol(metadata, fallback)
return fallback unless metadata.is_a?(Hash)
metadata["altname"].presence || metadata["display_name"].presence || fallback
end
def normalize_base_symbol(symbol)
value = symbol.to_s.upcase
value = FIAT_PREFIXES[value] if FIAT_PREFIXES.key?(value)
SYMBOL_FALLBACKS[value] || value
end
end