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%
2.3 KB · 70 lines swift
Raw Blame History
1//2//  Hex.swift3//  OS Vault4//5//  Author: Simon-Pierre Boucher6//  Mail: contact@spboucher.ai7//89import Foundation10import BigInt1112/// Minimal hex helpers for JSON-RPC quantities and calldata.13public enum Hex {1415    public static func quantity(_ value: BigUInt) -> String {16        "0x" + String(value, radix: 16)17    }1819    public static func toBigUInt(_ hex: String) -> BigUInt? {20        let stripped = hex.hasPrefix("0x") ? String(hex.dropFirst(2)) : hex21        if stripped.isEmpty { return 0 }22        return BigUInt(stripped, radix: 16)23    }2425    public static func data(_ hex: String) -> Data? {26        var stripped = hex.hasPrefix("0x") ? String(hex.dropFirst(2)) : hex27        if stripped.count % 2 != 0 { stripped = "0" + stripped }28        var out = Data(capacity: stripped.count / 2)29        var index = stripped.startIndex30        while index < stripped.endIndex {31            let next = stripped.index(index, offsetBy: 2)32            guard let byte = UInt8(stripped[index..<next], radix: 16) else { return nil }33            out.append(byte)34            index = next35        }36        return out37    }3839    public static func string(_ data: Data) -> String {40        "0x" + data.map { String(format: "%02x", $0) }.joined()41    }4243    /// Left-pads to a 32-byte ABI word.44    public static func abiWord(_ data: Data) -> Data {45        if data.count >= 32 { return data.suffix(32) }46        return Data(repeating: 0, count: 32 - data.count) + data47    }4849    public static func abiWord(_ value: BigUInt) -> Data {50        abiWord(value.serialize())51    }5253    /// ERC-20 `transfer(address,uint256)` calldata.54    public static func erc20TransferData(to recipient: String, amount: BigUInt) -> Data? {55        guard let addressData = data(recipient), addressData.count == 20 else { return nil }56        var calldata = Data([0xa9, 0x05, 0x9c, 0xbb])57        calldata.append(abiWord(addressData))58        calldata.append(abiWord(amount))59        return calldata60    }6162    /// ERC-20 `balanceOf(address)` calldata.63    public static func erc20BalanceOfData(owner: String) -> Data? {64        guard let addressData = data(owner), addressData.count == 20 else { return nil }65        var calldata = Data([0x70, 0xa0, 0x82, 0x31])66        calldata.append(abiWord(addressData))67        return calldata68    }69}70