|
@@ -4,6 +4,7 @@ namespace App\Helpers;
|
|
|
|
|
|
|
|
use Mdanter\Ecc\EccFactory;
|
|
use Mdanter\Ecc\EccFactory;
|
|
|
use Mdanter\Ecc\Random\RandomGeneratorFactory;
|
|
use Mdanter\Ecc\Random\RandomGeneratorFactory;
|
|
|
|
|
+use Illuminate\Support\Facades\Cache;
|
|
|
use Illuminate\Support\Facades\Crypt;
|
|
use Illuminate\Support\Facades\Crypt;
|
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Client;
|
|
|
use GuzzleHttp\Exception\GuzzleException;
|
|
use GuzzleHttp\Exception\GuzzleException;
|
|
@@ -27,6 +28,8 @@ class TronHelper
|
|
|
public static $nileUrl = 'https://nile.trongrid.io'; // 测试网
|
|
public static $nileUrl = 'https://nile.trongrid.io'; // 测试网
|
|
|
|
|
|
|
|
const CONFIRMED_NUMBER = 3; // 确认数
|
|
const CONFIRMED_NUMBER = 3; // 确认数
|
|
|
|
|
+ const GLOBAL_TRON_RATE_LIMIT_KEY = 'tron_request_global_rate_limit';
|
|
|
|
|
+ const GLOBAL_TRON_RATE_LIMIT_SECONDS = 1;
|
|
|
|
|
|
|
|
protected static $client;
|
|
protected static $client;
|
|
|
|
|
|
|
@@ -57,7 +60,7 @@ class TronHelper
|
|
|
'Content-Type' => 'application/json',
|
|
'Content-Type' => 'application/json',
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
- $apiKey = config('app.tron_pro_api_key', '');
|
|
|
|
|
|
|
+ $apiKey = self::getTronProApiKey();
|
|
|
if ($apiKey) {
|
|
if ($apiKey) {
|
|
|
$headers['TRON-PRO-API-KEY'] = $apiKey;
|
|
$headers['TRON-PRO-API-KEY'] = $apiKey;
|
|
|
}
|
|
}
|
|
@@ -65,6 +68,33 @@ class TronHelper
|
|
|
return $headers;
|
|
return $headers;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ public static function getTronProApiKey(): string
|
|
|
|
|
+ {
|
|
|
|
|
+ return trim((string) config('app.tron_pro_api_key', ''));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static function throttleTronRequest(int $seconds = self::GLOBAL_TRON_RATE_LIMIT_SECONDS, string $key = self::GLOBAL_TRON_RATE_LIMIT_KEY): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $store = self::getTronRateLimitStore();
|
|
|
|
|
+ $deadline = microtime(true) + max(3, $seconds + 2);
|
|
|
|
|
+
|
|
|
|
|
+ while (!$store->add($key, microtime(true), $seconds)) {
|
|
|
|
|
+ usleep(200000);
|
|
|
|
|
+ if (microtime(true) >= $deadline) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected static function getTronRateLimitStore()
|
|
|
|
|
+ {
|
|
|
|
|
+ try {
|
|
|
|
|
+ return Cache::store('redis');
|
|
|
|
|
+ } catch (\Throwable $e) {
|
|
|
|
|
+ return Cache::store(config('cache.default'));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* @description: 获取网络
|
|
* @description: 获取网络
|
|
|
* @return {*}
|
|
* @return {*}
|
|
@@ -114,6 +144,8 @@ class TronHelper
|
|
|
*/
|
|
*/
|
|
|
public static function transferUSDT($privateKey, $toAddress, $amount)
|
|
public static function transferUSDT($privateKey, $toAddress, $amount)
|
|
|
{
|
|
{
|
|
|
|
|
+ self::throttleTronRequest();
|
|
|
|
|
+
|
|
|
$nodeScript = base_path('node/index.js'); // Laravel根目录下的路径
|
|
$nodeScript = base_path('node/index.js'); // Laravel根目录下的路径
|
|
|
$nodeBin = 'node'; // 用 which node 查看,或自定义
|
|
$nodeBin = 'node'; // 用 which node 查看,或自定义
|
|
|
if(self::getTronNetwork()){
|
|
if(self::getTronNetwork()){
|
|
@@ -122,9 +154,8 @@ class TronHelper
|
|
|
$fullNodeUrl = self::$tronUrl;
|
|
$fullNodeUrl = self::$tronUrl;
|
|
|
}
|
|
}
|
|
|
$contractAddress = self::getContractAddress('USDT');
|
|
$contractAddress = self::getContractAddress('USDT');
|
|
|
- $apiKey = config('app.tron_pro_api_key', '');
|
|
|
|
|
- $cmd = sprintf(
|
|
|
|
|
- '%s %s %s %s %s %s %s %s 2>&1',
|
|
|
|
|
|
|
+ $apiKey = self::getTronProApiKey();
|
|
|
|
|
+ $parts = [
|
|
|
escapeshellcmd($nodeBin),
|
|
escapeshellcmd($nodeBin),
|
|
|
escapeshellarg($nodeScript),
|
|
escapeshellarg($nodeScript),
|
|
|
escapeshellarg($privateKey),
|
|
escapeshellarg($privateKey),
|
|
@@ -132,8 +163,11 @@ class TronHelper
|
|
|
escapeshellarg($contractAddress),
|
|
escapeshellarg($contractAddress),
|
|
|
escapeshellarg($fullNodeUrl),
|
|
escapeshellarg($fullNodeUrl),
|
|
|
escapeshellarg($amount),
|
|
escapeshellarg($amount),
|
|
|
- escapeshellarg($apiKey)
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ ];
|
|
|
|
|
+ if ($apiKey !== '') {
|
|
|
|
|
+ $parts[] = escapeshellarg($apiKey);
|
|
|
|
|
+ }
|
|
|
|
|
+ $cmd = implode(' ', $parts) . ' 2>&1';
|
|
|
|
|
|
|
|
exec($cmd, $outputLines, $status);
|
|
exec($cmd, $outputLines, $status);
|
|
|
$output = implode("\n", $outputLines);
|
|
$output = implode("\n", $outputLines);
|
|
@@ -285,6 +319,8 @@ class TronHelper
|
|
|
*/
|
|
*/
|
|
|
public static function getTrxBalance($addressBase58)
|
|
public static function getTrxBalance($addressBase58)
|
|
|
{
|
|
{
|
|
|
|
|
+ self::throttleTronRequest();
|
|
|
|
|
+
|
|
|
$hexAddress = TronHelper::base58check2HexString($addressBase58);
|
|
$hexAddress = TronHelper::base58check2HexString($addressBase58);
|
|
|
|
|
|
|
|
self::init();
|
|
self::init();
|
|
@@ -435,6 +471,8 @@ class TronHelper
|
|
|
public static function getTrc20UsdtRecharges(string $address, int $limit = 30): array
|
|
public static function getTrc20UsdtRecharges(string $address, int $limit = 30): array
|
|
|
{
|
|
{
|
|
|
|
|
|
|
|
|
|
+ self::throttleTronRequest();
|
|
|
|
|
+
|
|
|
self::init();
|
|
self::init();
|
|
|
|
|
|
|
|
$usdtContract = self::getContractAddress('USDT');
|
|
$usdtContract = self::getContractAddress('USDT');
|
|
@@ -489,6 +527,8 @@ class TronHelper
|
|
|
*/
|
|
*/
|
|
|
public static function getTrc20Balance($address)
|
|
public static function getTrc20Balance($address)
|
|
|
{
|
|
{
|
|
|
|
|
+ self::throttleTronRequest();
|
|
|
|
|
+
|
|
|
self::init();
|
|
self::init();
|
|
|
|
|
|
|
|
$contractAddress = self::getContractAddress('USDT');
|
|
$contractAddress = self::getContractAddress('USDT');
|
|
@@ -532,6 +572,8 @@ class TronHelper
|
|
|
{
|
|
{
|
|
|
// $client = new Client(['timeout' => 10]);
|
|
// $client = new Client(['timeout' => 10]);
|
|
|
|
|
|
|
|
|
|
+ self::throttleTronRequest();
|
|
|
|
|
+
|
|
|
self::init();
|
|
self::init();
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
@@ -976,6 +1018,8 @@ class TronHelper
|
|
|
if ($amount <= 0) {
|
|
if ($amount <= 0) {
|
|
|
throw new \Exception('不能低于 0 trx');
|
|
throw new \Exception('不能低于 0 trx');
|
|
|
}
|
|
}
|
|
|
|
|
+ self::throttleTronRequest();
|
|
|
|
|
+
|
|
|
// from 初始化
|
|
// from 初始化
|
|
|
if(self::getTronNetwork()){
|
|
if(self::getTronNetwork()){
|
|
|
$api = TronApi::testNetNilo();
|
|
$api = TronApi::testNetNilo();
|