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:
- MainNet — production blockchain.
- Shasta — used for testing your contract. You can get a test TRX on TronGrid.
- 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: