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");