HRC20 DApp
ERC20 DApp
In this chapter, we'll build a React DApp for the HRC20 Token we deployed previously.
The features for this DApp are similar to the NodeJS CLI tool we've built. The DApp should:
Subscribe to and display token transfer events.
Display total supply, and update it automatically.
Be able to mint new tokens.
Display information about transactions made, e.g. number of confirmations.
It looks something like this:
The only additional complication is that we no longer allow DApp to create a transaction without user permission. Now for every transaction, we should give the user an opportunity to approve or deny it:
The HRC20 DApp is more complex than the CLI App, because it needs to track multiple transactions, and update the UI when a new confirmation occurs.
We will use mobx.js, a reactive programming framework, to keep data and view synchronized.
We can use Qtum's sample DAPP ERC20 project https://github.com/qtumproject/qtumjs-dapp-erc20 , and use it to jump-start your own DApp project with HYDRA.
Brief Intro To Reactive Programming
Most of the complexity in GUI programming is in synchronizing the underlying data and the UI state. When data changes, the UI also needs to change. Conversely, when the UI changes (say user inputs a number), the data needs to change.
It is tedious and error-prone to keep the UI and data in sync.
It'd be nice to bind the UI and data, so they always change together. mobx
provides the tool to do that, and it is almost indistinguishable from magic.
Let's first see how we manually update UI without reactive programming, then we'll see how mobx automates that process.
Manual UI Update
Suppose the data is:
We read the data in a view rendering function:
Now we update the data:
Next, we'll need to manually call renderView
again to refresh:
If we forget to rerender, the view would be stale. In a complex application, there could be many different views using different pieces of data. It's a big challenge to keep track of everything correctly.
Reactive UI Update
Instead of calling renderView
manually, we'd like it to be called automatically when we modify the object, like so:
To accomplish this, mobx
introduces two magic functions:
observable: If you modify an observable object, code that depends on the object's data should automatically re-execute.
autorun: Execute a piece of code, and track all the pieces of observable data that had been used. If anything changed, re-execute.
We change the previously example like this:
And we render the UI using autorun
, so it gets re-executed when obj
is changed:
You can try this example on codepen.io. Modify obj
in the provided console, and see the view changing.
Note: In actual React code, we won't explicitly call
autorun
, the framework handles it. But the idea is the same, modify an object, and the components that uses the object would automatically re-render.
Running The Project
Clone the project:
Install project dependencies:
Like the nodejs CLI tool, we'll need to make the information about deployed contracts available. Let's copy/link solar.development.json
into the project:
Then start the web server:
Open http://localhost:3000, you should see:
Project Structure
src/index.ts: the entry of the project, doing a little bit of setup.
src/views: this directory contains all React components.
src/Store.ts: this observable object manages the logic and data of the application.
The rpc
and myToken
instances are initialized with two global constants:
The constants QTUM_RPC
and SOLAR_REPO
are defined in config/development.js.
Display Total Supply
Store
is an observable object. If the totalSupply
property changes, the React component that uses it would update.
When the app first loads, it calls updateTotalSupply
to get the total supply. The simplified Store
code:
Simply by setting this.totalSupply
, the view that uses it would get re-rendered. Specifically, this chunk of JSX:
https://github.com/hydra-chain/hydrajs-dapp-erc20/blob/92d4aed5128ff5685e23bc1bb4e0b1842e0dccca/src/views/App.tsx#L28-L32
Subscribe To Mint Events
Let's subscribe to the Mint
event so we can update the total supply immediately if somebody minted additional tokens. The simplified code:
Here the app subscribe to both Mint
and Transfer
events, and does something when notified:
Mint
: update the total supply.Transfer
: add the transfer event to an array, so we can display it in the UI.
The view that renders transferEvents
is straightforward:
This view get updated when a new item is added to transferEvents
.
Let's test this out. Use the NodeJS CLI to mint more tokens:
Even though the minting was done outside app, we still get notified. The total supply should increment by 1000, and a new Transfer
event should show up in the UI:
Transaction Lifecycle Management
In a typical web app, the user clicks a button, and the app makes an HTTP request to the server and get a response back. It's a simple cycle, and the user does not need to approve the HTTP request, or to know whether the request had been accepted by the server.
The lifecycle for a transaction has more stages:
A transaction pending user audit & approval.
A transaction is sent to qtumd, and broadcasted to the network.
User waits for transaction to reach some number of confirmations.
Your app may need to give indication as to where transactions are in each of these stages.
Minting Tokens
The mintTokens
method tracks the mint transactions that had been made, and updates the UI as the transactions progress through the various stages of their lifecycles.
The first half of the method creates a new observable txRecord
. The second half updates the txRecord, which in turn triggers views to update.
The annotated code for mintTokens
:
Without the record keeping logic, the code boils down to:
Mint Token UX Workflow
Enter the address and amount, click mint. Initially the tx should be pending for authorization:
Go to the authorization UI to approve it (http://localhost:9899/):
The transaction record should update, and show the number of confirmations reached (up to 3):
Conclusion
We've built a DApp for our HRC20 token. Next let's hold a crowdsale ICO for it!
Last updated