BlockChianService.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. <?php
  2. namespace crmeb\services\blockchain;
  3. use app\models\lala\WalletLog;
  4. use app\models\user\UserMoney;
  5. use crmeb\basic\BaseModel;
  6. use GuzzleHttp\Client;
  7. use think\db\exception\DataNotFoundException;
  8. use think\db\exception\DbException;
  9. use think\db\exception\ModelNotFoundException;
  10. use think\facade\Log;
  11. use Tron\Address;
  12. use Tron\Api;
  13. use Tron\Exceptions\TronErrorException;
  14. use Tron\TRC20;
  15. use Tron\TRX;
  16. class BlockChianService
  17. {
  18. //TODO main
  19. /**
  20. * 生成地址
  21. * @param string $code
  22. * @return array
  23. */
  24. public static function createAddress(string $code): array
  25. {
  26. $code = strtoupper($code);
  27. if (method_exists(self::class, $code . 'CreateAddress')) {
  28. $function = $code . 'CreateAddress';
  29. return self::$function();
  30. } else {
  31. return ["privateKey" => "",
  32. "address" => "",
  33. "hexAddress" => ""];
  34. }
  35. }
  36. /**
  37. * 生成地址
  38. * @param string $code
  39. * @param string $address
  40. * @return float
  41. */
  42. public static function balance(string $code, string $address): float
  43. {
  44. $code = strtoupper($code);
  45. if (method_exists(self::class, $code . 'Balance')) {
  46. $function = $code . 'Balance';
  47. return self::$function($address);
  48. } else {
  49. return 0;
  50. }
  51. }
  52. /**
  53. * 归集
  54. * @param array $money_info
  55. * @param string $summary_address
  56. * @param Address $gas_address
  57. * @return bool
  58. */
  59. public static function summary(array $money_info, string $summary_address, Address $gas_address): bool
  60. {
  61. $code = strtoupper($money_info['money_type']);
  62. if (method_exists(self::class, $code . 'Summary')) {
  63. $function = $code . 'Summary';
  64. return self::$function($money_info, $summary_address, $gas_address);
  65. } else {
  66. Log::error('币种' . $code . '尚不支持归集');
  67. return true;
  68. }
  69. }
  70. /**
  71. * 交易
  72. * @param string $code
  73. * @param Address $from
  74. * @param Address $to
  75. * @param float $amount
  76. * @return bool
  77. */
  78. public static function transfer(string $code, Address $from, Address $to, float $amount): bool
  79. {
  80. $code = strtoupper($code);
  81. if (method_exists(self::class, $code . 'Transfer')) {
  82. $function = $code . 'Transfer';
  83. return self::$function($from, $to, $amount);
  84. } else {
  85. Log::error('币种' . $code . '尚不支持交易');
  86. return true;
  87. }
  88. }
  89. /**
  90. * 获取交易
  91. * @param string $code
  92. * @param $address
  93. * @param $start_time
  94. * @return array
  95. */
  96. public static function checkTransfer(string $code, $address, $start_time): array
  97. {
  98. $code = strtoupper($code);
  99. if (method_exists(self::class, $code . 'CheckTransfer')) {
  100. $function = $code . 'CheckTransfer';
  101. return self::$function($address, $start_time);
  102. } else {
  103. return [];
  104. }
  105. }
  106. /**
  107. * 查询交易
  108. * @param string $code
  109. * @param string $txID
  110. * @return array
  111. */
  112. public static function getTransfer(string $code, string $txID): array
  113. {
  114. $code = strtoupper($code);
  115. if (method_exists(self::class, $code . 'GetTransfer')) {
  116. $function = $code . 'GetTransfer';
  117. return self::$function($txID);
  118. } else {
  119. return [];
  120. }
  121. }
  122. //TODO main - end
  123. //TODO auto
  124. /**
  125. * 自动获取交易记录
  126. * @return bool
  127. */
  128. public static function autoGetTransfer(): bool
  129. {
  130. $address = UserMoney::select();
  131. foreach ($address as $v) {
  132. if ($v['address']) {
  133. $res = BlockChianService::checkTransfer($v['money_type'], $v['address'], $v['max_timestamp'] + 1);
  134. // var_dump($res);
  135. // BaseModel::rollbackTrans();
  136. // exit();
  137. if ($res) {
  138. // $max_timestamp = $v['max_timestamp'];
  139. switch ($v['money_type']) {
  140. case 'USDT':
  141. case 'LALA':
  142. if (isset($res['data'])) {
  143. foreach ($res['data'] as $vv) {
  144. // if ($vv['block_timestamp'] > $max_timestamp) {
  145. // $max_timestamp = $vv['block_timestamp'];
  146. // }
  147. $data = [
  148. 'symbol' => $v['money_type'],
  149. 'transaction_id' => $vv['transaction_id'],
  150. 'from' => $vv['from'],
  151. 'to' => $vv['to'],
  152. 'type' => $vv['type'],
  153. 'amount' => bcdiv($vv['value'], bcpow(10, $vv['token_info']['decimals']), 8),
  154. 'block_timestamp' => $vv['block_timestamp'],
  155. ];
  156. if (!WalletLog::be($data)) {
  157. WalletLog::beginTrans();
  158. try {
  159. WalletLog::create($data);
  160. WalletLog::commitTrans();
  161. } catch (\Exception $e) {
  162. WalletLog::rollbackTrans();
  163. Log::error('AutoLoadTransferFail:' . $e->getMessage());
  164. return false;
  165. }
  166. }
  167. }
  168. }
  169. break;
  170. default:
  171. break;
  172. }
  173. // }
  174. }
  175. UserMoney::beginTrans();
  176. // if ($max_timestamp != $v['max_timestamp']) {
  177. try {
  178. UserMoney::where('address', $v['address'])->update(['max_timestamp' => time() * 1000]);
  179. UserMoney::commitTrans();
  180. } catch (\Exception $e) {
  181. UserMoney::rollbackTrans();
  182. Log::error('AutoLoadTransferFail:' . $e->getMessage());
  183. return false;
  184. }
  185. }
  186. }
  187. return true;
  188. }
  189. /**
  190. * 自动确认交易
  191. * @return bool
  192. */
  193. public static function autoCheckTransfer(): bool
  194. {
  195. BaseModel::beginTrans();
  196. try {
  197. $list = WalletLog::where('state', 0)->select();
  198. foreach ($list as $v) {
  199. $res = BlockChianService::getTransfer($v['symbol'], $v['transaction_id']);
  200. if ($res['status']) {
  201. switch ($v['symbol']) {
  202. case 'USDT':
  203. case 'LALA':
  204. if (isset($res['data'])) {
  205. if (isset($res['data']->contractRet)) {
  206. if ($res['data']->contractRet === 'SUCCESS') {
  207. $update['state'] = 1;
  208. WalletLog::where('id', $v['id'])->update($update);
  209. $user = UserMoney::where('address', $v['to'])->where('money_type', $v['symbol'])->value('uid');
  210. if ($user) {
  211. UserMoney::incomeMoney($user, $v['symbol'], $v['amount'], 'recharge', '用户充值', '用户充值' . $v['amount'] . $v['symbol'], $v['id']);
  212. }
  213. } else {
  214. $update['state'] = 2;
  215. WalletLog::where('id', $v['id'])->update($update);
  216. }
  217. }
  218. }
  219. break;
  220. default:
  221. break;
  222. }
  223. }
  224. }
  225. BaseModel::commitTrans();
  226. return true;
  227. } catch (\Exception $e) {
  228. BaseModel::rollbackTrans();
  229. Log::error('AutoCheckTransferFail:' . $e->getMessage());
  230. return false;
  231. }
  232. }
  233. /**
  234. * 自动归集
  235. * @return bool
  236. * @throws DataNotFoundException
  237. * @throws DbException
  238. * @throws ModelNotFoundException
  239. */
  240. public function autoSummary(): bool
  241. {
  242. $money_types = sys_data('money_type');
  243. // var_dump($money_types);
  244. $res = true;
  245. foreach ($money_types as $v) {
  246. if ($v['charge']) {
  247. //TODO 接入链上充值
  248. //有交易记录的地址
  249. $addresses = UserMoney::where('max_timestamp', '>', 0)->select()->toArray();
  250. foreach ($addresses as $vv) {
  251. // var_dump($vv);
  252. $res = $res && self::summary($vv, $v['summary_address'], new Address($v['gas_address'], $v['gas_key']));
  253. }
  254. }
  255. }
  256. return $res;
  257. }
  258. //TODO auto - end
  259. //TODO USDT
  260. /**
  261. * USDT 创建地址
  262. * @return array
  263. */
  264. public static function USDTCreateAddress(): array
  265. {
  266. try {
  267. $uri = 'https://api.trongrid.io';
  268. $api = new Api(new Client(['base_uri' => $uri]));
  269. $config = [
  270. 'contract_address' => 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',// USDT TRC20
  271. 'decimals' => 6,
  272. ];
  273. $trxWallet = new TRC20($api, $config);
  274. $address = $trxWallet->generateAddress();
  275. return [
  276. 'privateKey' => $address->privateKey,
  277. 'address' => $address->address,
  278. 'hexAddress' => $address->hexAddress
  279. ];
  280. } catch (\Exception $e) {
  281. return [
  282. 'privateKey' => '',
  283. 'address' => '',
  284. 'hexAddress' => ''
  285. ];
  286. }
  287. }
  288. /**
  289. * USDT 余额
  290. * @param $address
  291. * @return float
  292. */
  293. public static function USDTBalance($address): float
  294. {
  295. try {
  296. $uri = 'https://api.trongrid.io';
  297. $api = new Api(new Client(['base_uri' => $uri]));
  298. $config = [
  299. 'contract_address' => 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',// USDT TRC20
  300. 'decimals' => 6,
  301. ];
  302. $trxWallet = new TRC20($api, $config);
  303. $balance = $trxWallet->balance(new Address($address));
  304. return (float)$balance;
  305. } catch (\Exception $e) {
  306. return 0;
  307. }
  308. }
  309. /**
  310. * USDT 交易
  311. * @param $from
  312. * @param $to
  313. * @param $amount
  314. * @return array
  315. */
  316. public static function USDTTransfer($from, $to, $amount): array
  317. {
  318. try {
  319. $uri = 'https://api.trongrid.io';
  320. $api = new Api(new Client(['base_uri' => $uri]));
  321. $config = [
  322. 'contract_address' => 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',// USDT TRC20
  323. 'decimals' => 6,
  324. ];
  325. $trxWallet = new TRC20($api, $config);
  326. $transfer = $trxWallet->transfer($from, $to, $amount);
  327. return ['msg' => 'success', 'data' => $transfer, 'status' => true];
  328. } catch (\Exception $e) {
  329. return ['msg' => $e->getMessage(), 'status' => false, 'data' => $e->getTrace()];
  330. }
  331. }
  332. /**
  333. * USDT 获取交易记录
  334. * @param $address
  335. * @param $start_time
  336. * @return array|mixed
  337. */
  338. public static function USDTCheckTransfer($address, $start_time)
  339. {
  340. try {
  341. $uri = "https://api.trongrid.io/v1/accounts/{$address}/transactions/trc20";
  342. $contract_address = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';// USDT TRC20
  343. return json_decode(do_request($uri, [
  344. 'min_timestamp' => $start_time,
  345. 'limit' => 200,
  346. 'contract_address' => $contract_address,
  347. 'order_by' => 'block_timestamp,asc'
  348. ], null, false), true);
  349. } catch (\Exception $e) {
  350. return ['msg' => $e->getMessage(), 'status' => false, 'data' => $e->getTrace()];
  351. }
  352. }
  353. /**
  354. * USDT 确认交易记录
  355. * @param $txID
  356. * @return array
  357. */
  358. public static function USDTGetTransfer($txID)
  359. {
  360. try {
  361. $uri = 'https://api.trongrid.io';
  362. $api = new Api(new Client(['base_uri' => $uri]));
  363. $config = [
  364. 'contract_address' => 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',// USDT TRC20
  365. 'decimals' => 6,
  366. ];
  367. $trxWallet = new TRC20($api, $config);
  368. $transfer = $trxWallet->transactionReceipt($txID);
  369. return ['msg' => 'success', 'data' => $transfer, 'status' => true];
  370. } catch (\Exception $e) {
  371. return ['msg' => $e->getMessage(), 'status' => false, 'data' => $e->getTrace()];
  372. }
  373. }
  374. /**
  375. * USDT 归集
  376. * @param $money_info
  377. * @param $summary_address
  378. * @param $gas_address
  379. * @return bool
  380. * @throws TronErrorException
  381. */
  382. public static function USDTSummary($money_info, $summary_address, $gas_address): bool
  383. {
  384. $uri = 'https://api.trongrid.io';
  385. $api = new Api(new Client(['base_uri' => $uri]));
  386. $config = [
  387. 'contract_address' => 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',// USDT TRC20
  388. 'decimals' => 6,
  389. ];
  390. $trxWallet = new TRC20($api, $config);
  391. $address = new Address($money_info['address'], $money_info['privateKey'], $money_info['hexAddress']);
  392. $balance = $trxWallet->balance($address);
  393. //var_dump($balance);
  394. if ($balance > 0) {
  395. $trx = new TRX($api);
  396. $trx_balance = $trx->balance($address);
  397. //var_dump($trx_balance);
  398. if ($trx_balance < sys_config('trx_gas', 10)) {
  399. $trade_trx = ceil(10 - $trx_balance);
  400. //执行手续费转账
  401. $gas_trx_balance = $trx->balance($gas_address);
  402. if ($gas_trx_balance < $trade_trx + 2) {
  403. Log::error('USDT手续费账户余额不足');
  404. return false;
  405. }
  406. try {
  407. $res = $trx->transfer($gas_address, $address, $trade_trx);
  408. // var_dump($res);
  409. if (isset($res->txID)) {
  410. Log::error('转账TRX交易哈希:' . $res->txID);
  411. return true;
  412. } else {
  413. Log::error('转账TRX失败');
  414. return false;
  415. }
  416. } catch (\Exception $e) {
  417. Log::error('转账TRX失败' . $e->getMessage());
  418. return false;
  419. }
  420. } else {
  421. //执行转账
  422. try {
  423. $res = self::USDTTransfer($address, new Address($summary_address), $balance);
  424. // var_dump($res);
  425. if ($res['status']) {
  426. Log::error('转账交易哈希:' . $res['data']->txID);
  427. return true;
  428. } else {
  429. Log::error('转账失败' . $res['msg']);
  430. return false;
  431. }
  432. } catch (\Exception $e) {
  433. Log::error('转账失败' . $e->getMessage());
  434. return false;
  435. }
  436. }
  437. }
  438. return true;
  439. }
  440. //TODO USDT - end
  441. //TODO LALA
  442. /**
  443. * LALA 创建地址
  444. * @return array
  445. */
  446. public static function LALACreateAddress(): array
  447. {
  448. try {
  449. $uri = 'https://api.trongrid.io';
  450. $api = new Api(new Client(['base_uri' => $uri]));
  451. $config = [
  452. 'contract_address' => 'TLuwWZ8MkB6FFJDLYc19u7d4tFq2GV3rPL',// LALA TRC20
  453. 'decimals' => 8,
  454. ];
  455. $trxWallet = new TRC20($api, $config);
  456. $address = $trxWallet->generateAddress();
  457. return [
  458. 'privateKey' => $address->privateKey,
  459. 'address' => $address->address,
  460. 'hexAddress' => $address->hexAddress
  461. ];
  462. } catch (\Exception $e) {
  463. return [
  464. 'privateKey' => '',
  465. 'address' => '',
  466. 'hexAddress' => ''
  467. ];
  468. }
  469. }
  470. /**
  471. * USDT 余额
  472. * @param $address
  473. * @return float
  474. */
  475. public static function LALABalance($address): float
  476. {
  477. try {
  478. $uri = 'https://api.trongrid.io';
  479. $api = new Api(new Client(['base_uri' => $uri]));
  480. $config = [
  481. 'contract_address' => 'TLuwWZ8MkB6FFJDLYc19u7d4tFq2GV3rPL',// USDT TRC20
  482. 'decimals' => 8,
  483. ];
  484. $trxWallet = new TRC20($api, $config);
  485. $balance = $trxWallet->balance(new Address($address));
  486. return (float)$balance;
  487. } catch (\Exception $e) {
  488. return 0;
  489. }
  490. }
  491. /**
  492. * LALA 交易
  493. * @param $from
  494. * @param $to
  495. * @param $amount
  496. * @return array
  497. */
  498. public static function LALATransfer($from, $to, $amount): array
  499. {
  500. try {
  501. $uri = 'https://api.trongrid.io';
  502. $api = new Api(new Client(['base_uri' => $uri]));
  503. $config = [
  504. 'contract_address' => 'TLuwWZ8MkB6FFJDLYc19u7d4tFq2GV3rPL',// LALA TRC20
  505. 'decimals' => 8,
  506. ];
  507. $trxWallet = new TRC20($api, $config);
  508. $transfer = $trxWallet->transfer($from, $to, $amount);
  509. return ['msg' => 'success', 'data' => $transfer, 'status' => true];
  510. } catch (\Exception $e) {
  511. return ['msg' => $e->getMessage(), 'status' => false, 'data' => $e->getTrace()];
  512. }
  513. }
  514. /**
  515. * LALA 获取交易记录
  516. * @param $address
  517. * @param $start_time
  518. * @return array
  519. */
  520. public static function LALACheckTransfer($address, $start_time)
  521. {
  522. try {
  523. $uri = "https://api.trongrid.io/v1/accounts/{$address}/transactions/trc20";
  524. $contract_address = 'TLuwWZ8MkB6FFJDLYc19u7d4tFq2GV3rPL';// LALA TRC20
  525. return json_decode(do_request($uri, [
  526. 'min_timestamp' => $start_time,
  527. 'limit' => 200,
  528. 'contract_address' => $contract_address,
  529. 'order_by' => 'block_timestamp,asc'
  530. ], null, false), true);
  531. } catch (\Exception $e) {
  532. return ['msg' => $e->getMessage(), 'status' => false, 'data' => $e->getTrace()];
  533. }
  534. }
  535. /**
  536. * LALA 确认交易
  537. * @param $txID
  538. * @return array
  539. */
  540. public static function LALAGetTransfer($txID)
  541. {
  542. try {
  543. $uri = 'https://api.trongrid.io';
  544. $api = new Api(new Client(['base_uri' => $uri]));
  545. $config = [
  546. 'contract_address' => 'TLuwWZ8MkB6FFJDLYc19u7d4tFq2GV3rPL',// LALA TRC20
  547. 'decimals' => 8,
  548. ];
  549. $trxWallet = new TRC20($api, $config);
  550. $transfer = $trxWallet->transactionReceipt($txID);
  551. return ['msg' => 'success', 'data' => $transfer, 'status' => true];
  552. } catch (\Exception $e) {
  553. return ['msg' => $e->getMessage(), 'status' => false, 'data' => $e->getTrace()];
  554. }
  555. }
  556. /**
  557. * LALA 归集
  558. * @param $money_info
  559. * @param $summary_address
  560. * @param $gas_address
  561. * @return bool
  562. * @throws TronErrorException
  563. */
  564. public static function LALASummary($money_info, $summary_address, $gas_address): bool
  565. {
  566. $uri = 'https://api.trongrid.io';
  567. $api = new Api(new Client(['base_uri' => $uri]));
  568. $config = [
  569. 'contract_address' => 'TLuwWZ8MkB6FFJDLYc19u7d4tFq2GV3rPL',// LALA TRC20
  570. 'decimals' => 8,
  571. ];
  572. $trxWallet = new TRC20($api, $config);
  573. $address = new Address($money_info['address'], $money_info['privateKey'], $money_info['hexAddress']);
  574. $balance = $trxWallet->balance($address);
  575. //var_dump($balance);
  576. if ($balance > 0) {
  577. $trx = new TRX($api);
  578. $trx_balance = $trx->balance($address);
  579. //var_dump($trx_balance);
  580. if ($trx_balance < sys_config('trx_gas', 10)) {
  581. $trade_trx = ceil(10 - $trx_balance);
  582. //执行手续费转账
  583. $gas_trx_balance = $trx->balance($gas_address);
  584. if ($gas_trx_balance < $trade_trx + 2) {
  585. Log::error('LALA手续费账户余额不足');
  586. return false;
  587. }
  588. try {
  589. $res = $trx->transfer($gas_address, $address, $trade_trx);
  590. // var_dump($res);
  591. if (isset($res->txID)) {
  592. Log::error('转账TRX交易哈希:' . $res->txID);
  593. return true;
  594. } else {
  595. Log::error('转账TRX失败');
  596. return false;
  597. }
  598. } catch (\Exception $e) {
  599. Log::error('转账TRX失败' . $e->getMessage());
  600. return false;
  601. }
  602. } else {
  603. //执行转账
  604. try {
  605. $res = self::LALATransfer($address, new Address($summary_address), $balance);
  606. // var_dump($res);
  607. if ($res['status']) {
  608. Log::error('转账交易哈希:' . $res['data']->txID);
  609. return true;
  610. } else {
  611. Log::error('转账失败' . $res['msg']);
  612. return false;
  613. }
  614. } catch (\Exception $e) {
  615. Log::error('转账失败' . $e->getMessage());
  616. return false;
  617. }
  618. }
  619. }
  620. return true;
  621. }
  622. //TODO LALA - end
  623. }