{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "wallet-address",
  "type": "registry:lib",
  "dependencies": [
    "bs58"
  ],
  "files": [
    {
      "path": "src/registry/lib/wallet-address.ts",
      "content": "import { createHash } from \"crypto\";\nimport { Point } from \"@noble/ed25519\";\nimport bs58 from \"bs58\";\nimport { keccak256 } from \"js-sha3\";\n\ntype Network = \"evm\" | \"tron\" | \"solana\";\n\nexport const isAddress = (address: string, network: Network = \"evm\") => {\n  switch (network) {\n    case \"evm\":\n      return isEVMAddress(address);\n    case \"tron\":\n      return isTronAddress(address);\n    case \"solana\":\n      return isSolanaAddress(address);\n  }\n};\n\n// ============ EVM ============\n\nconst EVM_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;\n\nexport const isEVMAddress = (address: string, strict = true) => {\n  if (!EVM_ADDRESS_REGEX.test(address)) return false;\n  if (address.toLowerCase() === address) return true;\n  if (strict) return checksumAddress(address) === address;\n  return true;\n};\n\nexport const checksumAddress = (address: string, chainId?: number) => {\n  const hexAddress = chainId\n    ? `${chainId}${address.toLowerCase()}`\n    : address.substring(2).toLowerCase();\n  const hash = keccak256.array(stringToBytes(hexAddress));\n  const addr = (\n    chainId ? hexAddress.substring(`${chainId}0x`.length) : hexAddress\n  ).split(\"\");\n  for (let i = 0; i < 40; i += 2) {\n    if (hash[i >> 1] >> 4 >= 8 && addr[i]) {\n      addr[i] = addr[i].toUpperCase();\n    }\n    if ((hash[i >> 1] & 0x0f) >= 8 && addr[i + 1]) {\n      addr[i + 1] = addr[i + 1].toUpperCase();\n    }\n  }\n  return `0x${addr.join(\"\")}`;\n};\n\nconst stringToBytes = (str: string) => {\n  const bytes = new Uint8Array(str.length);\n  for (let i = 0; i < str.length; i++) {\n    bytes[i] = str.charCodeAt(i);\n  }\n  return bytes;\n};\n\n// ============ Tron ============\n\nconst TRON_ADDRESS_SIZE = 34;\nconst TRON_ADDRESS_PREFIX_BYTE = 0x41;\n\nexport const isTronAddress = (address: string) => {\n  if (address.length !== TRON_ADDRESS_SIZE) return false;\n\n  let decodeAddr = bs58.decode(address);\n  if (decodeAddr.length !== 25) return false;\n\n  if (decodeAddr[0] !== TRON_ADDRESS_PREFIX_BYTE) return false;\n\n  const checkSum = decodeAddr.slice(21);\n  decodeAddr = decodeAddr.slice(0, 21);\n\n  const hash0 = hexToBytes(sha256(decodeAddr));\n  const hash1 = hexToBytes(sha256(hash0));\n  const checkSum1 = hash1.slice(0, 4);\n\n  if (\n    checkSum[0] === checkSum1[0] &&\n    checkSum[1] === checkSum1[1] &&\n    checkSum[2] === checkSum1[2] &&\n    checkSum[3] === checkSum1[3]\n  )\n    return true;\n\n  return false;\n};\n\n/**\n * SHA256 hash function\n */\nfunction sha256(data: Uint8Array): string {\n  return createHash(\"sha256\").update(data).digest(\"hex\");\n}\n\n/**\n * Converts hex string to Uint8Array\n */\nfunction hexToBytes(hex: string): Uint8Array {\n  const bytes = new Uint8Array(hex.length / 2);\n  for (let i = 0; i < hex.length; i += 2) {\n    bytes[i / 2] = Number.parseInt(hex.slice(i, i + 2), 16);\n  }\n  return bytes;\n}\n\n// ============ Solana ============\n\nconst SOLANA_PUBKEY_BYTES = 32;\nconst SOLANA_ADDRESS_REGEX = /^[1-9A-HJ-NP-Za-km-z]{43,44}$/;\n\nexport const isSolanaAddress = (address: string): boolean => {\n  if (!SOLANA_ADDRESS_REGEX.test(address)) {\n    return false;\n  }\n\n  try {\n    const decoded = bs58.decode(address);\n    if (decoded.length !== SOLANA_PUBKEY_BYTES) {\n      return false;\n    }\n\n    if (decoded.every((byte) => byte === 0)) {\n      return false;\n    }\n\n    Point.fromBytes(decoded);\n    return true;\n  } catch {\n    return false;\n  }\n};\n",
      "type": "registry:lib",
      "target": "lib/wallet-address.ts"
    }
  ]
}