The TRON Developer Hub

Welcome to the TRON developer hub. You'll find comprehensive guides and documentation to help you start working with TRON as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started    

Custom Oracle Implementation

Smart contracts are able to run algorithmic calculations and store and retrieve data. Since the contracts are limited to the blockchain, it’s not possible to make network requests from a Tron contract. Oracles solve this problem by watching the blockchain for events and responding to them by publishing the results of a network request back to the contract. In this way, contracts can interact with the off-chain world.

Source code can be found here.

Developing the Smart Contract

Below is a contract that will have an oracle listen for events being emitted. The oracle will pick up on an event, make a request to get price data for Tron, and write it back to the smart contract.

pragma solidity ^0.4.24;

contract PriceOracle {
	// Address of oracle set in the contract constructor
  address oracleAddress;
  
  // Price data
  string price;
  string rank;
  string marketCap;
  string vol24H;
  string perChange1H;
  string perChange1D;
  string perChange7D;
  
  // Function called on creation of contract, sets oracle address
  constructor (address _oracleAddress) public {
    oracleAddress = _oracleAddress;
  }
  
  // Event emitted when price is updated from oracle
  event PriceUpdate (
  string price,
  string rank,
  string marketCap,
  string vol24H,
  string perChange1H,
  string perChange1D,
  string perChange7D
  );
  
  // Event emitted when a price update is initiated
  event InitUpdate();
  
  // Function called to return price data
  function getPriceData() public returns (string, string, string, string, string, string, string) {
    return (price, rank, marketCap, vol24H, perChange1H, perChange1D, perChange7D);
  }
  
  // Function called to initate price update
  function initUpdate() public {
    emit InitUpdate();
  }
  
  // function called by oracle to update price data within contract
  function updatePrice (
  string _price,
  string _rank,
  string _marketCap,
  string _vol24H,
  string _perChange1H,
  string _perChange1D,
  string _perChange7D
  )
  public
  {
    require(msg.sender == oracleAddress);
    price = _price;
    rank = _rank;
    marketCap = _marketCap;
    vol24H = _vol24H;
    perChange1H = _perChange1H;
    perChange1D = _perChange1D;
    perChange7D = _perChange7D;
    
    emit PriceUpdate (
    price,
    rank,
    marketCap,
    vol24H,
    perChange1H,
    perChange1D,
    perChange7D
    );
  }
}

Deploying the Smart Contract

Now that we have the smart contract written, we are going to deploy it onto the Shasta testnet using Tron Studio. Copy and paste the PriceOracle.sol contract into Tron Studio.

Configure your existing settings to point to the Shasta testnet. Make sure to switch your Environment to Testnet as well.

Developing and Running the Oracle

Now that you have your contract compiled and Tron Studio pointed at Shasta testnet, let's develop the oracle that will be listening for events, fetching price data from an external API, and writing it back to the contract.

Run mkdir PriceOracle and cd into the project directory by running cd PriceOracle in your terminal.

Next, run npm init to initiate a Node.js instance, configure your package.json properties, and open the project directory in your text editor.

Moving on, run npm install tronweb and *npm install request in your project directory to add the necessary dependancies to the oracle.

Finally, create a new javascript file called index.js and copy the below code to the file.

// Initiate request object
const request = require("request");
// Initiate TronWeb object
const TronWeb = require('TronWeb');
const HttpProvider = TronWeb.providers.HttpProvider;
// Full node http endpoint
const fullNode = new HttpProvider("https://api.shasta.trongrid.io");
// Solidity node http endpoint
const solidityNode = new HttpProvider("https://api.shasta.trongrid.io");
// Contract events http endpoint
const eventServer = "https://api.shasta.trongrid.io";
// Private key of oracle
const privateKey = '';

// Create instance of TronWeb
const tronWeb = new TronWeb(
    fullNode,
    solidityNode,
    eventServer,
    privateKey
);


// Create instance of contract object
const contract = {
    "PriceOracle.sol:PriceOracle": {
        "address": "",
        "abi":
    }
};

// Initiate PriceOracle contract object 
const priceOracle = tronWeb.contract(contract["PriceOracle.sol:PriceOracle"].abi, contract["PriceOracle.sol:PriceOracle"].address);

// Function to watch for events on PriceOracle contract
function startEventListener() {
  // Watch for InitUpdate event
    priceOracle.InitUpdate().watch((err, {result}) => {
        if (err) return console.error('Failed to bind event listener:', err);
      
      // Make request to fetch price data from https://api.coinmarketcap.com
        request("https://api.coinmarketcap.com/v2/ticker/1958/", function (err, response, body) {
            if (err) return;
          
          // Parse price data in API response
            const json = JSON.parse(body);
            const data = json.data;
            const rank = data.rank;
            const price = data.quotes.USD.price;
            const marketCap = data.quotes.USD.market_cap;
            const vol24H = data.quotes.USD.volume_24h;
            const perChange1H = data.quotes.USD.percent_change_1h;
            const perChange1D = data.quotes.USD.percent_change_24h;
            const perChange7D = data.quotes.USD.percent_change_7d;
          
// Call state changing function updatePrice within PriceOracle contract to write price data
            priceOracle.updatePrice(price.toString(), rank.toString(), marketCap.toString(),
                vol24H.toString(), perChange1H.toString(), perChange1D.toString(), perChange7D.toString()).send({
                shouldPollResponse: true,
                callValue: 0
            }).catch(function (err) {
                console.log(err)
            });
        })
    });

// Watch for PriceUpdate event
    priceOracle.PriceUpdate().watch((err, {result}) => {
        if (err) return console.error('Failed to bind event listener:', err);
        console.log(result);
    });
}

// Call startEventListener function to watch for events in PriceOracle contract
startEventListener();

Assign the privateKey variable with the private key of the Tron account that you want to be the oracle.

In Tron Studio, copy the public address of the oracle (Public key of the private key variable in the index.js file) in the constructor parameter box and deploy the contract to the Shasta testnet.

Note: If the Tron account of the oracle doesn't have any testnet TRX, the deploy will fail. You can receive test TRX here.

Copy the deployed contract address and convert it to hex string using this tool.

Copy the hex string and assign it to the "address" variable within the contract object in the index.js file.

Next, copy the deployed contract ABI from Tron Studio and assign it to the "abi" variable within the contract object in the index.js file.

Let's start our oracle by running node index.js in the project directory terminal.

The oracle is now listening for events on the deployed PriceOracle contract. In Tron Studio, call the initUpdate function to update the price data within the contract.

Upon successfully calling the initUpdate function, the InitUpdate event is emitted and the oracle picks up on the emitted event, calls and parses the price data api response, and calls the PriceOracle updatePrice contract function to write the price data through this code in the oracle index.js file.

Upon successfully writing the price data through the updatePrice function, the PriceUpdate event is emitted. The oracle will pick up on this emitted event and display the price data from the contract through this code. You will see this in the console of your project.

Congratulations, you have successfully developed a custom oracle that works with the Tron blockchain!

Full Code Examples

pragma solidity ^0.4.24;

contract PriceOracle {
  address oracleAddress;
  
  string price;
  string rank;
  string marketCap;
  string vol24H;
  string perChange1H;
  string perChange1D;
  string perChange7D;
  
  constructor (address _oracleAddress) public {
    oracleAddress = _oracleAddress;
  }
  
  event PriceUpdate (
  string price,
  string rank,
  string marketCap,
  string vol24H,
  string perChange1H,
  string perChange1D,
  string perChange7D
  );
  
  event InitUpdate();
  
  function getPriceData() public returns (string, string, string, string, string, string, string) {
    return (price, rank, marketCap, vol24H, perChange1H, perChange1D, perChange7D);
  }
  
  function initUpdate() public {
    emit InitUpdate();
  }
  
  function updatePrice (
  string _price,
  string _rank,
  string _marketCap,
  string _vol24H,
  string _perChange1H,
  string _perChange1D,
  string _perChange7D
  )
  public
  {
    require(msg.sender == oracleAddress);
    price = _price;
    rank = _rank;
    marketCap = _marketCap;
    vol24H = _vol24H;
    perChange1H = _perChange1H;
    perChange1D = _perChange1D;
    perChange7D = _perChange7D;
    
    emit PriceUpdate (
    price,
    rank,
    marketCap,
    vol24H,
    perChange1H,
    perChange1D,
    perChange7D
    );
  }
}
// Initiate request object
const request = require("request");
// Initiate TronWeb object
const TronWeb = require('TronWeb');
const HttpProvider = TronWeb.providers.HttpProvider;
// Full node http endpoint
const fullNode = new HttpProvider("https://api.shasta.trongrid.io");
// Solidity node http endpoint
const solidityNode = new HttpProvider("https://api.shasta.trongrid.io");
// Contract events http endpoint
const eventServer = "https://api.shasta.trongrid.io";
// Private key of oracle
const privateKey = 'b815adfd6ef133d5a878869cb3a2b31f32d4c1481132a71300c3e125be0ab1a1';

// Create instance of TronWeb
const tronWeb = new TronWeb(
    fullNode,
    solidityNode,
    eventServer,
    privateKey
);


// Create instance of contract object
const contract = {
    "PriceOracle.sol:PriceOracle": {
        "address": "4100CB5944750274A723EB22064201BF2BA1089F55",
        "abi": [{
            "constant": false,
            "inputs": [],
            "name": "initUpdate",
            "outputs": [],
            "payable": false,
            "stateMutability": "nonpayable",
            "type": "function"
        }, {
            "constant": false,
            "inputs": [],
            "name": "getPriceData",
            "outputs": [{"name": "", "type": "string"}, {"name": "", "type": "string"}, {
                "name": "",
                "type": "string"
            }, {"name": "", "type": "string"}, {"name": "", "type": "string"}, {
                "name": "",
                "type": "string"
            }, {"name": "", "type": "string"}],
            "payable": false,
            "stateMutability": "nonpayable",
            "type": "function"
        }, {
            "constant": false,
            "inputs": [{"name": "_price", "type": "string"}, {"name": "_rank", "type": "string"}, {
                "name": "_marketCap",
                "type": "string"
            }, {"name": "_vol24H", "type": "string"}, {
                "name": "_perChange1H",
                "type": "string"
            }, {"name": "_perChange1D", "type": "string"}, {"name": "_perChange7D", "type": "string"}],
            "name": "updatePrice",
            "outputs": [],
            "payable": false,
            "stateMutability": "nonpayable",
            "type": "function"
        }, {
            "inputs": [{"name": "_oracleAddress", "type": "address"}],
            "payable": false,
            "stateMutability": "nonpayable",
            "type": "constructor"
        }, {
            "anonymous": false,
            "inputs": [{"indexed": false, "name": "price", "type": "string"}, {
                "indexed": false,
                "name": "rank",
                "type": "string"
            }, {"indexed": false, "name": "marketCap", "type": "string"}, {
                "indexed": false,
                "name": "vol24H",
                "type": "string"
            }, {"indexed": false, "name": "perChange1H", "type": "string"}, {
                "indexed": false,
                "name": "perChange1D",
                "type": "string"
            }, {"indexed": false, "name": "perChange7D", "type": "string"}],
            "name": "PriceUpdate",
            "type": "event"
        }, {"anonymous": false, "inputs": [], "name": "InitUpdate", "type": "event"}]
    }
};

// Initiate PriceOracle contract object 
const priceOracle = tronWeb.contract(contract["PriceOracle.sol:PriceOracle"].abi, contract["PriceOracle.sol:PriceOracle"].address);

// Function to watch for events on PriceOracle contract
function startEventListener() {
  // Watch for InitUpdate event
    priceOracle.InitUpdate().watch((err, {result}) => {
        if (err) return console.error('Failed to bind event listener:', err);
      
      // Make request to fetch price data from https://api.coinmarketcap.com
        request("https://api.coinmarketcap.com/v2/ticker/1958/", function (err, response, body) {
            if (err) return;
          
          // Parse price data in API response
            const json = JSON.parse(body);
            const data = json.data;
            const rank = data.rank;
            const price = data.quotes.USD.price;
            const marketCap = data.quotes.USD.market_cap;
            const vol24H = data.quotes.USD.volume_24h;
            const perChange1H = data.quotes.USD.percent_change_1h;
            const perChange1D = data.quotes.USD.percent_change_24h;
            const perChange7D = data.quotes.USD.percent_change_7d;
          
// Call state changing function updatePrice within PriceOracle contract to write price data
            priceOracle.updatePrice(price.toString(), rank.toString(), marketCap.toString(),
                vol24H.toString(), perChange1H.toString(), perChange1D.toString(), perChange7D.toString()).send({
                shouldPollResponse: true,
                callValue: 0
            }).catch(function (err) {
                console.log(err)
            });
        })
    });

// Watch for PriceUpdate event
    priceOracle.PriceUpdate().watch((err, {result}) => {
        if (err) return console.error('Failed to bind event listener:', err);
        console.log(result);
    });
}

// Call startEventListener function to watch for events in PriceOracle contract
startEventListener();