HYDRA Documentation
  • Introduction to Hydra Chain
  • HydraGon
    • Migrate to HydraGon
    • Staking Calculator
  • Legacy Hydra
  • FAQ
  • Hydra web wallet
    • Create New Wallet
      • Key File Option
      • Mnemonic Words Option
    • Access Your Wallet
      • From Mnemonic Words
      • From Private Key
      • From Key File
    • Send and Receive Assets
      • Receive Assets
      • Send Assets
    • Add HRC20 Token
    • Setup Offline Wallet
  • Hydra web browser extension
    • How to integrate with dApps
  • Hydra for Beginners
  • Ledger Nano Guide
  • Hydra Bridge
  • HydraDEX
    • Adding and Removing Liquidity
    • Liquidity Mining on HydraDEX
  • Useful Links (Legacy)
  • Essentials
    • UTXOs Accounting
    • Test & Main Networks
    • Desktop wallet basic usage
    • Wallet Encrypt, Backup and Restore
    • Hydra Core Wallet Commands
    • Adding Nodes
    • Encrypt and Unlock Hydra Wallet
    • Wallet Recovery With Salvagewallet
    • bech32 support
    • Repositories
    • Hydra Exchange Usage Guide
    • How to Add Options
    • How to Use bootstrap.dat
    • Command Lines (RPC API)
    • Guidance of Hydra Deployment and RPC Settings
    • How to Build Hydra on Raspbian
  • HRC20 Tokens
    • HRC20 Token
    • HRC20 Raw Transactions
    • HRC20 With Hydrachainjs
    • HRC20 DApp
  • HRC721 Tokens
    • HRC721 Token - How to deploy
  • How Transactions Work
  • Hydra Economy (Legacy)
    • The Flexible Supply Mechanism
    • Legacy Staking Calculator
  • Installation Guides
  • Guide for Linux
  • Guide for Raspberry Pi
  • Guide for MacOS
  • Staking HYDRA Coins
    • Setting up Staking
    • Staking with Windows VPS on AWS
    • Staking with Linux on DigitalOcean VPS
    • How to Stake Hydra on Linux
    • Stake With Linux VPS
    • How to Stake on FreeBSD
    • Hydra node health check
    • Superstaking
    • Delegating to Superstaker
    • Delegating via Mobile App or Web Browser
    • Lydra Basics
    • Understanding LYDRA — Key Concepts and Dynamics
  • Hydra Chain Core Team
  • KYC/AML Policy
  • Privacy Policy
  • API Documentation
    • Explorer API (in work)
      • General Blockchain Info
      • Fetching Transaction History for HYDRA and HRC20 tokens
      • Block Info
      • Transaction Info
    • Hydra DEX API
  • Community Tools
    • Github repository
    • Docker image for Hydra Node
    • Hydradex.org Custom Lists
  • Security Audits Hydra Bridge
Powered by GitBook
On this page
  • ERC20 DApp
  • Brief Intro To Reactive Programming
  • Manual UI Update
  • Reactive UI Update
  • Running The Project
  • Project Structure
  • Display Total Supply
  • Subscribe To Mint Events
  • Transaction Lifecycle Management
  • Minting Tokens
  • Mint Token UX Workflow
  • Conclusion

Was this helpful?

  1. HRC20 Tokens

HRC20 DApp

PreviousHRC20 With HydrachainjsNextHRC721 Tokens

Last updated 4 years ago

Was this helpful?

ERC20 DApp

In this chapter, we'll build a React DApp for the .

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 , because it needs to track multiple transactions, and update the UI when a new confirmation occurs.

We will use , a reactive programming framework, to keep data and view synchronized.

We can use Qtum's sample DAPP ERC20 project , 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:

const obj = {
  a: 1,
  b: 2,
}

We read the data in a view rendering function:

function renderView(obj) {
  const view = (
    <div>
      a: {obj.a}
      <br/>
      b: {obj.b}
    div>
  )
  ReactDOM.render(view, document.querySelector("#root"))
}

Now we update the data:

obj.a = 10

