Creating DApp for TRON Platform

Yaroslav Bigus
8 min readNov 28, 2019

Plan of attack

All modern blockchain platforms support smart-contracts. This allows developers to build decentralized apps (DApp). I had a small idea for my own DApp, a small fantasy-basketball-like game — where people can buy avatars of NBA player with crypto wallet, and after player get scores in real games, win crypto (ideally more than avatar costs). Rules for scoring was pretty simple:

To participate in the game, a user buys NBA players avatars(contract with players is valid for 10 days) and their successful actions in the real games give user points back. Points can be converted back to money and withdrew.

As a blockchain platform, I chose Tron because of the great toolset, speed and almost 100% smart contract compatibility between Tron and Ethereum. So I started to build my DApp.

Tron Toolset

Solidity is a language for smart contracts. It’s a simple language, but pretty dumb and insecure. Tron Solidity has almost 100% compatibility with Ethereum.

There was Tron Studio as IDE, but it’s deprecated now. But to tell truth, even before I prefer to use online Remix IDE and then convert Ethereum contract to Tron. Also, there is a nice Solidity extension for the Visual Studio Code.

TronBox is a tool for compiling and deploying smart contracts (Ether analog: Truffle).

TronWeb is a JS API for connecting and interacting with smart contract(Ether analog: Web3)

TronLink is a browser extension to make TronWeb accessible from Chrome. There are apps for mobile like TronLink and MathWallet which allows accessing TronWeb object in your on mobile.

There are 3 types of environments in TronNetwork:

1. MainNet — production blockchain.

2. Shasta — used for testing your contract. You can get a test TRX on TronGrid.

3. Development — docker image with runner blockchain.

For development I usually use Shasta, but sometimes it has accessing issues, so docker based private network can work better and faster for you.

Smart Contract

There are 2 types of accounts in blockchains: normal (your wallet) and contract. Both have address and balance, both support receiving transactions, but contracts additionally support receiving transaction which runs contract’s methods and modifies it’s state or trigger it to transfer money. As mentioned above, smart-contract written in Solidity language, then compiling to bytecode and ABI (application binary interface), then compiled code deployed to the blockchain with a unique address. After this, all blockchain users having a contract address can send transaction which triggers public contract method calls. Contract bytecode executes in the virtual machine(Ethereum/Tron Virtual Machine). To be fair, my knowledge is limited here so enough theory let’s develop our dapp :).

For start, we’ll create structures to store our DApp data and initialize in the constructor contract owner(admin) with contract creator’s wallet address:

Struct definition is pretty similar to other languages, dynamic arrays declaration is also the same as in other languages. Maps definition looks a little bit different: mapping(<key_type> => <value_type>);

For almost every entity I store ID in the dynamic array, and data to Map<ID, value>, so it’s easy to iterate over keys in for loop. For example, we have a dynamic array for wallet addresses, and Map<address, Player>.

Now let’s create methods for players: they can list, purchase or renew avatar:

All these methods are public, listAvatars declared as View Function, which is a promise not to modify contract state. This is an important concept: if your function modifies state it burns Energy, and if it’s transferring money it costs Bandwidth. You should keep this in mind when developing contracts because Energy and Bandwidth cost you money.

Methods for buying and renewal avatars are declared as payable functions. From the listing, you can see that we use require a function to ensure data are valid (avatar id exists, user buying with correct price) if at least one condition fails contract returns error. I found a small issue here when your DApp retrieves error from the contract, TronWeb doesn’t recognize a specified error message it just says “REVERT opcode executed”, so to show user-friendly error messages you should validate all errors on frontend also.

Now let’s allow players to see their balance and be able to withdraw money. It’s really easy to do with the code below:

Finally, the admin(contract owner) should be able to add a new avatar, set the latest avatar scores.

That’s all that we need for our MVP. Original contract has additional methods for updating avatar prices, increase contract balance, set moderators, etc. But I think you got how it works.

Now when the contract code is ready and tested we can create a new project using TronBox tronbox init. Then we can save our solidity code to the contracts folder.

Copy your wallet’s private key to .env file and setup config in tronbox.js if needed (by default it’s enough to place the private key in .env). Also, you need to require your contract in migrations/deploy_migrations.js:

Now we can compile the project using the command: tronbox compile - — compile-all.

When everything is ready we can deploy a smart contract to Shasta Network using the following command: source .env && tronbox migrate — network shasta

As output, you should see the deployed contract address (in base58 as hex format). Save these addresses.

API

You probably noticed that I didn’t save avatars images and names in smart contracts, just IDs. That was made in purpose. First of all, it’s expensive to store lots of data on the contract. Also, it’s hard to return a list of string from solidity function at all. That’s why I build small API on ExpressJS + MongoDB, which returns additional NBA players’ data for specified playerID (name, image address, team, etc). I don’t want to focus on this in this article.

DApp

Now we have a smart contract and API for detailed data and finally, we are ready to create our DApp. For start, generate React app using create-react-app.

As the first step we should figure out does user has a TronLink extension, otherwise, he can’t interact with our smart contract. After a user is logined into TronLink we can access the contract and call its public methods.

To fetch available players from the contract(+ their data from API) we’ll use React Effect Hook, to access API we’ll use ES6 fetch method, to call contract’s public view function, simply call contract.yourViewMethod(<data>).call() which returns Promise:

To call a contract’s payable function we call contract.yourPayableMethod(<data>).send({callValue: <amount>, shouldPollResponse: <should we wait contract response>}), where callValue is amount of money which will be sent to contract (in our case this is NBA player price):

Now we can render our avatars component’s data:

Components for listing purchased avatars and renew avatar looks very similar, so I’ll not provide their listing in this post.

And last but very important method is to withdraw the available balance. It works similar to avatars: use call method to ask balance, use send to withdraw. Here is a component code to do it:

That’s all that is needed for our MVP. I used Netlify for hosting DApp. It has a free plan and very easy to setup.

Here is a link to the app in production (don’t forget to install the TronLink Chrome extension before using it).

Admin Utils

Admin can interact with his part of smart-contract (set scores, add player) for this purpose I created a small NodeJS app(but it could be React app similar to client’s app).

To interact with blockchain on the backend you should require TronWeb library and initialize TronWeb object in your code, then you can access methods the same as we did in ReactApp:

Summary

To tell truth, DApps still bleeding-edge technology: sometimes Shasta network doesn’t work, sometimes you can’t deploy to Shasta, require method doesn’t return a specified error message, and many Solidity dumb things described above. Also, store data in smart-contract is expensive, I only uploaded TOP 100(by scores) NBA players and my wallet was out of energy, even though I froze 1500trx and landed additional energy.

Blockchains for dapps are still a pretty small and volatile market(and most users use it to play at casinos). For example, here is analytics for the last 90 days from dap.review:

As you can see EOS active users dropped from 80k to 16k in just 2 days, Tron(~35k users/day) and ETH (~18k users/day) look a little bit more stable, but these amounts low.

But even 40k users daily can be a good start for your app. And as Peter Thiel mentioned in his “Zero to One: Notes on Startups, or How to Build the Future” you should develop for small markets with potential for growth, and when niche market will grow, your app grows with it and becomes a monopoly. Who knows, maybe the DApps market is the next big thing?

--

--