Tron Create Raw Transaction


Generate serialized raw transaction that ready broadcast to TRON network.


Generate Raw Tx

<?php 
use IEXBase\TronAPI\Tron;
use IEXBase\TronAPI\Support;
use Protocol\Transaction\Contract\ContractType;

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

//include all php files that generated by protoc
$dir   = new RecursiveDirectoryIterator('protobuf/core/');
$iter  = new RecursiveIteratorIterator($dir);
$files = new RegexIterator($iter, '/^.+\.php$/', RecursiveRegexIterator::GET_MATCH); // an Iterator, not an array

foreach ( $files as $file ) {
	
	if (is_array($file)) {
		foreach($file as $filename) {
			include $filename;
		}
	} else {
		include $file;
	}
}


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');
		}
		
		//get current block
		$tron = new \IEXBase\TronAPI\Tron($fullNode, $solidityNode, $eventServer);
		$newestBlock = $tron->getCurrentBlock();
		$currentHeight = (int)$newestBlock['block_header']['raw_data']['number'];
		if ($currentHeight<=0) {
			throw new Exception("Fail retrieve current block.");
		}
		
		//get last confirmed block
		$confirmation = 20;
		$targetHeight = ($currentHeight - $confirmation) + 1;
		
		$confirmedBlock = $tron->getBlockByNumber($targetHeight);
		$blockHeight = (int)$confirmedBlock['block_header']['raw_data']['number'];
		$blockTs = (int)$confirmedBlock['block_header']['raw_data']['timestamp'];
		$blockHash = $confirmedBlock['blockID'];
		
		$currentTimeMillis = round(microtime(true) * 1000);
		
		//build tx
		$contract = new \Protocol\Transaction\Contract();
		$contract->mergeFromString(hex2str($_POST['contract_hex']));
		
		if (in_array($contract->getType(), [ContractType::TriggerSmartContract,ContractType::CreateSmartContract])) {
			if (!is_numeric($_POST['feelimit'])) {
				throw new Exception("Fee limit is required");
			} else if (bccomp($_POST['feelimit'], "1000", 6) == 1) {
				throw new Exception("Fee limit should not exceed 1000 TRX");
			}
		} else {
			if (strlen($_POST['feelimit'])) {
				throw new Exception("Fee limit is only applicable to TriggerSmartContract or CreateSmartContract contract type.");
			}
		}
		
		$feeLimitInSun = bcmul($_POST['feelimit'], TRX_TO_SUN);
		$raw = new \Protocol\Transaction\Raw();
		$raw->setContract([$contract]);
		$raw->setFeeLimit($feeLimitInSun);
		
		$blockHeightIn64bits = str_pad(dechex($blockHeight), 8 * 2 /* 8 bytes = 16 hex chars*/, "0", STR_PAD_LEFT);
		
		/*
		If you reference a block that is generated before recent 65535 block, the transaction will be failed. I will suggest to use the latest solidified block as the reference block to ensure the transaction cannot failed because of TAPOS error.
		*/
		$raw->setRefBlockBytes( hex2Str( $refBlockBytes = substr($blockHeightIn64bits, 12, 4) ));
		$raw->setRefBlockHash( hex2Str( $refBlockHash =  substr($blockHash, 16, 16) ));
		$raw->setTimestamp($currentTimeMillis);
		$raw->setExpiration( $blockTs + ((int)$_POST['expiration'] * 1000) );
		
		$txId = hash("sha256", $raw->serializeToString());
		
		$tx = new \Protocol\Transaction();
		$tx->setRawData($raw);
		
		$signature = Support\Secp::sign($txId, $_POST['privkey']);
		$tx->setSignature([hex2str( $signature )]);
	
    ?>
        <div class="alert alert-success">
			<h6 class="mt-3">Raw Tx Hex</h6>
			<textarea class="form-control" rows="5" id="comment" readonly><?php echo str2hex($tx->serializeToString());?></textarea>
			
			
			<h6 class="mt-3">Tx Byte Size</h6>
			<input class="form-control" rows="5" id="comment" readonly value="<?php echo $tx->byteSize();?>"></textarea>
			
			<h6 class="mt-3">Consume Bandwidth</h6>
			<input class="form-control" rows="5" id="comment" readonly value="<?php echo $tx->byteSize() + 64;?>"></textarea>
			
			<h6 class="mt-3">Tx Id</h6>
			<input class="form-control" rows="5" id="comment" readonly value="<?php echo $txId;?>"></textarea>
		</div>
