// +---------------------------------------------------------------------- namespace App\Services; use App\Models\CoinLogModel; use App\Models\MemberModel; use App\Services\Api\MemberService; use App\Services\Common\CoinLogService; use BitWasp\Bitcoin\Address\AddressCreator; use BitWasp\Bitcoin\Address\PayToPubKeyHashAddress; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\Crypto\Random\Random; use BitWasp\Bitcoin\Key\Factory\HierarchicalKeyFactory; use BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory; use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39Mnemonic; use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39SeedGenerator; use BitWasp\Bitcoin\Mnemonic\MnemonicFactory; use BitWasp\Bitcoin\Script\WitnessProgram; use GuzzleHttp\Client; use IEXBase\TronAPI\Tron; use Tron\Api; use Tron\TRC20; use Tron\TRX; use Web3\Web3; use Web3p\EthereumUtil\Util; /** * USDT链管理-服务类 * Class UsdtWalletService * @package App\Services */ class UsdtWalletService extends BaseService { protected $apiUrl = ''; protected $config = []; protected $apiUrls = [ 'usdt_trx2_transfer_log' => '/v1/accounts/%s/transactions/trc20?limit=%s&only_to=%s&only_from=%s&only_confirmed=true&contract_address=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t' ]; /** * 构造函数 * UsdtWalletService constructor. */ public function __construct() { $this->memberModel = new MemberModel(); $this->coinModel = new CoinLogModel(); $this->config = ConfigService::make()->getConfigOptionByGroup(4); $this->apiUrl = isset($this->config['usdt_api_url']) ? $this->config['usdt_api_url'] : ''; if (empty($this->config) || empty($this->apiUrl)) { return false; } } /** * 静态入口 * @return UsdtWalletService|null */ public static function make() { return parent::make(); // TODO: Change the autogenerated stub } /** * 获取TRC2.0钱包地址 * @throws \Tron\Exceptions\TronErrorException */ public function getTrxAddress() { $api = new Api(new Client(['base_uri' => $this->config['tron_api_url']])); $trxWallet = new TRX($api); $addressData = $trxWallet->generateAddress(); $addressData = (array)$addressData; return ['wif' => $addressData['privateKey'], 'hexAddress' => $addressData['hexAddress'], 'address' => $addressData['address']]; } /** * trx 转账 * @param $from 转账账户 * @param $to 进账账户 * @param $amount 转账金额 * @throws \Tron\Exceptions\TransactionException * @throws \Tron\Exceptions\TronErrorException */ public function trxTransfer($from, $to, $amount) { if ($amount <= 0) { $this->error = '2205'; return false; } if (empty($this->config['tron_api_url'])) { $this->error = '2206'; return false; } $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']]; $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'],'headers'=> $headers])); $trxWallet = new TRX($api); // 获取钱包参数 try { $fromData = MemberService::make()->getWallet($from, 'trc'); $privateKey = isset($fromData['trc_wif']) ? $fromData['trc_wif'] : ''; $hexAddress = isset($fromData['trc_hexaddress']) ? $fromData['trc_hexaddress'] : ''; if (empty($privateKey) || empty($hexAddress)) { $this->error = '2203'; return false; } $tron = new Tron(); $tron->setAddress($to); $toAddress = $tron->getAddress(); $from = new \Tron\Address($from, $privateKey, $hexAddress); $to = new \Tron\Address($toAddress['base58'], '', $toAddress['hex']); $result = $trxWallet->transfer($from, $to, $amount); return $result; } catch (\Exception $exception) { $message = $exception->getMessage(); $this->error = $message; return false; } } /** * usdt-trc2.0 转账 * @param $from 转账账户 * @param $to 进账账户 * @param $amount 转账金额 * @throws \Tron\Exceptions\TransactionException * @throws \Tron\Exceptions\TronErrorException */ public function usdtTrcTransfer($from, $to, $amount) { if ($amount <= 0) { $this->error = '2205'; return false; } if (empty($this->config['tron_api_url'])) { $this->error = '2206'; return false; } $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']]; $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'],'headers'=> $headers])); $trxWallet = new TRC20($api, ['contract_address' => $this->config['tron_contract_address'], 'decimals' => 6]); // 获取钱包参数 try { $fromData = MemberService::make()->getWallet($from, 'trc'); $privateKey = isset($fromData['trc_wif']) ? $fromData['trc_wif'] : ''; $hexAddress = isset($fromData['trc_hexaddress']) ? $fromData['trc_hexaddress'] : ''; if (empty($privateKey) || empty($hexAddress)) { $this->error = '2203'; return false; } $tron = new Tron(); $tron->setAddress($to); $toAddress = $tron->getAddress(); $from = new \Tron\Address($from, $privateKey, $hexAddress); $to = new \Tron\Address($toAddress['base58'], '', $toAddress['hex']); $result = $trxWallet->transfer($from, $to, $amount); return $result; } catch (\Exception $exception) { $message = $exception->getMessage(); $this->error = $message; return false; } } /** * 监听USDT-TRC2.0转账记录并进账 * @param $userId 用户ID * @param $address 用户钱包地址 * @param int $coinType 币种:1-usdt * @param int $limit 转账记录数,最新的 * @return array|false */ public function getTrc20TransferLog($userId, $address, $coinType= 1, $limit = 50) { if($userId<=0 || empty($address)){ $this->error = '1013'; return false; } $url = sprintf($this->apiUrls['usdt_trx2_transfer_log'], $address, $limit, 'true','false'); $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']]; $result = curl_get($this->config['tron_api_url'] . $url, [], $headers, 10); $result = $result? json_decode($result, true) : []; $datas = isset($result['data']) ? $result['data'] : []; $status = isset($result['success']) ? $result['success'] : ''; if ($status != true || empty($datas)) { $this->error = '2207'; return false; } $logs = []; foreach ($datas as $v) { $amount = isset($v['value'])? intval($v['value']) : 0; $amount = moneyFormat($amount/1000000, 6); $time = isset($v['block_timestamp'])? intval($v['block_timestamp']) : 0; $txid = isset($v['transaction_id'])? $v['transaction_id'] : ''; if(!CoinLogService::make()->checkExists('txid', $txid) && $time> time() - 6*3600){ $balance = $this->memberModel->where(['id'=> $userId])->value('usdt_num'); $log = [ 'user_id'=> $userId, 'change_type'=> 1, 'coin_type'=> $coinType, 'contact_type'=> 1, 'order_no'=> get_order_num('OT'), 'from_address'=> isset($v['from'])? $v['from'] : '', 'to_address'=> isset($v['to'])? $v['to'] : '', 'txid'=> $txid, 'num'=> $amount, 'balance'=> $balance, 'create_time'=> intval($time/1000), 'status'=> 1, 'mark'=> 1, ]; if($this->memberModel->where(['id'=> $userId])->increment('usdt_num', $amount)){ $logs[] = $log; $this->coinModel->insert($log); } } } return $logs; } /** * 监听USDT-TRC2.0充值记录并进账 * @param $userId 用户ID * @param $address 用户钱包地址 * @param int $coinType 币种:1-usdt * @param int $limit 转账记录数,最新的 * @return array|false */ public function getTrc20RechargeLog($userId, $address, $coinType= 1, $limit = 50) { if($userId<=0 || empty($address)){ $this->error = '1013'; return false; } $url = sprintf($this->apiUrls['usdt_trx2_transfer_log'], $address, $limit, 'false','true'); $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']]; $result = curl_get($this->config['tron_api_url'] . $url, [], $headers, 10); $result = $result? json_decode($result, true) : []; $datas = isset($result['data']) ? $result['data'] : []; $status = isset($result['success']) ? $result['success'] : ''; if ($status != true || empty($datas)) { $this->error = '2207'; return false; } $logs = []; foreach ($datas as $v) { $amount = isset($v['value'])? intval($v['value']) : 0; $amount = moneyFormat($amount/1000000, 6); $time = isset($v['block_timestamp'])? intval($v['block_timestamp']) : 0; $txid = isset($v['transaction_id'])? $v['transaction_id'] : ''; if(!CoinLogService::make()->checkExists('txid', $txid) && $time> time() - 6*3600){ $balance = $this->memberModel->where(['id'=> $userId])->value('usdt_num'); $log = [ 'user_id'=> $userId, 'change_type'=> 2, 'coin_type'=> $coinType, 'contact_type'=> 1, 'order_no'=> get_order_num('OT'), 'from_address'=> isset($v['from'])? $v['from'] : '', 'to_address'=> isset($v['to'])? $v['to'] : '', 'txid'=> $txid, 'num'=> $amount, 'balance'=> $balance, 'create_time'=> intval($time/1000), 'status'=> 1, 'mark'=> 1, ]; if($this->memberModel->where(['id'=> $userId])->decrement('usdt_num', $amount)){ $logs[] = $log; $this->coinModel->insert($log); } } } return $logs; } /** * @param $address * @return false|float|string */ public function getUsdtByTrc20($address) { $cacheKey = "caches:wallet:balance:{$address}"; if(RedisService::get($cacheKey)){ return false; } if (empty($address)) { $this->error = '1018'; return false; } if (empty($this->config['tron_api_url'])) { $this->error = '2206'; return false; } try { $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']]; $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'],'headers'=> $headers])); $trxWallet = new TRC20($api, ['contract_address' => $this->config['tron_contract_address'], 'decimals' => 6]); $tron = new Tron(); $tron->setAddress($address); $address = $tron->getAddress(); $address = new \Tron\Address($address['base58'], '', $address['hex']); $result = $trxWallet->balance($address); return $result? floatval($result) : '0.00'; } catch (\Exception $exception){ $this->error = $exception->getMessage(); return false; } } /** * 获取ERC2.0钱包地址 * @param string $type * @throws \BitWasp\Bitcoin\Exceptions\RandomBytesFailure */ public function getErcAddress() { $random = new Random(); $network = Bitcoin::getNetwork(); $privateKeyFactory = new PrivateKeyFactory(); $privateKey = $privateKeyFactory->generateCompressed($random); $publicKey = $privateKey->getPublicKey(); // p2pkh 格式的地址 $addressService = new PayToPubKeyHashAddress($publicKey->getPubKeyHash()); // 将生成的钱包保存到数据库中 $wif = $privateKey->toWif($network); $address = $addressService->getAddress(); return ['wif' => $wif, 'hexAddress' => $this->getHash16Address($address), 'address' => $address]; } /** * 获取ERC钱包地址 * @throws \BitWasp\Bitcoin\Exceptions\RandomBytesFailure */ public function getWalletAddress() { $math = Bitcoin::getMath(); $network = Bitcoin::getNetwork(); $random = new Random(); // 生成随机数(initial entropy) $entropy = $random->bytes(Bip39Mnemonic::MIN_ENTROPY_BYTE_LEN); $bip39 = MnemonicFactory::bip39(); // 通过随机数生成助记词 $mnemonic = $bip39->entropyToMnemonic($entropy); echo "mnemonic: " . $mnemonic . PHP_EOL . PHP_EOL;// 助记词 $seedGenerator = new Bip39SeedGenerator(); // 通过助记词生成种子,传入可选加密串 $seed = $seedGenerator->getSeed($mnemonic, 'otc'); echo "seed: " . $seed->getHex() . PHP_EOL; $hdFactory = new HierarchicalKeyFactory(); $master = $hdFactory->fromEntropy($seed); $util = new Util(); // 设置路径account $hardened = $master->derivePath("44'/60'/0'/0/0"); echo " - m/44'/60'/0'/0/0 " . PHP_EOL; echo " public key: " . $hardened->getPublicKey()->getHex() . PHP_EOL; echo " private key: " . $hardened->getPrivateKey()->getHex() . PHP_EOL;// 可以导入到imtoken使用的私钥 echo " address: " . $util->publicKeyToAddress($util->privateKeyToPublicKey($hardened->getPrivateKey()->getHex())) . PHP_EOL;// 私钥导入imtoken后一样的地址 } public function getWebAddress($label = '1') { $web3 = new Web3("https://cloudflare-eth.com"); $web3->eth->personal->newAccount($label, function ($err, $account) use (&$newAccount) { if ($err !== null) { echo 'Error: ' . $err->getMessage(); return; } $newAccount = $account; echo 'New account: ' . $account . PHP_EOL; }); var_dump($newAccount); } /** * 获取HASH钱包地址 * @param $address 钱包地址 * @return \BitWasp\Buffertools\BufferInterface * @throws \BitWasp\Bitcoin\Exceptions\UnrecognizedAddressException */ public function getHash16Address($address) { $data = WitnessProgram::v0((new AddressCreator())->fromString($address)->getHash()); $buffer = $data->getProgram()->getHex(); return $buffer ? '0x' . $buffer : ''; } /** * 获取HASH钱包地址 * @param $address 钱包地址 * @return \BitWasp\Buffertools\BufferInterface * @throws \BitWasp\Bitcoin\Exceptions\UnrecognizedAddressException */ public function getHexAddress($address) { $data = WitnessProgram::v0((new AddressCreator())->fromString($address)->getHash()); $buffer = $data->getProgram()->getHex(); return $buffer ? '0x' . $buffer : ''; } /** * 创建交易参数 * @param $payWif * @param $address * @param $amount * @param string $coin * @throws \BitWasp\Bitcoin\Exceptions\Base58ChecksumFailure * @throws \BitWasp\Bitcoin\Exceptions\InvalidPrivateKey * @throws \BitWasp\Bitcoin\Exceptions\UnrecognizedAddressException * @throws \BitWasp\Bitcoin\Exceptions\WitnessScriptException * api: https://services.tokenview.com/vipapi/onchainwallet/{币种简称小写}?apikey={apikey} */ public function createTrade($payAddress, $address, $amount, $coin = 'etc') { $data = [ 'owner_address' => $payAddress, 'to_address' => $address, 'amount' => $amount, 'method' => 'createtransaction', 'visible' => false, ]; $this->apiUrl = $this->apiUrl . "/onchainwallet/{$coin}?apikey=" . $this->config['usdt_apikey']; var_dump($data); var_dump($this->apiUrl); $result = curl_api($this->apiUrl, $data, ["Content-Type: application/json"]); var_dump($result); } }