Utils.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <?php
  2. namespace App\Servers\Icon;
  3. use kornrunner\Keccak;
  4. /**
  5. * Class Utils
  6. * @package common\components\eth
  7. */
  8. class Utils
  9. {
  10. public static function fixHex($hex)
  11. {
  12. $hex = strtolower($hex);
  13. $hex = substr($hex, 0, 2) === '0x' ? $hex : ('0x' . $hex);
  14. if (strcmp($hex, '0x') === 0) {
  15. $hex = '0x0';
  16. }
  17. return $hex;
  18. }
  19. /**
  20. * @param string $url
  21. * @param mixed $rawData
  22. * @param int $timeout
  23. * @return bool|string
  24. */
  25. public static function post($url, $rawData, $timeout = 3)
  26. {
  27. $options = [
  28. CURLOPT_URL => $url,
  29. CURLOPT_POST => true,
  30. CURLOPT_RETURNTRANSFER => true,
  31. CURLOPT_FOLLOWLOCATION => true,
  32. CURLOPT_AUTOREFERER => true,
  33. CURLOPT_HEADER => false,
  34. CURLOPT_TIMEOUT => 5,
  35. CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_0,
  36. CURLOPT_HTTPHEADER => [
  37. 'Content-Type: application/json',
  38. 'Accept: application/json',
  39. ],
  40. CURLOPT_TIMEOUT => $timeout,
  41. CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
  42. CURLOPT_SSL_VERIFYHOST => false,
  43. CURLOPT_SSL_VERIFYPEER => false,
  44. CURLOPT_POSTFIELDS => $rawData,
  45. ];
  46. $ch = curl_init();
  47. curl_setopt_array($ch, $options);
  48. $rawResp = curl_exec($ch);
  49. // $e=curl_error($ch);
  50. if ($rawResp === false) {
  51. return false;
  52. }
  53. curl_close($ch);
  54. return $rawResp;
  55. }
  56. /**
  57. * Convert to wei
  58. * @param string $fund eg: 1eth, 0.1gwei
  59. * @return bool|string
  60. */
  61. public static function toWei($fund)
  62. {
  63. $pattern = '/^([\d]+(?:\.\d+)?)([a-zA-Z]+)/i';
  64. if (!preg_match($pattern, $fund, $matches)) {
  65. return false;
  66. }
  67. $fund = $matches[1];
  68. $unit = strtolower($matches[2]);
  69. return self::convertUnit($fund, $unit, 'wei');
  70. }
  71. /**
  72. * Convert to eth
  73. * @param string $fund eg: 567wei, 123gwei
  74. * @return bool|string
  75. */
  76. public static function toEther($fund)
  77. {
  78. $pattern = '/^([\d]+(?:\.\d+)?)([a-zA-Z]+)/i';
  79. if (!preg_match($pattern, $fund, $matches)) {
  80. return false;
  81. }
  82. $fund = $matches[1];
  83. $unit = strtolower($matches[2]);
  84. return self::convertUnit($fund, $unit, 'eth');
  85. }
  86. public static function fund2int($fund, $decimal = 18)
  87. {
  88. $rate = "1" . str_repeat('0', $decimal);
  89. return bcmul($fund, $rate);
  90. }
  91. public static function int2fund($int, $decimal = 18)
  92. {
  93. $rate = "1" . str_repeat('0', $decimal);
  94. $result = bcdiv($int, $rate, 5);
  95. if (strpos($result, '.') !== false) {
  96. list($int, $dec) = explode('.', $result);
  97. $dec = rtrim($dec, '0');
  98. if ($dec !== '') {
  99. $result = $int . '.' . $dec;
  100. } else {
  101. $result = $int;
  102. }
  103. }
  104. return $result;
  105. }
  106. /**
  107. * Ethereum units count against each other
  108. * @param string $number
  109. * @param string $from
  110. * @param string $to
  111. * @return bool|string
  112. */
  113. public static function convertUnit($number, $from, $to)
  114. {
  115. $units = [
  116. 'wei' => 0,
  117. 'kwei' => 3,
  118. 'mwei' => 6,
  119. 'gwei' => 9,
  120. 'microether' => 12,
  121. 'milliether' => 15,
  122. 'ether' => 18,
  123. 'eth' => 18,
  124. ];
  125. if (!isset($units[$from]) || !isset($units[$to])) {
  126. return false;
  127. }
  128. $maxDecimal = max($units); // max scale
  129. if ($units[$from] > $units[$to]) {
  130. $operator = "1" . str_repeat("0", $units[$from] - $units[$to]);
  131. $result = bcmul($number, $operator, $maxDecimal);
  132. } elseif ($units[$from] == $units[$to]) {
  133. $result = $number;
  134. } else {
  135. $operator = "1" . str_repeat("0", $units[$to] - $units[$from]);
  136. $result = bcdiv($number, $operator, $maxDecimal);
  137. }
  138. // The number of excess decimal digits after removing the result
  139. if (strpos($result, '.') !== false) {
  140. list($int, $dec) = explode('.', $result);
  141. $dec = rtrim($dec, '0');
  142. if ($dec !== '') {
  143. $result = $int . '.' . $dec;
  144. } else {
  145. $result = $int;
  146. }
  147. }
  148. return $result;
  149. }
  150. /**
  151. * @param $method
  152. * @param array $args
  153. * @return false|string
  154. */
  155. public static function decodeSolMethod($method, $args = [])
  156. {
  157. $pattern = '/^[a-z0-9]+\(([^\)]+)\)$/i';
  158. if (!preg_match($pattern, $method, $matched)) {
  159. return false;
  160. }
  161. try {
  162. $sign = substr(Keccak::hash($method, 256), 0, 8);
  163. $params = explode(',', $matched[1]); // 分析参数
  164. foreach ($params as $key => $param) {
  165. $arg = $args[$key];
  166. if (strpos($param, 'uint') !== false || strpos($param, 'int') !== false) {
  167. $paramSign = substr(self::dec2hex($arg), 2);
  168. } elseif (strpos($param, 'address') !== false) {
  169. $paramSign = substr(self::fixHex($arg), 2);
  170. } else {
  171. return false;
  172. }
  173. $sign .= str_pad($paramSign, 64, '0', STR_PAD_LEFT);
  174. }
  175. return self::fixHex($sign);
  176. } catch (\Exception $e) {
  177. return false;
  178. }
  179. }
  180. public static function dec2hex($number)
  181. {
  182. $hexvalues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
  183. $hexval = '';
  184. while ($number != '0') {
  185. $hexval = $hexvalues[bcmod($number, '16')] . $hexval;
  186. $number = bcdiv($number, '16', 0);
  187. }
  188. return self::fixHex($hexval);
  189. }
  190. public static function hex2dec($number)
  191. {
  192. if (strpos($number, '0x') !== false) {
  193. $number = substr($number, 2);
  194. }
  195. $number = strtoupper($number);
  196. $decvalues = [
  197. '0' => '0', '1' => '1', '2' => '2',
  198. '3' => '3', '4' => '4', '5' => '5',
  199. '6' => '6', '7' => '7', '8' => '8',
  200. '9' => '9', 'A' => '10', 'B' => '11',
  201. 'C' => '12', 'D' => '13', 'E' => '14',
  202. 'F' => '15'
  203. ];
  204. $decval = '0';
  205. $number = strrev($number);
  206. for ($i = 0; $i < strlen($number); $i++) {
  207. $decval = bcadd(bcmul(bcpow('16', $i, 0), $decvalues[$number[$i]]), $decval);
  208. }
  209. return $decval;
  210. }
  211. public static function prettyNum($number)
  212. {
  213. if ($number > 10000) {
  214. $number = bcdiv($number, "10000", 2) . '万';
  215. }
  216. return $number;
  217. }
  218. }