Files
cycle_api/sdk/Wallet/Trc20Sdk.php
2024-03-25 06:15:36 +08:00

253 lines
8.9 KiB
PHP

<?php
namespace Sdk\Wallet;
use App\Bean\Sdk\Wallet\Tron\NowBlockBean;
use App\Bean\Sdk\Wallet\Tron\ResponseBean;
use App\Bean\Sdk\Wallet\Tron\TokenAddressBean;
use App\Bean\Sdk\Wallet\Tron\TransferTransactionBean;
use App\Exceptions\WalletSdkException;
use App\Tools\Math;
use GuzzleHttp\Client;
use IEXBase\TronAPI\Exception\TronException;
use IEXBase\TronAPI\Provider\HttpProvider;
use IEXBase\TronAPI\Tron;
use Sdk\Wallet\Tools\Formatter;
use Sdk\Wallet\Tools\Utils;
class Trc20Sdk
{
protected $tron;
protected $tronContract;
protected $config = [];
protected TokenAddress $contractAddress;
protected Http $http;
const DECIMALS = 6;
function __construct(Client $_api, string $contractAddress)
{
$this->http = new Http($_api);
$this->contractAddress = new TokenAddress($contractAddress);
$host = $this->getHttpClient()->getClient()->getConfig('base_uri')->getScheme() . '://' . $this->getHttpClient()->getClient()->getConfig('base_uri')->getHost();
$fullNode = new HttpProvider($host);
$solidityNode = new HttpProvider($host);
$eventServer = new HttpProvider($host);
try {
$this->tron = new Tron($fullNode, $solidityNode, $eventServer);
// $this->tronContract = new TRC20Contract($this->tron,$contractAddress);
} catch (\Exception $e) {
throw new WalletSdkException($e->getMessage(), $e->getCode());
}
}
function getHttpClient(): Http
{
return $this->http;
}
//获取当前最新区块事件
function getLastBlockEvent(): NowBlockBean|bool
{
$data = [
'limit' => 1,
'order_by' => 'block_timestamp,desc',
];
$res = $this->getHttpClient()->get('/v1/blocks/latest/events', $data);
if (!isset($res['data'][0])) return false;
$ResponseBean = new ResponseBean($res);
$item = $ResponseBean->getData()[0];
return new NowBlockBean($item);
}
//获取当前最新区块事件
function getNowBlockNumber(): NowBlockBean|bool
{
return $this->getLastBlockEvent();
}
//根据区块高度获取交易信息
public function getTrc20BlockEventsByBlockNumber(string|int $blockNumber, $fingerprint = null, $limit = 200): bool|ResponseBean
{
$path = '/v1/contracts/' . $this->contractAddress->address . '/events';
$data = [
'block_number' => $blockNumber,
'limit' => $limit,
'only_confirmed' => true,
];
if (!empty($fingerprint)) $data['fingerprint'] = $fingerprint;
$res = $this->getHttpClient()->get($path, $data);
if (!isset($res['success'])) return false;
if ($res['success'] !== true) return false;
return new ResponseBean($res);
}
//根据区块高度获取交易信息
public function getTrc20BlockEventsTransferByBlockNumber(string|int $blockNumber, $fingerprint = null, $limit = 200): bool|ResponseBean
{
$path = '/v1/contracts/' . $this->contractAddress->address . '/events';
$data = [
'event_name' => 'Transfer',
'block_number' => $blockNumber,
'limit' => $limit,
'only_confirmed' => true,
'order_by' => 'block_timestamp,asc',
];
if (!empty($fingerprint)) $data['fingerprint'] = $fingerprint;
$res = $this->getHttpClient()->get($path, $data);
if (!isset($res['success'])) return false;
if ($res['success'] !== true) return false;
return new ResponseBean($res);
}
//获取账户合约交易记录
public function getAccountTrc20Events(string $address, $fingerprint = null, $limit = 200): bool|ResponseBean
{
$path = '/v1/accounts/' . $address . '//transactions/trc20';
$data = [
'limit' => $limit,
'contract_address' => $this->contractAddress->address,
'only_confirmed' => true,
'order_by' => 'block_timestamp,desc',
];
if (!empty($fingerprint)) $data['fingerprint'] = $fingerprint;
$res = $this->getHttpClient()->get($path, $data);
if (!isset($res['success'])) return false;
if ($res['success'] !== true) return false;
return new ResponseBean($res);
}
//获取TRC20余额
function getTrc20Balance(string $address): float|string
{
$address = new TokenAddress($address);
$format = Formatter::toAddressFormat($address->hexAddress);
$res = $this->getHttpClient()->post('/wallet/triggersmartcontract', [
'contract_address' => $this->contractAddress->hexAddress,
'function_selector' => 'balanceOf(address)',
'parameter' => $format,
'owner_address' => $address->hexAddress,
]);
if (!isset($res['result']['result'])) {
throw new WalletSdkException('getTrc20Balance error');
}
if ($res['result']['result'] !== true) {
throw new WalletSdkException('getTrc20Balance error');
}
try {
$hex_value = $res['constant_result'][0];
$balance = Math::valueToAmount(hexdec($hex_value), self::DECIMALS);
} catch (\Exception $e) {
throw new WalletSdkException($e->getMessage());
}
return $balance;
}
//获取TRX余额
function getTrxBalance(string $address): float
{
$this->tron->setAddress($address);
return $this->tron->getBalance($address, true);
}
//TRC20转账
function trc20Transfer(TokenAddress $from, TokenAddress $to, float $amount): TransferTransactionBean|bool
{
$this->tron->setAddress($from->address);
$this->tron->setPrivateKey($from->privateKey);
$toFormat = Formatter::toAddressFormat($to->hexAddress);
try {
$amount = Utils::toMinUnitByDecimals($amount, self::DECIMALS);
} catch (\Exception $e) {
throw new WalletSdkException($e->getMessage());
}
$numberFormat = Formatter::toIntegerFormat($amount);
$body = $this->getHttpClient()->post('/wallet/triggersmartcontract', [
'contract_address' => $this->contractAddress->hexAddress,
'function_selector' => 'transfer(address,uint256)',
'parameter' => "{$toFormat}{$numberFormat}",
'fee_limit' => 30000000,
'call_value' => 0,
'owner_address' => $from->hexAddress,
]);
if (!isset($body['result']['result'])) {
throw new WalletSdkException(hex2bin($body['result']['message']));
}
try {
$tradeobj = $this->tron->signTransaction($body['transaction']);
$response = $this->tron->sendRawTransaction($tradeobj);
} catch (\Exception $e) {
throw new WalletSdkException($e->getMessage(), $e->getCode());
}
if (isset($response['result']) && $response['result'] == true) {
return new TransferTransactionBean($body['transaction']);
} else {
throw new WalletSdkException(hex2bin($response['result']['message']));
}
return false;
}
//TRX转账
function trxTransfer(TokenAddress $from, TokenAddress $to, float $amount): TransferTransactionBean
{
$this->tron->setAddress($from->address);
$this->tron->setPrivateKey($from->privateKey);
try {
$transaction = $this->tron->getTransactionBuilder()->sendTrx($to->address, $amount, $from->address);
$signedTransaction = $this->tron->signTransaction($transaction);
$response = $this->tron->sendRawTransaction($signedTransaction);
} catch (\Exception $e) {
throw new WalletSdkException($e->getMessage(), $e->getCode());
}
if (isset($response['result']) && $response['result'] == true) {
$TransferTransactionBean = new TransferTransactionBean($signedTransaction);
return $TransferTransactionBean;
} else {
throw new WalletSdkException(hex2bin($response['message']));
}
}
//根据交易hash获取交易信息
function getTransactionByTid(string $tid): array
{
try {
return $this->tron->getTransaction($tid);
} catch (\Exception $e) {
throw new WalletSdkException($e->getMessage(), $e->getCode());
}
}
//检测交易是否成功
function checkTransactionByTid(string $tid): bool
{
$res = $this->getTransactionByTid($tid);
if (empty($res)) return false;
if (!isset($res['ret']['contractRet'])) return false;
if ($res['ret']['contractRet'] === 'SUCCESS') return true;
return false;
}
//生成新地址
function createAccount(): TokenAddressBean
{
try {
$res = $this->tron->createAccount();
} catch (TronException $e) {
throw new WalletSdkException($e->getMessage(), $e->getCode());
}
return new TokenAddressBean($res->getRawData());
}
}