<?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">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="contract_hex">Contract Serialized Hex:</label>
        <input class="form-control" type='text' name='contract_hex' id='contract_hex' value='<?php echo $_POST['contract_hex']?>'>
    </div>
	
	<div class="form-group">
		<label for="feelimit">Fee Limit (Maximum TRX consumption):</label>
		
		<div class="input-group mb-3">
			<input class="form-control" type='text' name='feelimit' id='feelimit' value='<?php echo $_POST['feelimit']?>'>
			<div class="input-group-append">
			  <span class="input-group-text">TRX</span>
			</div>
		</div>
		<small>This applicable to smart contract deployment (CreateSmartContract) or execution (TriggerSmartContract) only, put blank if you are not sure.</small>
	</div>
	
	<div class="form-group">
		<label for="expiration">Expiration Time:</label>
		
		<div class="input-group mb-3">
			<input class="form-control" type='text' name='expiration' id='expiration' value='<?php echo $_POST['expiration']?>'>
			<div class="input-group-append">
			  <span class="input-group-text">Seconds</span>
			</div>
		</div>
		
		<small>
			Relative time from last confirmed block.
		</small>
	</div>
	
	<div class="form-group">
        <label for="privkey">Private Key:</label>
        <input class="form-control" type='text' name='privkey' id='privkey' value='<?php echo $_POST['privkey']?>'>
    </div>
   
    <input type='submit' class="btn btn-success btn-block"/>
</form>
<?php
include_once("html_iframe_footer.php");
<?php
# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: core/Tron.proto

namespace Protocol\Transaction;

use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;

/**
 * Generated from protobuf message <code>protocol.Transaction.raw</code>
 */
class raw extends \Google\Protobuf\Internal\Message
{
    /**
     * Generated from protobuf field <code>bytes ref_block_bytes = 1;</code>
     */
    protected $ref_block_bytes = '';
    /**
     * Generated from protobuf field <code>int64 ref_block_num = 3;</code>
     */
    protected $ref_block_num = 0;
    /**
     * Generated from protobuf field <code>bytes ref_block_hash = 4;</code>
     */
    protected $ref_block_hash = '';
    /**
     * Generated from protobuf field <code>int64 expiration = 8;</code>
     */
    protected $expiration = 0;
    /**
     * Generated from protobuf field <code>repeated .protocol.authority auths = 9;</code>
     */
    private $auths;
    /**
     * transaction note
     *
     * Generated from protobuf field <code>bytes data = 10;</code>
     */
    protected $data = '';
    /**
     *only support size = 1, repeated list here for extension
     *
     * Generated from protobuf field <code>repeated .protocol.Transaction.Contract contract = 11;</code>
     */
    private $contract;
    /**
     * scripts not used
     *
     * Generated from protobuf field <code>bytes scripts = 12;</code>
     */
    protected $scripts = '';
    /**
     * Generated from protobuf field <code>int64 timestamp = 14;</code>
     */
    protected $timestamp = 0;
    /**
     * Generated from protobuf field <code>int64 fee_limit = 18;</code>
     */
    protected $fee_limit = 0;

    /**
     * Constructor.
     *
     * @param array $data {
     *     Optional. Data for populating the Message object.
     *
     *     @type string $ref_block_bytes
     *     @type int|string $ref_block_num
     *     @type string $ref_block_hash
     *     @type int|string $expiration
     *     @type \Protocol\authority[]|\Google\Protobuf\Internal\RepeatedField $auths
     *     @type string $data
     *           transaction note
     *     @type \Protocol\Transaction\Contract[]|\Google\Protobuf\Internal\RepeatedField $contract
     *          only support size = 1, repeated list here for extension
     *     @type string $scripts
     *           scripts not used
     *     @type int|string $timestamp
     *     @type int|string $fee_limit
     * }
     */
    public function __construct($data = NULL) {
        \GPBMetadata\Core\Tron::initOnce();
        parent::__construct($data);
    }

    /**
     * Generated from protobuf field <code>bytes ref_block_bytes = 1;</code>
     * @return string
     */
    public function getRefBlockBytes()
    {
        return $this->ref_block_bytes;
    }

