UsdtWalletService.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2017~2021 LARAVEL研发中心
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://www.laravel.cn
  8. // +----------------------------------------------------------------------
  9. // | Author: laravel开发员 <laravel.qq.com>
  10. // +----------------------------------------------------------------------
  11. namespace App\Services;
  12. use App\Models\CoinLogModel;
  13. use App\Models\MemberModel;
  14. use App\Services\Api\MemberService;
  15. use App\Services\Common\CoinLogService;
  16. use BitWasp\Bitcoin\Address\AddressCreator;
  17. use BitWasp\Bitcoin\Address\PayToPubKeyHashAddress;
  18. use BitWasp\Bitcoin\Bitcoin;
  19. use BitWasp\Bitcoin\Crypto\Random\Random;
  20. use BitWasp\Bitcoin\Key\Factory\HierarchicalKeyFactory;
  21. use BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory;
  22. use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39Mnemonic;
  23. use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39SeedGenerator;
  24. use BitWasp\Bitcoin\Mnemonic\MnemonicFactory;
  25. use BitWasp\Bitcoin\Script\WitnessProgram;
  26. use GuzzleHttp\Client;
  27. use IEXBase\TronAPI\Tron;
  28. use Tron\Api;
  29. use Tron\TRC20;
  30. use Tron\TRX;
  31. use Web3\Web3;
  32. use Web3p\EthereumUtil\Util;
  33. /**
  34. * USDT链管理-服务类
  35. * Class UsdtWalletService
  36. * @package App\Services
  37. */
  38. class UsdtWalletService extends BaseService
  39. {
  40. protected $apiUrl = '';
  41. protected $config = [];
  42. protected $apiUrls = [
  43. 'usdt_trx2_transfer_log' => '/v1/accounts/%s/transactions/trc20?limit=%s&only_to=%s&only_from=%s&only_confirmed=true&contract_address=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'
  44. ];
  45. /**
  46. * 构造函数
  47. * UsdtWalletService constructor.
  48. */
  49. public function __construct()
  50. {
  51. $this->memberModel = new MemberModel();
  52. $this->coinModel = new CoinLogModel();
  53. $this->config = ConfigService::make()->getConfigOptionByGroup(4);
  54. $this->apiUrl = isset($this->config['usdt_api_url']) ? $this->config['usdt_api_url'] : '';
  55. if (empty($this->config) || empty($this->apiUrl)) {
  56. return false;
  57. }
  58. }
  59. /**
  60. * 静态入口
  61. * @return UsdtWalletService|null
  62. */
  63. public static function make()
  64. {
  65. return parent::make(); // TODO: Change the autogenerated stub
  66. }
  67. /**
  68. * 获取TRC2.0钱包地址
  69. * @throws \Tron\Exceptions\TronErrorException
  70. */
  71. public function getTrxAddress()
  72. {
  73. $api = new Api(new Client(['base_uri' => $this->config['tron_api_url']]));
  74. $trxWallet = new TRX($api);
  75. $addressData = $trxWallet->generateAddress();
  76. $addressData = (array)$addressData;
  77. return ['wif' => $addressData['privateKey'], 'hexAddress' => $addressData['hexAddress'], 'address' => $addressData['address']];
  78. }
  79. /**
  80. * trx 转账
  81. * @param $from 转账账户
  82. * @param $to 进账账户
  83. * @param $amount 转账金额
  84. * @throws \Tron\Exceptions\TransactionException
  85. * @throws \Tron\Exceptions\TronErrorException
  86. */
  87. public function trxTransfer($from, $to, $amount)
  88. {
  89. if ($amount <= 0) {
  90. $this->error = '2205';
  91. return false;
  92. }
  93. if (empty($this->config['tron_api_url'])) {
  94. $this->error = '2206';
  95. return false;
  96. }
  97. $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']];
  98. $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'],'headers'=> $headers]));
  99. $trxWallet = new TRX($api);
  100. // 获取钱包参数
  101. try {
  102. $fromData = MemberService::make()->getWallet($from, 'trc');
  103. $privateKey = isset($fromData['trc_wif']) ? $fromData['trc_wif'] : '';
  104. $hexAddress = isset($fromData['trc_hexaddress']) ? $fromData['trc_hexaddress'] : '';
  105. if (empty($privateKey) || empty($hexAddress)) {
  106. $this->error = '2203';
  107. return false;
  108. }
  109. $tron = new Tron();
  110. $tron->setAddress($to);
  111. $toAddress = $tron->getAddress();
  112. $from = new \Tron\Address($from, $privateKey, $hexAddress);
  113. $to = new \Tron\Address($toAddress['base58'], '', $toAddress['hex']);
  114. $result = $trxWallet->transfer($from, $to, $amount);
  115. return $result;
  116. } catch (\Exception $exception) {
  117. $message = $exception->getMessage();
  118. $this->error = $message;
  119. return false;
  120. }
  121. }
  122. /**
  123. * usdt-trc2.0 转账
  124. * @param $from 转账账户
  125. * @param $to 进账账户
  126. * @param $amount 转账金额
  127. * @throws \Tron\Exceptions\TransactionException
  128. * @throws \Tron\Exceptions\TronErrorException
  129. */
  130. public function usdtTrcTransfer($from, $to, $amount)
  131. {
  132. if ($amount <= 0) {
  133. $this->error = '2205';
  134. return false;
  135. }
  136. if (empty($this->config['tron_api_url'])) {
  137. $this->error = '2206';
  138. return false;
  139. }
  140. $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']];
  141. $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'],'headers'=> $headers]));
  142. $trxWallet = new TRC20($api, ['contract_address' => $this->config['tron_contract_address'], 'decimals' => 6]);
  143. // 获取钱包参数
  144. try {
  145. $fromData = MemberService::make()->getWallet($from, 'trc');
  146. $privateKey = isset($fromData['trc_wif']) ? $fromData['trc_wif'] : '';
  147. $hexAddress = isset($fromData['trc_hexaddress']) ? $fromData['trc_hexaddress'] : '';
  148. if (empty($privateKey) || empty($hexAddress)) {
  149. $this->error = '2203';
  150. return false;
  151. }
  152. $tron = new Tron();
  153. $tron->setAddress($to);
  154. $toAddress = $tron->getAddress();
  155. $from = new \Tron\Address($from, $privateKey, $hexAddress);
  156. $to = new \Tron\Address($toAddress['base58'], '', $toAddress['hex']);
  157. $result = $trxWallet->transfer($from, $to, $amount);
  158. return $result;
  159. } catch (\Exception $exception) {
  160. $message = $exception->getMessage();
  161. $this->error = $message;
  162. return false;
  163. }
  164. }
  165. /**
  166. * 监听USDT-TRC2.0转账记录并进账
  167. * @param $userId 用户ID
  168. * @param $address 用户钱包地址
  169. * @param int $coinType 币种:1-usdt
  170. * @param int $limit 转账记录数,最新的
  171. * @return array|false
  172. */
  173. public function getTrc20TransferLog($userId, $address, $coinType= 1, $limit = 50)
  174. {
  175. if($userId<=0 || empty($address)){
  176. $this->error = '1013';
  177. return false;
  178. }
  179. $url = sprintf($this->apiUrls['usdt_trx2_transfer_log'], $address, $limit, 'true','false');
  180. $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']];
  181. $result = curl_get($this->config['tron_api_url'] . $url, [], $headers, 10);
  182. $result = $result? json_decode($result, true) : [];
  183. $datas = isset($result['data']) ? $result['data'] : [];
  184. $status = isset($result['success']) ? $result['success'] : '';
  185. if ($status != true || empty($datas)) {
  186. $this->error = '2207';
  187. return false;
  188. }
  189. $logs = [];
  190. foreach ($datas as $v) {
  191. $amount = isset($v['value'])? intval($v['value']) : 0;
  192. $amount = moneyFormat($amount/1000000, 6);
  193. $time = isset($v['block_timestamp'])? intval($v['block_timestamp']) : 0;
  194. $txid = isset($v['transaction_id'])? $v['transaction_id'] : '';
  195. if(!CoinLogService::make()->checkExists('txid', $txid) && $time> time() - 6*3600){
  196. $balance = $this->memberModel->where(['id'=> $userId])->value('usdt_num');
  197. $log = [
  198. 'user_id'=> $userId,
  199. 'change_type'=> 1,
  200. 'coin_type'=> $coinType,
  201. 'contact_type'=> 1,
  202. 'order_no'=> get_order_num('OT'),
  203. 'from_address'=> isset($v['from'])? $v['from'] : '',
  204. 'to_address'=> isset($v['to'])? $v['to'] : '',
  205. 'txid'=> $txid,
  206. 'num'=> $amount,
  207. 'balance'=> $balance,
  208. 'create_time'=> intval($time/1000),
  209. 'status'=> 1,
  210. 'mark'=> 1,
  211. ];
  212. if($this->memberModel->where(['id'=> $userId])->increment('usdt_num', $amount)){
  213. $logs[] = $log;
  214. $this->coinModel->insert($log);
  215. }
  216. }
  217. }
  218. return $logs;
  219. }
  220. /**
  221. * 监听USDT-TRC2.0充值记录并进账
  222. * @param $userId 用户ID
  223. * @param $address 用户钱包地址
  224. * @param int $coinType 币种:1-usdt
  225. * @param int $limit 转账记录数,最新的
  226. * @return array|false
  227. */
  228. public function getTrc20RechargeLog($userId, $address, $coinType= 1, $limit = 50)
  229. {
  230. if($userId<=0 || empty($address)){
  231. $this->error = '1013';
  232. return false;
  233. }
  234. $url = sprintf($this->apiUrls['usdt_trx2_transfer_log'], $address, $limit, 'false','true');
  235. $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']];
  236. $result = curl_get($this->config['tron_api_url'] . $url, [], $headers, 10);
  237. $result = $result? json_decode($result, true) : [];
  238. $datas = isset($result['data']) ? $result['data'] : [];
  239. $status = isset($result['success']) ? $result['success'] : '';
  240. if ($status != true || empty($datas)) {
  241. $this->error = '2207';
  242. return false;
  243. }
  244. $logs = [];
  245. foreach ($datas as $v) {
  246. $amount = isset($v['value'])? intval($v['value']) : 0;
  247. $amount = moneyFormat($amount/1000000, 6);
  248. $time = isset($v['block_timestamp'])? intval($v['block_timestamp']) : 0;
  249. $txid = isset($v['transaction_id'])? $v['transaction_id'] : '';
  250. if(!CoinLogService::make()->checkExists('txid', $txid) && $time> time() - 6*3600){
  251. $balance = $this->memberModel->where(['id'=> $userId])->value('usdt_num');
  252. $log = [
  253. 'user_id'=> $userId,
  254. 'change_type'=> 2,
  255. 'coin_type'=> $coinType,
  256. 'contact_type'=> 1,
  257. 'order_no'=> get_order_num('OT'),
  258. 'from_address'=> isset($v['from'])? $v['from'] : '',
  259. 'to_address'=> isset($v['to'])? $v['to'] : '',
  260. 'txid'=> $txid,
  261. 'num'=> $amount,
  262. 'balance'=> $balance,
  263. 'create_time'=> intval($time/1000),
  264. 'status'=> 1,
  265. 'mark'=> 1,
  266. ];
  267. if($this->memberModel->where(['id'=> $userId])->decrement('usdt_num', $amount)){
  268. $logs[] = $log;
  269. $this->coinModel->insert($log);
  270. }
  271. }
  272. }
  273. return $logs;
  274. }
  275. /**
  276. * @param $address
  277. * @return false|float|string
  278. */
  279. public function getUsdtByTrc20($address)
  280. {
  281. $cacheKey = "caches:wallet:balance:{$address}";
  282. if(RedisService::get($cacheKey)){
  283. return false;
  284. }
  285. if (empty($address)) {
  286. $this->error = '1018';
  287. return false;
  288. }
  289. if (empty($this->config['tron_api_url'])) {
  290. $this->error = '2206';
  291. return false;
  292. }
  293. try {
  294. $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']];
  295. $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'],'headers'=> $headers]));
  296. $trxWallet = new TRC20($api, ['contract_address' => $this->config['tron_contract_address'], 'decimals' => 6]);
  297. $tron = new Tron();
  298. $tron->setAddress($address);
  299. $address = $tron->getAddress();
  300. $address = new \Tron\Address($address['base58'], '', $address['hex']);
  301. $result = $trxWallet->balance($address);
  302. return $result? floatval($result) : '0.00';
  303. } catch (\Exception $exception){
  304. $this->error = $exception->getMessage();
  305. return false;
  306. }
  307. }
  308. /**
  309. * 获取ERC2.0钱包地址
  310. * @param string $type
  311. * @throws \BitWasp\Bitcoin\Exceptions\RandomBytesFailure
  312. */
  313. public function getErcAddress()
  314. {
  315. $random = new Random();
  316. $network = Bitcoin::getNetwork();
  317. $privateKeyFactory = new PrivateKeyFactory();
  318. $privateKey = $privateKeyFactory->generateCompressed($random);
  319. $publicKey = $privateKey->getPublicKey();
  320. // p2pkh 格式的地址
  321. $addressService = new PayToPubKeyHashAddress($publicKey->getPubKeyHash());
  322. // 将生成的钱包保存到数据库中
  323. $wif = $privateKey->toWif($network);
  324. $address = $addressService->getAddress();
  325. return ['wif' => $wif, 'hexAddress' => $this->getHash16Address($address), 'address' => $address];
  326. }
  327. /**
  328. * 获取ERC钱包地址
  329. * @throws \BitWasp\Bitcoin\Exceptions\RandomBytesFailure
  330. */
  331. public function getWalletAddress()
  332. {
  333. $math = Bitcoin::getMath();
  334. $network = Bitcoin::getNetwork();
  335. $random = new Random();
  336. // 生成随机数(initial entropy)
  337. $entropy = $random->bytes(Bip39Mnemonic::MIN_ENTROPY_BYTE_LEN);
  338. $bip39 = MnemonicFactory::bip39();
  339. // 通过随机数生成助记词
  340. $mnemonic = $bip39->entropyToMnemonic($entropy);
  341. echo "mnemonic: " . $mnemonic . PHP_EOL . PHP_EOL;// 助记词
  342. $seedGenerator = new Bip39SeedGenerator();
  343. // 通过助记词生成种子,传入可选加密串
  344. $seed = $seedGenerator->getSeed($mnemonic, 'otc');
  345. echo "seed: " . $seed->getHex() . PHP_EOL;
  346. $hdFactory = new HierarchicalKeyFactory();
  347. $master = $hdFactory->fromEntropy($seed);
  348. $util = new Util();
  349. // 设置路径account
  350. $hardened = $master->derivePath("44'/60'/0'/0/0");
  351. echo " - m/44'/60'/0'/0/0 " . PHP_EOL;
  352. echo " public key: " . $hardened->getPublicKey()->getHex() . PHP_EOL;
  353. echo " private key: " . $hardened->getPrivateKey()->getHex() . PHP_EOL;// 可以导入到imtoken使用的私钥
  354. echo " address: " . $util->publicKeyToAddress($util->privateKeyToPublicKey($hardened->getPrivateKey()->getHex())) . PHP_EOL;// 私钥导入imtoken后一样的地址
  355. }
  356. public function getWebAddress($label = '1')
  357. {
  358. $web3 = new Web3("https://cloudflare-eth.com");
  359. $web3->eth->personal->newAccount($label, function ($err, $account) use (&$newAccount) {
  360. if ($err !== null) {
  361. echo 'Error: ' . $err->getMessage();
  362. return;
  363. }
  364. $newAccount = $account;
  365. echo 'New account: ' . $account . PHP_EOL;
  366. });
  367. var_dump($newAccount);
  368. }
  369. /**
  370. * 获取HASH钱包地址
  371. * @param $address 钱包地址
  372. * @return \BitWasp\Buffertools\BufferInterface
  373. * @throws \BitWasp\Bitcoin\Exceptions\UnrecognizedAddressException
  374. */
  375. public function getHash16Address($address)
  376. {
  377. $data = WitnessProgram::v0((new AddressCreator())->fromString($address)->getHash());
  378. $buffer = $data->getProgram()->getHex();
  379. return $buffer ? '0x' . $buffer : '';
  380. }
  381. /**
  382. * 获取HASH钱包地址
  383. * @param $address 钱包地址
  384. * @return \BitWasp\Buffertools\BufferInterface
  385. * @throws \BitWasp\Bitcoin\Exceptions\UnrecognizedAddressException
  386. */
  387. public function getHexAddress($address)
  388. {
  389. $data = WitnessProgram::v0((new AddressCreator())->fromString($address)->getHash());
  390. $buffer = $data->getProgram()->getHex();
  391. return $buffer ? '0x' . $buffer : '';
  392. }
  393. /**
  394. * 创建交易参数
  395. * @param $payWif
  396. * @param $address
  397. * @param $amount
  398. * @param string $coin
  399. * @throws \BitWasp\Bitcoin\Exceptions\Base58ChecksumFailure
  400. * @throws \BitWasp\Bitcoin\Exceptions\InvalidPrivateKey
  401. * @throws \BitWasp\Bitcoin\Exceptions\UnrecognizedAddressException
  402. * @throws \BitWasp\Bitcoin\Exceptions\WitnessScriptException
  403. * api: https://services.tokenview.com/vipapi/onchainwallet/{币种简称小写}?apikey={apikey}
  404. */
  405. public function createTrade($payAddress, $address, $amount, $coin = 'etc')
  406. {
  407. $data = [
  408. 'owner_address' => $payAddress,
  409. 'to_address' => $address,
  410. 'amount' => $amount,
  411. 'method' => 'createtransaction',
  412. 'visible' => false,
  413. ];
  414. $this->apiUrl = $this->apiUrl . "/onchainwallet/{$coin}?apikey=" . $this->config['usdt_apikey'];
  415. var_dump($data);
  416. var_dump($this->apiUrl);
  417. $result = curl_api($this->apiUrl, $data, ["Content-Type: application/json"]);
  418. var_dump($result);
  419. }
  420. }