diff --git a/src/Utils.php b/src/Utils.php index 59c26de..1d1fd50 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -138,7 +138,6 @@ class Utils /** * isAddress - * To do: check address checksum * * @param string * @return bool @@ -148,12 +147,35 @@ class Utils if (!is_string($value)) { throw new InvalidArgumentException('The value to isAddress function must be string.'); } - if (preg_match('/^(0x|0X)?[a-fA-F0-9]{40}$/', $value) == 1) { + if (preg_match('/^(0x|0X)?[a-f0-9]{40}$/', $value) === 1 || preg_match('/^(0x|0X)?[A-F0-9]{40}$/', $value) === 1) { return true; - } else { - // validate address checksum } - return false; + return self::isAddressChecksum($value); + } + + /** + * isAddressChecksum + * + * @param string + * @return bool + */ + public static function isAddressChecksum($value) + { + if (!is_string($value)) { + throw new InvalidArgumentException('The value to isAddressChecksum function must be string.'); + } + $value = self::stripZero($value); + $hash = self::stripZero(self::sha3(mb_strtolower($value))); + + for ($i = 0; $i < 40; $i++) { + if ( + (intval($hash[$i], 16) > 7 && mb_strtoupper($value[$i]) !== $value[$i]) || + (intval($hash[$i], 16) <= 7 && mb_strtolower($value[$i]) !== $value[$i]) + ) { + return false; + } + } + return true; } /** diff --git a/test/unit/UtilsTest.php b/test/unit/UtilsTest.php index a464cc0..6c683ea 100644 --- a/test/unit/UtilsTest.php +++ b/test/unit/UtilsTest.php @@ -140,6 +140,58 @@ class UtilsTest extends TestCase $this->assertEquals($isAddress, true); } + /** + * testIsAddressChecksum + * + * @return void + */ + public function testIsAddressChecksum() + { + $isAddressChecksum = Utils::isAddressChecksum('0x52908400098527886E0F7030069857D2E4169EE7'); + + $this->assertEquals($isAddressChecksum, true); + + $isAddressChecksum = Utils::isAddressChecksum('0x8617E340B3D01FA5F11F306F4090FD50E238070D'); + + $this->assertEquals($isAddressChecksum, true); + + $isAddressChecksum = Utils::isAddressChecksum('0xde709f2102306220921060314715629080e2fb77'); + + $this->assertEquals($isAddressChecksum, true); + + $isAddressChecksum = Utils::isAddressChecksum('0x27b1fdb04752bbc536007a920d24acb045561c26'); + + $this->assertEquals($isAddressChecksum, true); + + $isAddressChecksum = Utils::isAddressChecksum('0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed'); + + $this->assertEquals($isAddressChecksum, true); + + $isAddressChecksum = Utils::isAddressChecksum('0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed'); + + $this->assertEquals($isAddressChecksum, true); + + $isAddressChecksum = Utils::isAddressChecksum('0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359'); + + $this->assertEquals($isAddressChecksum, true); + + $isAddressChecksum = Utils::isAddressChecksum('0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB'); + + $this->assertEquals($isAddressChecksum, true); + + $isAddressChecksum = Utils::isAddressChecksum('0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb'); + + $this->assertEquals($isAddressChecksum, true); + + $isAddressChecksum = Utils::isAddressChecksum('0XD1220A0CF47C7B9BE7A2E6BA89F429762E7B9ADB'); + + $this->assertEquals($isAddressChecksum, false); + + $isAddressChecksum = Utils::isAddressChecksum('0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb'); + + $this->assertEquals($isAddressChecksum, false); + } + /** * testStripZero *