Retrieve transaction info and display in human readable form for ease of read.
<?php
use IEXBase\TronAPI\Tron;
use IEXBase\TronAPI\Support;
use kornrunner\Keccak;
use Web3\Contracts\Ethabi;
use Web3\Contracts\Types\{Address, Boolean, Bytes, DynamicBytes, Integer, Str, Uinteger};
define("TRX_TO_SUN",'1000000');
define("SUN_TO_TRX", '0.000001');
include_once "../libraries/vendor/autoload.php";
include_once("html_iframe_header.php");
include_once("tron_utils.php");
$supportChains = ['main'=>"Tron Mainnet", 'shasta'=>"Shasta Testnet"];
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
try {
if ($_POST['chain'] == 'main') {
$fullNode = new \IEXBase\TronAPI\Provider\HttpProvider('https://api.trongrid.io');
$solidityNode = new \IEXBase\TronAPI\Provider\HttpProvider('https://api.trongrid.io');
$eventServer = new \IEXBase\TronAPI\Provider\HttpProvider('https://api.trongrid.io');
} else {
$fullNode = new \IEXBase\TronAPI\Provider\HttpProvider('https://api.shasta.trongrid.io');
$solidityNode = new \IEXBase\TronAPI\Provider\HttpProvider('https://api.shasta.trongrid.io');
$eventServer = new \IEXBase\TronAPI\Provider\HttpProvider('https://api.shasta.trongrid.io');
}
$tron = new \IEXBase\TronAPI\Tron($fullNode, $solidityNode, $eventServer);
$tx = $tron->getTransaction($_POST['tx_hash']);
$txInfo = $tron->getTransactionInfo($_POST['tx_hash']);
$humanTxInfo = $txInfo;
if (isset($humanTxInfo['resMessage']))
$humanTxInfo['resMessage'] = hex2str($humanTxInfo['resMessage']);
if (isset($humanTxInfo['contract_address']))
$humanTxInfo['contract_address'] = hexString2Base58check($humanTxInfo['contract_address']);
if (isset($humanTxInfo['fee']))
$consumedFeeLimit = bcmul($humanTxInfo['fee'], SUN_TO_TRX, 6);
$totalFeeLimit = bcmul($tx['raw_data']['fee_limit'], SUN_TO_TRX, 6);
$humanTxInfo['fee'] = "{$consumedFeeLimit} TRX / {$totalFeeLimit} TRX";
$humanTxInfo['fee'] .= ", consumed ".bcmul(bcdiv($consumedFeeLimit,$totalFeeLimit,6), "100", 2)."% of fee limit";
if (isset($humanTxInfo['receipt']['energy_fee'])) {
$humanTxInfo['receipt']['energy_fee'] = bcmul($humanTxInfo['receipt']['energy_fee'], SUN_TO_TRX, 6). " TRX or {$humanTxInfo['receipt']['energy_fee']} SUN";
}
if (isset($humanTxInfo['receipt']['origin_energy_usage'])) {
$humanTxInfo['receipt']['origin_energy_usage'] .= " Energy";
}
if (isset($humanTxInfo['receipt']['energy_usage_total'])) {
$humanTxInfo['receipt']['energy_usage_total'] .= " Energy";
}
if (isset($humanTxInfo['receipt']['energy_usage'])) {
$humanTxInfo['receipt']['energy_usage'] .= " Energy";
}
if (isset($humanTxInfo['receipt']['net_usage'])) {
$humanTxInfo['receipt']['net_usage'] .= " Bandwidth";
}
if (isset($humanTxInfo['receipt']['net_fee'])) {
$humanTxInfo['receipt']['net_fee'] = bcmul($humanTxInfo['receipt']['net_fee'], SUN_TO_TRX, 6). " TRX or {$humanTxInfo['receipt']['net_fee']} SUN";
}
$contractDetails = [];
$ethAbi = new Ethabi(['address' => new Address,'bool' => new Boolean,'bytes' => new Bytes,'dynamicBytes' => new DynamicBytes,'int' => new Integer,'string' => new Str,'uint' => new Uinteger,]);
if (is_array($humanTxInfo['log'])) {
//refer to https://developers.tron.network/docs/vm-event about how to decode this
foreach($humanTxInfo['log'] as $k=>$log) {
if (isset($humanTxInfo['log'][$k]['address'])) {
$humanTxInfo['log'][$k]['address'] = hexString2Base58check($contractAddress = "41" . $humanTxInfo['log'][$k]['address']);
if (!$contractDetails[$contractAddress]) {
$contractDetail = $tron->getManager()->request("wallet/getcontract", ["value"=>$contractAddress], "post");
$contractDetails[$contractAddress] = $contractDetail;
}
//decode
$topicPointer = 0;
$targetFunction = $humanTxInfo['log'][$k]['topics'][ $topicPointer++ ];
$abiItems = $contractDetails[$contractAddress]['abi']['entrys'];
foreach($abiItems as $item) {
if ($item['type'] == 'Event') {
$functionParams = [];
if (@count($item['inputs']) > 0) {
foreach($item['inputs'] as $input) {
$functionParams[] = $input['type'];
}
}
$compareFunction = Keccak::hash($plain = "{$item['name']}(".implode(",",$functionParams).")",256);
if ($compareFunction == $targetFunction) {
$humanTxInfo['log'][$k]['topics'][0] = $plain;
$functionNames = $functionParams = [];
if (@count($item['inputs']) > 0) {
foreach($item['inputs'] as $input) {
if($input['indexed'] === true) {
$thisTopic = $topicPointer++;
$paramValue = $humanTxInfo['log'][$k]['topics'][ $thisTopic ];
$decodedValue = $ethAbi->decodeParameter($input['type'], $paramValue);
if ($input['type'] == 'address') {
$humanTxInfo['log'][$k]['topics'][ $thisTopic ] = hexString2Base58check("41".substr($decodedValue, 2));
}
} else {
$functionParams[] = $input['type'];
$functionNames[] = $input['name'];
}
}
}
$nonIndexedData = $humanTxInfo['log'][$k]['data'];
if (count($functionParams) > 0 AND strlen($nonIndexedData) > 0) {
$decodedValues = $ethAbi->decodeParameters($functionParams, $nonIndexedData);
if (@count($decodedValues) > 0) {
$humanTxInfo['log'][$k]['decodedData'] = [];
foreach($decodedValues as $k2=>$decodedValue) {
if (is_bool($decodedValue)) {
$decodedValue = ($decodedValue === true) ? "true" : "false";
}
$humanTxInfo['log'][$k]['decodedData'][] = "Parameter Details - Name: {$functionNames[$k2]}, Data Type: {$functionParams[$k2]}, Value: {$decodedValue}";
}
}
}
}
}
}
}
}
}
if ($txInfo['result'] == 'FAILED') {
$label = "danger";
} else {
$label = "success";
}
?>
<div class="alert alert-<?php echo $label?>">
<h6 class="mt-3">Function Return Result (Original)</h6>
<textarea class="form-control" rows="10" id="comment" readonly><?Php print_r($txInfo)?></textarea>
</div>
<div class="alert alert-<?php echo $label?>">
<h6 class="mt-3">Function Return Result (Human Readable)</h6>
<textarea class="form-control" rows="20" id="comment" readonly><?Php print_r($humanTxInfo)?></textarea>
</div>
<!--
This is a contract created by another contract. So there's no chance for the developer to set an ABI.
You should refer to the creator contract's code.
-->
<?php
} catch (Exception $e) {
$errmsg .= "Problem found. " . $e->getMessage();
}
}
if ($errmsg) {
?>
<div class="alert alert-danger">
<strong>Error!</strong> <?php echo $errmsg?>
</div>
<?php
}
?>
<form action='' method='post'>
<div class="form-group">
<label for="chain">Description:</label>
<table class='table table-bordered table-sm' >
<tr><td style="width:30%;">$txInfo[fee]:</td><td>Consumption of fee, capped at fee limit.</td></tr>
<tr><td style="width:30%;">$txInfo[receipt][energy_usage]:</td><td>Consumption of Energy by contract caller (not include energy_fee).</td></tr>
<tr><td>$txInfo[receipt][energy_fee]:</td><td>Consumption of TRX (SUN) by contract caller due to insufficient Energy.</td></tr>
<tr><td>$txInfo[receipt][origin_energy_usage]:</td><td>Consumption of Energy provided by contract owner.</td></tr>
<tr><td>$txInfo[receipt][energy_usage_total]:</td><td>The total amount of Energy consumed in contract(including the number of Energy corresponding to energy_usage, origin_energy_usage, and energy_fee).</td></tr>
<tr><td>$txInfo[receipt][net_usage]:</td><td>Consumption of Bandwith by contract caller (not include net_fee).</td></tr>
<tr><td>$txInfo[receipt][net_fee]:</td><td>Consumption of TRX (SUN) by contract caller due to insufficient Bandwith.</td></tr>
</table>
</div>
<div class="form-group">
<label for="chain">Chain:</label>
<select id="chain" name="chain" class="form-control" >
<?php
foreach($supportChains as $k=>$v) {
echo "<option value='{$k}'".($k == $_POST['chain'] ? " selected": "").">{$v}</option>";
}
?>
</select>
</div>
<div class="form-group">
<label for="tx_hash">Transaction Hash:</label>
<input class="form-control" type='text' name='tx_hash' id='tx_hash' value='<?php echo $_POST['tx_hash']?>'>
</div>
<input type='submit' class="btn btn-success btn-block"/>
</form>
<?php
include_once("html_iframe_footer.php");