toHex(true); $hex = preg_replace('/^0+(?!$)/', '', $hex); } elseif (is_string($value)) { $value = self::stripZero($value); $hex = implode('', unpack('H*', $value)); } elseif ($value instanceof BigInteger) { $hex = $value->toHex(true); $hex = preg_replace('/^0+(?!$)/', '', $hex); } else { throw new InvalidArgumentException('The value to toHex function is not support.'); } if ($isPrefix) { return '0x' . $hex; } return $hex; } /** * hexToBin * * @param string * @return string */ public static function hexToBin($value) { if (!is_string($value)) { throw new InvalidArgumentException('The value to hexToBin function must be string.'); } if (self::isZeroPrefixed($value)) { $count = 1; $value = str_replace('0x', '', $value, $count); } return pack('H*', $value); } /** * isZeroPrefixed * * @param string * @return bool */ public static function isZeroPrefixed($value) { if (!is_string($value)) { throw new InvalidArgumentException('The value to isZeroPrefixed function must be string.'); } return (strpos($value, '0x') === 0); } /** * stripZero * * @param string $value * @return string */ public static function stripZero($value) { if (self::isZeroPrefixed($value)) { $count = 1; return str_replace('0x', '', $value, $count); } return $value; } /** * isNegative * * @param string * @return bool */ public static function isNegative($value) { if (!is_string($value)) { throw new InvalidArgumentException('The value to isNegative function must be string.'); } return (strpos($value, '-') === 0); } /** * isAddress * * @param string $value * @return bool */ public static function isAddress($value) { if (!is_string($value)) { throw new InvalidArgumentException('The value to isAddress function must be string.'); } if (preg_match('/^(0x|0X)?[a-f0-9A-F]{40}$/', $value) !== 1) { return false; } elseif (preg_match('/^(0x|0X)?[a-f0-9]{40}$/', $value) === 1 || preg_match('/^(0x|0X)?[A-F0-9]{40}$/', $value) === 1) { return true; } return self::isAddressChecksum($value); } /** * isAddressChecksum * * @param string $value * @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; } /** * isHex * * @param string $value * @return bool */ public static function isHex($value) { return (is_string($value) && preg_match('/^(0x)?[a-f0-9A-F]*$/', $value) === 1); } /** * sha3 * keccak256 * * @param string $value * @return string */ public static function sha3($value) { if (!is_string($value)) { throw new InvalidArgumentException('The value to sha3 function must be string.'); } if (strpos($value, '0x') === 0) { $value = self::hexToBin($value); } $hash = Keccak::hash($value, 256); if ($hash === self::SHA3_NULL_HASH) { return null; } return $hash; } /** * toBn * Change number or number string to BigInteger. * * @param BigInteger|string|int $number * @return array|BigInteger */ public static function toBn($number) { if ($number instanceof BigInteger) { $bn = $number; } elseif (is_int($number)) { $bn = new BigInteger($number); } elseif (is_numeric($number)) { $number = (string) $number; if (self::isNegative($number)) { $count = 1; $number = str_replace('-', '', $number, $count); $negative1 = new BigInteger(-1); } if (strpos($number, '.') > 0) { $comps = explode('.', $number); if (count($comps) > 2) { throw new InvalidArgumentException('toBn number must be a valid number.'); } $whole = $comps[0]; $fraction = $comps[1]; return [ new BigInteger($whole), new BigInteger($fraction), strlen($comps[1]), isset($negative1) ? $negative1 : false ]; } else { $bn = new BigInteger($number); } if (isset($negative1)) { $bn = $bn->multiply($negative1); } } elseif (is_string($number)) { $number = mb_strtolower($number); if (self::isNegative($number)) { $count = 1; $number = str_replace('-', '', $number, $count); $negative1 = new BigInteger(-1); } if (self::isZeroPrefixed($number) || preg_match('/[a-f]+/', $number) === 1) { $number = self::stripZero($number); $bn = new BigInteger($number, 16); } elseif (empty($number)) { $bn = new BigInteger(0); } else { throw new InvalidArgumentException('toBn number must be valid hex string.'); } if (isset($negative1)) { $bn = $bn->multiply($negative1); } } else { throw new InvalidArgumentException('toBn number must be BigInteger, string or int.'); } return $bn; } /** * 根据精度展示资产 * @param $number * @param int $decimals * @return string */ public static function toDisplayAmount($number, int $decimals) { $number = number_format($number,0,'.','');//格式化 $bn = self::toBn($number); $bnt = self::toBn(pow(10, $decimals)); return self::divideDisplay($bn->divide($bnt), $decimals); } public static function divideDisplay(array $divResult, int $decimals) { list($bnq, $bnr) = $divResult; $ret = "$bnq->value"; if ($bnr->value > 0) { $ret .= '.' . rtrim(sprintf("%0{$decimals}d", $bnr->value), '0'); } return $ret; } public static function toMinUnitByDecimals($number, int $decimals) { $bn = self::toBn($number); $bnt = self::toBn(pow(10, $decimals)); if (is_array($bn)) { // fraction number list($whole, $fraction, $fractionLength, $negative1) = $bn; $whole = $whole->multiply($bnt); switch (MATH_BIGINTEGER_MODE) { case $whole::MODE_GMP: static $two; $powerBase = gmp_pow(gmp_init(10), (int) $fractionLength); break; case $whole::MODE_BCMATH: $powerBase = bcpow('10', (string) $fractionLength, 0); break; default: $powerBase = pow(10, (int) $fractionLength); break; } $base = new BigInteger($powerBase); $fraction = $fraction->multiply($bnt)->divide($base)[0]; if ($negative1 !== false) { return $whole->add($fraction)->multiply($negative1); } return $whole->add($fraction); } return $bn->multiply($bnt); } }