UNPKG

chaingate

Version:

Multi-chain cryptocurrency SDK for TypeScript — unified API for Bitcoin, Ethereum, Litecoin, Dogecoin, Bitcoin Cash, Polygon, Arbitrum, and any EVM-compatible chain. Create wallets, query balances, send transactions, and manage tokens and NFTs across UTXO

81 lines (80 loc) 3.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.privateKeyToPublicKey = privateKeyToPublicKey; exports.compressPublicKey = compressPublicKey; exports.publicKeyToEthAddress = publicKeyToEthAddress; exports.isValidEvmAddress = isValidEvmAddress; const secp256k1_js_1 = require("@noble/curves/secp256k1.js"); const sha3_js_1 = require("@noble/hashes/sha3.js"); const encoding_1 = require("./encoding"); /** * Returns the compressed public key for a given private key. * * @param privateKey - The private key bytes. * @returns The compressed public key bytes. */ function privateKeyToPublicKey(privateKey) { return secp256k1_js_1.secp256k1.getPublicKey(privateKey, true); } /** * Compresses a public key to its short form. Accepts both compressed and uncompressed keys. * * @param raw - The public key bytes (compressed or uncompressed). * @returns The compressed public key bytes. */ function compressPublicKey(raw) { // Use hex to avoid Uint8Array type variance issues with @noble/curves const point = secp256k1_js_1.secp256k1.Point.fromHex((0, encoding_1.bytesToHex)(raw)); return point.toBytes(true); } /** * Derives an EIP-55 checksummed Ethereum address from a compressed or uncompressed public key. * * @param publicKey - The public key bytes (compressed or uncompressed). * @returns The checksummed Ethereum address (e.g. `"0xAb5801a7..."`). */ function publicKeyToEthAddress(publicKey) { // Decompress to the uncompressed form (65 bytes: 04 || x || y), // then drop the 0x04 prefix to get the raw 64-byte x||y. const point = secp256k1_js_1.secp256k1.Point.fromHex((0, encoding_1.bytesToHex)(publicKey)); const uncompressed = point.toBytes(false); // 65 bytes const xy = uncompressed.slice(1); // 64 bytes const hash = (0, sha3_js_1.keccak_256)(xy); const rawAddress = (0, encoding_1.bytesToHex)(hash.slice(12)); // last 20 bytes return toEip55Checksum(rawAddress); } /** * Applies EIP-55 mixed-case checksum to a raw hex address. */ function toEip55Checksum(address) { const lower = address.toLowerCase(); const hashHex = (0, encoding_1.bytesToHex)((0, sha3_js_1.keccak_256)(new TextEncoder().encode(lower))); let checksummed = '0x'; for (let i = 0; i < lower.length; i++) { const char = lower[i]; checksummed += parseInt(hashHex[i], 16) >= 8 ? char.toUpperCase() : char; } return checksummed; } // Matches exactly 40 hex characters, with or without 0x prefix. const EVM_ADDRESS_RE = /^(0x)?[0-9a-fA-F]{40}$/; /** * Checks whether a string is a valid EVM address. * * Accepts both checksummed and all-lowercase/all-uppercase forms. * When the address uses mixed case, the EIP-55 checksum is verified. * * @param address - The address string to validate. * @returns `true` if the address is valid. */ function isValidEvmAddress(address) { if (!EVM_ADDRESS_RE.test(address)) return false; // Strip 0x prefix for checksum evaluation. const raw = address.startsWith('0x') || address.startsWith('0X') ? address.slice(2) : address; // All-lowercase or all-uppercase is valid without checksum verification. if (raw === raw.toLowerCase() || raw === raw.toUpperCase()) return true; // Mixed case → verify EIP-55 checksum. return toEip55Checksum(raw) === `0x${raw}`; }