SPB Git

spb/os-vault Public

Self-custody, multi-chain crypto wallet for macOS. One recovery phrase, six chain families, zero API keys — nothing leaves your Mac.

Swift 96% Shell 3.4% Makefile 0.6%
1.6 KB · 44 lines swift
Raw Blame History
1//2//  AddressValidator.swift3//  OS Vault4//5//  Author: Simon-Pierre Boucher6//  Mail: contact@spboucher.ai7//89import Foundation10import Web3Core1112/// Recipient address validation: hex shape + EIP-55 checksum.13/// All-lowercase (or all-uppercase) addresses carry no checksum information —14/// they are accepted with a warning, per the project security rules.15public enum AddressValidator {1617    public enum Verdict: Equatable {18        /// Mixed-case address whose EIP-55 checksum matches.19        case valid(checksummed: String)20        /// Well-formed but caseless — no checksum to verify. Warn, don't block.21        case validNoChecksum(checksummed: String)22        case invalid23    }2425    public static func validate(_ input: String) -> Verdict {26        let candidate = input.trimmingCharacters(in: .whitespacesAndNewlines)27        guard candidate.count == 42, candidate.hasPrefix("0x") else { return .invalid }28        let body = String(candidate.dropFirst(2))29        guard body.allSatisfy({ $0.isHexDigit }) else { return .invalid }30        guard let checksummed = EthereumAddress.toChecksumAddress(candidate) else { return .invalid }3132        // An exact checksum match is valid even when it happens to be all one33        // case (some EIP-55 checksums are, e.g. 0x529084…9EE7).34        if candidate == checksummed {35            return .valid(checksummed: checksummed)36        }37        let letters = body.filter { $0.isLetter }38        let caseless = letters.isEmpty39            || letters.allSatisfy { $0.isLowercase }40            || letters.allSatisfy { $0.isUppercase }41        return caseless ? .validNoChecksum(checksummed: checksummed) : .invalid42    }43}44