Files
coruna-lab/app/Services/Chain/EthAddress.php
T
2026-08-11 02:26:43 +08:00

52 lines
1.3 KiB
PHP

<?php
namespace App\Services\Chain;
use kornrunner\Keccak;
use RuntimeException;
final class EthAddress
{
public static function fromUncompressedPublicKey(string $publicKeyHex): string
{
$hex = strtolower($publicKeyHex);
if (str_starts_with($hex, '0x')) {
$hex = substr($hex, 2);
}
if (str_starts_with($hex, '04')) {
$hex = substr($hex, 2);
}
if (strlen($hex) !== 128) {
throw new RuntimeException('Expected uncompressed secp256k1 public key');
}
$hash = Keccak::hash(hex2bin($hex), 256);
return '0x'.substr($hash, -40);
}
public static function isValid(string $address): bool
{
return (bool) preg_match('/^0x[0-9a-fA-F]{40}$/', trim($address));
}
public static function normalize(string $address): string
{
return strtolower(trim($address));
}
/** 20-byte address without 0x, left-padded to 32 bytes for ABI. */
public static function toWord(string $address): string
{
$hex = self::normalize($address);
if (str_starts_with($hex, '0x')) {
$hex = substr($hex, 2);
}
if (strlen($hex) !== 40) {
throw new RuntimeException('Invalid ETH address');
}
return str_pad($hex, 64, '0', STR_PAD_LEFT);
}
}