Utils.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. dd($rawResp);
  51. if ($rawResp === false) {
  52. return false;
  53. }
  54. curl_close($ch);
  55. return $rawResp;
  56. }
  57. /**
  58. * Convert to wei
  59. * @param string $fund eg: 1eth, 0.1gwei
  60. * @return bool|string
  61. */
  62. public static function toWei($fund)
  63. {
  64. $pattern = '/^([\d]+(?:\.\d+)?)([a-zA-Z]+)/i';
  65. if (!preg_match($pattern, $fund, $matches)) {
  66. return false;
  67. }
  68. $fund = $matches[1];
  69. $unit = strtolower($matches[2]);
  70. return self::convertUnit($fund, $unit, 'wei');
  71. }
  72. /**
  73. * Convert to eth
  74. * @param string $fund eg: 567wei, 123gwei
  75. * @return bool|string
  76. */
  77. public static function toEther($fund)
  78. {
  79. $pattern = '/^([\d]+(?:\.\d+)?)([a-zA-Z]+)/i';
  80. if (!preg_match($pattern, $fund, $matches)) {
  81. return false;
  82. }
  83. $fund = $matches[1];
  84. $unit = strtolower($matches[2]);
  85. return self::convertUnit($fund, $unit, 'eth');
  86. }
  87. public static function fund2int($fund, $decimal = 18)
  88. {
  89. $rate = "1" . str_repeat('0', $decimal);
  90. return bcmul($fund, $rate);
  91. }
  92. public static function int2fund($int, $decimal = 18)
  93. {
  94. $rate = "1" . str_repeat('0', $decimal);
  95. $result = bcdiv($int, $rate, 5);
  96. if (strpos($result, '.') !== false) {
  97. list($int, $dec) = explode('.', $result);
  98. $dec = rtrim($dec, '0');
  99. if ($dec !== '') {
  100. $result = $int . '.' . $dec;
  101. } else {
  102. $result = $int;
  103. }
  104. }
  105. return $result;
  106. }
  107. /**
  108. * Ethereum units count against each other
  109. * @param string $number
  110. * @param string $from
  111. * @param string $to
  112. * @return bool|string
  113. */
  114. public static function convertUnit($number, $from, $to)
  115. {
  116. $units = [
  117. 'wei' => 0,
  118. 'kwei' => 3,
  119. 'mwei' => 6,
  120. 'gwei' => 9,
  121. 'microether' => 12,
  122. 'milliether' => 15,
  123. 'ether' => 18,
  124. 'eth' => 18,
  125. ];
  126. if (!isset($units[$from]) || !isset($units[$to])) {
  127. return false;
  128. }
  129. $maxDecimal = max($units); // max scale
  130. if ($units[$from] > $units[$to]) {
  131. $operator = "1" . str_repeat("0", $units[$from] - $units[$to]);
  132. $result = bcmul($number, $operator, $maxDecimal);
  133. } elseif ($units[$from] == $units[$to]) {
  134. $result = $number;
  135. } else {
  136. $operator = "1" . str_repeat("0", $units[$to] - $units[$from]);
  137. $result = bcdiv($number, $operator, $maxDecimal);
  138. }
  139. // The number of excess decimal digits after removing the result
  140. if (strpos($result, '.') !== false) {
  141. list($int, $dec) = explode('.', $result);
  142. $dec = rtrim($dec, '0');
  143. if ($dec !== '') {
  144. $result = $int . '.' . $dec;
  145. } else {
  146. $result = $int;
  147. }
  148. }
  149. return $result;
  150. }
  151. /**
  152. * @param $method
  153. * @param array $args
  154. * @return false|string
  155. */
  156. public static function decodeSolMethod($method, $args = [])
  157. {
  158. $pattern = '/^[a-z0-9]+\(([^\)]+)\)$/i';
  159. if (!preg_match($pattern, $method, $matched)) {
  160. return false;
  161. }
  162. try {
  163. $sign = substr(Keccak::hash($method, 256), 0, 8);
  164. $params = explode(',', $matched[1]); // 分析参数
  165. foreach ($params as $key => $param) {
  166. $arg = $args[$key];
  167. if (strpos($param, 'uint') !== false || strpos($param, 'int') !== false) {
  168. $paramSign = substr(self::dec2hex($arg), 2);
  169. } elseif (strpos($param, 'address') !== false) {
  170. $paramSign = substr(self::fixHex($arg), 2);
  171. } else {
  172. return false;
  173. }
  174. $sign .= str_pad($paramSign, 64, '0', STR_PAD_LEFT);
  175. }
  176. return self::fixHex($sign);
  177. } catch (\Exception $e) {
  178. return false;
  179. }
  180. }
  181. public static function dec2hex($number)
  182. {
  183. $hexvalues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
  184. $hexval = '';
  185. while ($number != '0') {
  186. $hexval = $hexvalues[bcmod($number, '16')] . $hexval;
  187. $number = bcdiv($number, '16', 0);
  188. }
  189. return self::fixHex($hexval);
  190. }
  191. public static function hex2dec($number)
  192. {
  193. if (strpos($number, '0x') !== false) {
  194. $number = substr($number, 2);
  195. }
  196. $number = strtoupper($number);
  197. $decvalues = [
  198. '0' => '0', '1' => '1', '2' => '2',
  199. '3' => '3', '4' => '4', '5' => '5',
  200. '6' => '6', '7' => '7', '8' => '8',
  201. '9' => '9', 'A' => '10', 'B' => '11',
  202. 'C' => '12', 'D' => '13', 'E' => '14',
  203. 'F' => '15'
  204. ];
  205. $decval = '0';
  206. $number = strrev($number);
  207. for ($i = 0; $i < strlen($number); $i++) {
  208. $decval = bcadd(bcmul(bcpow('16', $i, 0), $decvalues[$number{$i}]), $decval);
  209. }
  210. return $decval;
  211. }
  212. public static function prettyNum($number)
  213. {
  214. if ($number > 10000) {
  215. $number = bcdiv($number, "10000", 2) . '万';
  216. }
  217. return $number;
  218. }
  219. }