Next, we'll need to manually call renderView again to refresh:

renderView(obj)

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:

obj.a = 10

To accomplish this, mobx introduces two magic functions:

We change the previously example like this:


const obj = observable({
  a: 1,
  b: 2,
})

And we render the UI using autorun, so it gets re-executed when obj is changed:


autorun(() => {
  renderView(obj)
})

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:

git clone https://github.com/hydra-chain/qtumjs-dapp-erc20.git

Install project dependencies:

yarn install
# or: npm install

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:

ln -s ~/hydrabook/examples/mytoken/solar.development.json solar.development.json

Then start the web server:

npm start

> hydra-portal-ui@0.0.1 start /Users/rosen/hydra/hydrajs-dapp-erc20
> neutrino start

✔ Development server running on: http://localhost:3000
✔ Build completed

Project Structure

The rpc and myToken instances are initialized with two global constants:

const rpc = new HydraRPC(HYDRA_RPC)

const myToken = new Contract(rpc, SOLAR_REPO.contracts["zeppelin-solidity/contracts/token/CappedToken.sol"])

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:

class Store {
  @observable public totalSupply: number = 0

  
  public async updateTotalSupply() {
    const result = await myToken.call("totalSupply")
    const supply = result.outputs[0]

    
    this.totalSupply = supply.toNumber()
  }
}

Simply by setting this.totalSupply, the view that uses it would get re-rendered. Specifically, this chunk of JSX:

<h1>
  <span className="is-size-2"> {totalSupply} span>
  <br />
  Total Supply
h1>

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:

class Store {
  @observable.shallow public transferEvents: ITransferLog[] = []

  
  private async observeEvents() {
    this.emitter = myToken.logEmitter()

    this.emitter.on("Mint", () => {
      this.updateTotalSupply()
    })

    this.emitter.on("Transfer", (log: ITransferLog) => {
      this.transferEvents.unshift(log)
    })
  }
}

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:

<h1> Transfers h1>

{transferEvents.length === 0 && "no transfer event observed yet"}

{
  transferEvents.map((log) => <TransferLog key={log.transactionHash} log={log} />)
}

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:

node index.js mint dcd32b87270aeb980333213da2549c9907e09e94 1000

mint tx: 7f0ff25475e2e6e0943fa6fb934999019d7a6a886126c220d0fa7cdcc3c36feb

✔ confirm mint

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:

  1. A transaction pending user audit & approval.

  2. A transaction is sent to qtumd, and broadcasted to the network.

  3. 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:

public async mintTokens(toAddress: string, amount: number) {
  
  
  this.txRecords.unshift({
    method: "mint",
    params: {
      toAddress,
      amount,
    },

    
    tx: undefined,
    error: undefined,
  })

  
  const txRecord = this.txRecords[0]

  

  try {
    
    
    const tx = await myToken.send("mint", [toAddress, amount])

    
    txRecord.tx = tx

    
    await tx.confirm(3, (tx2) => {
      
      
      
      txRecord.tx = tx2
    })
  } catch (err) {
    
    
    
    txRecord.error = err
  }
}

Without the record keeping logic, the code boils down to:

const tx = await myToken.send("mint", [toAddress, amount])
await tx.confirm(3)

Mint Token UX Workflow

Enter the address and amount, click mint. Initially the tx should be pending for authorization:

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!

: If you modify an observable object, code that depends on the object's data should automatically re-execute.

: Execute a piece of code, and track all the pieces of observable data that had been used. If anything changed, re-execute.

You can . Modify obj in the provided console, and see the view changing.

Open , you should see:

: the entry of the project, doing a little bit of setup.

: this directory contains all React components.

: this observable object manages the logic and data of the application.

The constants QTUM_RPC and SOLAR_REPO are defined in .

Go to the authorization UI to approve it ():

observable
autorun
try this example on codepen.io
http://localhost:3000
src/index.ts
src/views
src/Store.ts
config/development.js
http://localhost:9899/
HRC20 Token we deployed previously
mobx.js
https://github.com/qtumproject/qtumjs-dapp-erc20
CLI App