    /**
     * Generated from protobuf field <code>bytes ref_block_bytes = 1;</code>
     * @param string $var
     * @return $this
     */
    public function setRefBlockBytes($var)
    {
        GPBUtil::checkString($var, False);
        $this->ref_block_bytes = $var;

        return $this;
    }

    /**
     * Generated from protobuf field <code>int64 ref_block_num = 3;</code>
     * @return int|string
     */
    public function getRefBlockNum()
    {
        return $this->ref_block_num;
    }

    /**
     * Generated from protobuf field <code>int64 ref_block_num = 3;</code>
     * @param int|string $var
     * @return $this
     */
    public function setRefBlockNum($var)
    {
        GPBUtil::checkInt64($var);
        $this->ref_block_num = $var;

        return $this;
    }

    /**
     * Generated from protobuf field <code>bytes ref_block_hash = 4;</code>
     * @return string
     */
    public function getRefBlockHash()
    {
        return $this->ref_block_hash;
    }

    /**
     * Generated from protobuf field <code>bytes ref_block_hash = 4;</code>
     * @param string $var
     * @return $this
     */
    public function setRefBlockHash($var)
    {
        GPBUtil::checkString($var, False);
        $this->ref_block_hash = $var;

        return $this;
    }

    /**
     * Generated from protobuf field <code>int64 expiration = 8;</code>
     * @return int|string
     */
    public function getExpiration()
    {
        return $this->expiration;
    }

    /**
     * Generated from protobuf field <code>int64 expiration = 8;</code>
     * @param int|string $var
     * @return $this
     */
    public function setExpiration($var)
    {
        GPBUtil::checkInt64($var);
        $this->expiration = $var;

        return $this;
    }

    /**
     * Generated from protobuf field <code>repeated .protocol.authority auths = 9;</code>
     * @return \Google\Protobuf\Internal\RepeatedField
     */
    public function getAuths()
    {
        return $this->auths;
    }

    /**
     * Generated from protobuf field <code>repeated .protocol.authority auths = 9;</code>
     * @param \Protocol\authority[]|\Google\Protobuf\Internal\RepeatedField $var
     * @return $this
     */
    public function setAuths($var)
    {
        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Protocol\authority::class);
        $this->auths = $arr;

        return $this;
    }

    /**
     * transaction note
     *
     * Generated from protobuf field <code>bytes data = 10;</code>
     * @return string
     */
    public function getData()
    {
        return $this->data;
    }

    /**
     * transaction note
     *
     * Generated from protobuf field <code>bytes data = 10;</code>
     * @param string $var
     * @return $this
     */
    public function setData($var)
    {
        GPBUtil::checkString($var, False);
        $this->data = $var;

        return $this;
    }

    /**
     *only support size = 1, repeated list here for extension
     *
     * Generated from protobuf field <code>repeated .protocol.Transaction.Contract contract = 11;</code>
     * @return \Google\Protobuf\Internal\RepeatedField
     */
    public function getContract()
    {
        return $this->contract;
    }

    /**
     *only support size = 1, repeated list here for extension
     *
     * Generated from protobuf field <code>repeated .protocol.Transaction.Contract contract = 11;</code>
     * @param \Protocol\Transaction\Contract[]|\Google\Protobuf\Internal\RepeatedField $var
     * @return $this
     */
    public function setContract($var)
    {
        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Protocol\Transaction\Contract::class);
        $this->contract = $arr;

        return $this;
    }

    /**
     * scripts not used
     *
     * Generated from protobuf field <code>bytes scripts = 12;</code>
     * @return string
     */
    public function getScripts()
    {
        return $this->scripts;
    }

    /**
     * scripts not used
     *
     * Generated from protobuf field <code>bytes scripts = 12;</code>
     * @param string $var
     * @return $this
     */
    public function setScripts($var)
    {
        GPBUtil::checkString($var, False);
        $this->scripts = $var;

        return $this;
    }

    /**
     * Generated from protobuf field <code>int64 timestamp = 14;</code>
     * @return int|string
     */
    public function getTimestamp()
    {
        return $this->timestamp;
    }

    /**
     * Generated from protobuf field <code>int64 timestamp = 14;</code>
     * @param int|string $var
     * @return $this
     */
    public function setTimestamp($var)
    {
        GPBUtil::checkInt64($var);
        $this->timestamp = $var;

        return $this;
    }

    /**
     * Generated from protobuf field <code>int64 fee_limit = 18;</code>
     * @return int|string
     */
    public function getFeeLimit()
    {
        return $this->fee_limit;
    }

    /**
     * Generated from protobuf field <code>int64 fee_limit = 18;</code>
     * @param int|string $var
     * @return $this
     */
    public function setFeeLimit($var)
    {
        GPBUtil::checkInt64($var);
        $this->fee_limit = $var;

        return $this;
    }

}

