@frak-labs/core-sdk
Version:
Core SDK of the Frak wallet, low level library to interact directly with the frak ecosystem.
77 lines (69 loc) • 2.66 kB
text/typescript
import type { Address } from "viem";
/**
* Address utilities — minimal, dependency-free replacements for the subset of
* `viem` helpers we used to import. Keeping these in-house lets the SDK ship
* without pulling viem's checksum/keccak/error chain into the bundle.
*
* Scope is intentionally narrow:
* - `isAddress`: shape-only validation (no EIP-55 checksum)
* - `areAddressesEqual`: case-insensitive equality
* - `addressToBytes` / `bytesToAddress`: fixed 20-byte conversion
*/
/** Matches a 0x-prefixed 40-char hex string regardless of case. */
const ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
/**
* Check whether a value is a syntactically valid Ethereum address.
*
* This intentionally skips EIP-55 checksum validation: the SDK never produces
* checksum-cased payloads, and downstream consumers (wallet, indexer) treat
* addresses case-insensitively. Avoiding the checksum path drops keccak256 +
* @noble/hashes from the bundle.
*/
export function isAddress(value: unknown): value is Address {
return typeof value === "string" && ADDRESS_REGEX.test(value);
}
/**
* Case-insensitive equality check for two Ethereum addresses.
*
* Both inputs are assumed to be syntactically valid addresses; callers that
* receive untrusted input should validate via {@link isAddress} first.
*/
export function areAddressesEqual(a: Address, b: Address): boolean {
return a.toLowerCase() === b.toLowerCase();
}
/**
* Decode a 20-byte Ethereum address into a fixed-size Uint8Array(20).
*
* Throws when the input is not exactly `0x` + 40 hex chars — callers wrap
* the call in try/catch (see {@link FrakContextManager.compress}) so any
* malformed input degrades to a graceful undefined return.
*/
export function addressToBytes(address: Address): Uint8Array {
const bytes = new Uint8Array(20);
for (let i = 0; i < 20; i++) {
const byte = Number.parseInt(
address.substring(2 + i * 2, 4 + i * 2),
16
);
if (Number.isNaN(byte)) {
throw new Error(`Invalid address: ${address}`);
}
bytes[i] = byte;
}
return bytes;
}
/** Lookup table avoids `padStart` overhead in the hot encode loop. */
const HEX_BYTE = /*#__PURE__*/ Array.from({ length: 256 }, (_, i) =>
i.toString(16).padStart(2, "0")
);
/**
* Encode a 20-byte Uint8Array (or a 20-byte subarray view) into a lowercase
* hex Ethereum address. The caller MUST guarantee `bytes.length === 20`.
*/
export function bytesToAddress(bytes: Uint8Array): Address {
let out = "0x";
for (let i = 0; i < 20; i++) {
out += HEX_BYTE[bytes[i]];
}
return out as Address;
}