253 lines
8.9 KiB
PHP
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());
|
|
}
|
|
|
|
|
|
}
|