// Adding a class alias for backwards compatibility with the previous class name.
class_alias(raw::class, \Protocol\Transaction_raw::class);

<?php
# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: core/Tron.proto

namespace Protocol;

use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;

/**
 * Generated from protobuf message <code>protocol.Transaction</code>
 */
class Transaction extends \Google\Protobuf\Internal\Message
{
    /**
     * Generated from protobuf field <code>.protocol.Transaction.raw raw_data = 1;</code>
     */
    protected $raw_data = null;
    /**
     * only support size = 1, repeated list here for muti-sig extension
     *
     * Generated from protobuf field <code>repeated bytes signature = 2;</code>
     */
    private $signature;
    /**
     * Generated from protobuf field <code>repeated .protocol.Transaction.Result ret = 5;</code>
     */
    private $ret;

    /**
     * Constructor.
     *
     * @param array $data {
     *     Optional. Data for populating the Message object.
     *
     *     @type \Protocol\Transaction\raw $raw_data
     *     @type string[]|\Google\Protobuf\Internal\RepeatedField $signature
     *           only support size = 1, repeated list here for muti-sig extension
     *     @type \Protocol\Transaction\Result[]|\Google\Protobuf\Internal\RepeatedField $ret
     * }
     */
    public function __construct($data = NULL) {
        \GPBMetadata\Core\Tron::initOnce();
        parent::__construct($data);
    }

    /**
     * Generated from protobuf field <code>.protocol.Transaction.raw raw_data = 1;</code>
     * @return \Protocol\Transaction\raw
     */
    public function getRawData()
    {
        return isset($this->raw_data) ? $this->raw_data : null;
    }

    public function hasRawData()
    {
        return isset($this->raw_data);
    }

    public function clearRawData()
    {
        unset($this->raw_data);
    }

    /**
     * Generated from protobuf field <code>.protocol.Transaction.raw raw_data = 1;</code>
     * @param \Protocol\Transaction\raw $var
     * @return $this
     */
    public function setRawData($var)
    {
        GPBUtil::checkMessage($var, \Protocol\Transaction\raw::class);
        $this->raw_data = $var;

        return $this;
    }

    /**
     * only support size = 1, repeated list here for muti-sig extension
     *
     * Generated from protobuf field <code>repeated bytes signature = 2;</code>
     * @return \Google\Protobuf\Internal\RepeatedField
     */
    public function getSignature()
    {
        return $this->signature;
    }

    /**
     * only support size = 1, repeated list here for muti-sig extension
     *
     * Generated from protobuf field <code>repeated bytes signature = 2;</code>
     * @param string[]|\Google\Protobuf\Internal\RepeatedField $var
     * @return $this
     */
    public function setSignature($var)
    {
        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::BYTES);
        $this->signature = $arr;

        return $this;
    }

    /**
     * Generated from protobuf field <code>repeated .protocol.Transaction.Result ret = 5;</code>
     * @return \Google\Protobuf\Internal\RepeatedField
     */
    public function getRet()
    {
        return $this->ret;
    }

    /**
     * Generated from protobuf field <code>repeated .protocol.Transaction.Result ret = 5;</code>
     * @param \Protocol\Transaction\Result[]|\Google\Protobuf\Internal\RepeatedField $var
     * @return $this
     */
    public function setRet($var)
    {
        $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Protocol\Transaction\Result::class);
        $this->ret = $arr;

        return $this;
    }

}









Tutorials
About Us
Contents have been open source in GITHUB. Please give me a ⭐ if you found this helpful :)
Community
Problem? Raise me a new issue.
Support Us
Buy me a coffee. so i can spend more nights for this :)

BTCSCHOOLS would like to present you with more pratical but little theory throughout our tutorials. Pages' content are constantly keep reviewed to avoid mistakes, but we cannot warrant correctness of all contents. While using this site, you agree to accept our terms of use, cookie & privacy policy. Copyright 2019 by BTCSCHOOLS. All Rights Reserved.