Skip to content

This is a sample implementation of an ERC20 like token in a Hedera Consensus Service(HCS) decentralised application

License

Notifications You must be signed in to change notification settings

Mistralteam/hedera-hcs-token-example

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CircleCI codecov License

HCS Token

This is a sample implementation and ERC20 like token in a Hedera Consensus Service(HCS) Decentralized Application.

Overview

The purpose is to show how to build the necessary components to implement a token on HCS.

  • Definition for messages (this is done in protobuf here so that the implementation is easily portable to other languages)
  • A model for the state (Token and addresses primarily)
  • A means to generate messages to send to HCS
  • A means to subscribe to notifications from a mirror node and act upon the state as a result of processing the notifications.
  • Ensuring that duplicate messages aren't processed to avoid double spend.

To keep things simple, it is operated with command line inputs and state is held in a json file.

Process

Operations

  • User runs the application with command line inputs specifying an operation such as construct
  • Inputs are validated and a primitive message specifying an operation such as construct, mint, join or transfer is prepared
  • The operation is signed by the OPERATOR_KEY (private key) found in the .env file
  • The signature is added to the primitive message
  • The public key of the user (derived from OPERATOR_KEY in .env) is added to the primitive message
  • This primitive message is sent to HCS for consensus
  • No changes have been made to state (Except for construct which sets the topicId)

Queries

  • User runs the application with command line inputs specifying a query such as balanceOf
  • The specified query is run against local state and printed to the console

Refresh

This is a "special" command which instructs the application to subscribe to a mirror node and act upon the notifications that result from operations above.

When a notification is received

  • it is parsed
  • the signature is verified
  • operations that can only be performed by the owner are rejected if not initiated by the correct address
  • inputs are checked against state (e.g. does an address have sufficient balance for a transfer)
  • if all successful, local state is updated

Build

The project is built using maven

Linux/MacOs

./mvnw clean install

Windows

mvnw clean install

Configuration

  • copy .env.sample to .env
  • edit .env and set the OPERATOR_ID and OPERATOR_KEY

Run

Test run

Once built, you can try it out with the following commands which will create the token, mint it and then query it.

# construct the token
java -jar hcs-token-example-1.0-run.jar construct TestToken TTT 2
# mint the token
java -jar hcs-token-example-1.0-run.jar mint 1000
# wait for a mirror update
java -jar hcs-token-example-1.0-run.jar refresh
# query information about the token
java -jar hcs-token-example-1.0-run.jar name
java -jar hcs-token-example-1.0-run.jar symbol
java -jar hcs-token-example-1.0-run.jar decimals
java -jar hcs-token-example-1.0-run.jar totalSupply

** Note: Local state is stored in a file called {your operator id}.json, to reset the environment, simply delete the file **

Individual commands

Refresh

Any operation that affects state is only applied as a result of a mirror notification, no local state updates are performed unless they are motivated by a mirror notification. This ensures the consistency of state across all instances of the application. Indeed, if a HCS transaction failed for some reason and local state had been updated previously, there would be a discrepancy in state between application instances.

This update should be run before any queries to ensure the local application state is up to date.

java -jar hcs-token-example-1.0-run.jar refresh

Note: A more complete implementation would run this in the background as a thread for example to ensure local state is updated as promptly as possible

Note: Allow a few seconds after construct to run refresh to allow the new TopicId to be propagated to mirror nodes.

Construct

construct {name} {symbol} {decimals}

This constructs a HCS transaction to construct the token with a name, symbol and decimals. It will automatically create a new HCS TopicId and return it to the console, you can communicate this topic Id to others so they can join your App Net. This will also be stored in {your operator id}.json so that it is remembered by the application.

Note: If you include a space in the token name, be sure to surround the name in quotes (e.g. "my token")

java -jar hcs-token-example-1.0-run.jar construct TestToken TTT 8

Join

join {topicId}

This sets up an App Net instance to join a particular Token by informing it of the Topic Id to use and also sends a HCS transaction to inform other App Net participants of the new user's address, it should be run by anyone wanting to take part in the token.

Note: Construct automatically adds the operator's address to the address book and sets it to be the owner of the token.

java -jar hcs-token-example-1.0-run.jar join topicId (e.g. 0.0.1234)

Note: This step could be optional, but ensures consistency of states across all App Net instances and enables verification of a recipient address in the event of a transfer.

GenKey

This can be used to generate a random key pair so that you can use the public key to test transfers with.

Mint

mint {quantity}

This constructs a HCS transaction to mint the token. When the notification is received (refresh), the token's totalSupply will be set to the amount specified and the balance of the public address derived from the OPERATOR_ID in .env will be set to the same value.

java -jar hcs-token-example-1.0-run.jar mint 1000

Get token name

This returns the name of the token from local state. If this returns empty, you may need to run refresh.

java -jar hcs-token-example-1.0-run.jar name

Get token symbol

This returns the symbol of the token from local state. If this returns empty, you may need to run refresh.

java -jar hcs-token-example-1.0-run.jar symbol

Get token decimals

This returns the decimals of the token from local state. If this returns empty, you may need to run refresh.

java -jar hcs-token-example-1.0-run.jar decimals

Get token totalSupply

This returns the totalSupply of the token from local state. If this returns empty, you may need to run refresh.

java -jar hcs-token-example-1.0-run.jar totalSupply

Get address balance

balanceOf {address}

This returns the balance of the specified address from local state. If this returns a value you weren't expecting, you may need to run refresh.

java -jar hcs-token-example-1.0-run.jar balanceOf input_your_public_key_here

Transfer

transfer {address} {quantity}

This constructs a HCS transaction to transfer tokens from one address to another. When the notification is received (refresh), both addresses' balances are updated.

Note: The from address is set to the public key derived from the OPERATOR_KEY in the .env file.

java -jar hcs-token-example-1.0-run.jar transfer 302a300506032b65700321009308a434a9cac34e2f7ce95fc671bfbbaa4e43760880c4f1ad5a58a0b3932232 20

Approve

approve {spender} {amount}

This constructs a HCS transaction to approve another address as a spender up to a given amount. When the notification is received (refresh), the spender is added to the list of allowances.

Note: The from address is set to the public key derived from the OPERATOR_KEY in the .env file.

java -jar hcs-token-example-1.0-run.jar approve 302a300506032b65700321009308a434a9cac34e2f7ce95fc671bfbbaa4e43760880c4f1ad5a58a0b3932232 20

Allowance

allowance {owner} {spender}

This queries local state and returns the current allowance for a given pair of addresses

java -jar hcs-token-example-1.0-run.jar allowance 302a300506032b65700321006e42135c6c7c9162a5f96f6d693677742fd0b3f160e1168cc28f2dadaa9e79cc 302a300506032b65700321009308a434a9cac34e2f7ce95fc671bfbbaa4e43760880c4f1ad5a58a0b3932232

Increase Allowance

increaseAllowance {spender} {addedValue}

This constructs a HCS transaction to increase the allowance for a given address. When the notification is received (refresh), the allowance for the spender address is increased accordingly.

java -jar hcs-token-example-1.0-run.jar increaseAllowance 302a300506032b65700321009308a434a9cac34e2f7ce95fc671bfbbaa4e43760880c4f1ad5a58a0b3932232 20

Decrease Allowance

decreaseAllowance {spender} {addedValue}

This constructs a HCS transaction to decrease the allowance for a given address. When the notification is received (refresh), the allowance for the spender address is decreased accordingly.

java -jar hcs-token-example-1.0-run.jar decreaseAllowance 302a300506032b65700321009308a434a9cac34e2f7ce95fc671bfbbaa4e43760880c4f1ad5a58a0b3932232 20

Transfer From

transferFrom {fromAddress} {toAddress} {amount}

This constructs a HCS transaction to transfer tokens from an address using an allowance. When the notification is received (refresh), the balance of the fromAddress is deducted amount, the balance of toAddress is increased by amount and finally, the allowance of the operator is deducted amount.

java -jar hcs-token-example-1.0-run.jar transferFrom 302a300506032b65700321006e42135c6c7c9162a5f96f6d693677742fd0b3f160e1168cc28f2dadaa9e79cc 302a300506032b65700321009308a434a9cac34e2f7ce95fc671bfbbaa4e43760880c4f1ad5a58a0b3932232 10

Burn

burn {amount}

This constructs a HCS transaction to burn tokens from the operator's account When the notification is received (refresh), the balance operator's account is deducted the amount.

java -jar hcs-token-example-1.0-run.jar burn 302a300506032b65700321006e42135c6c7c9162a5f96f6d693677742fd0b3f160e1168cc28f2dadaa9e79cc 302a300506032b65700321009308a434a9cac34e2f7ce95fc671bfbbaa4e43760880c4f1ad5a58a0b3932232 10

Acting as another user

If you would like to pretend to be another user (or node) of the App Net, you will need to:

  • Create a Hedera Account Id with sufficient funds to run HCS transactions
  • Update your .env file with the new account details

then

java -jar hcs-token-example-1.0-run.jar join topicId (e.g. 0.0.1234)

followed by

java -jar hcs-token-example-1.0-run.jar refresh

to update your local state from notifications

From then on, any operations you perform will be performed with this user's address.

Local state

As mentioned above, local state is only updated as a result of a mirror notification. You can try this for yourself by sending a Construct command and checking the contents of the {operator id}.json file.

At this stage, the file should only contain the created Topic Id.

Then, run a mint command and check the state file again, no changes.

Finally, run a refresh command to see the state file updated as a result of mirror notifications.

run.sh

This is sample shell script to run through all the operations, to execute it, first setup two accounts on the Hedera network, then type the following in a command prompt.

export OPERATOR_SECRET_1={input your first account private key}
export OPERATOR_PUBLIC_1={input your first account public key}
export OPERATOR_ID_1={input your first account id}
export OPERATOR_SECRET_2={input your second account private key}
export OPERATOR_PUBLIC_2={input your second account public key}
export OPERATOR_ID_2={input your second account id}

if you don't set these variables up, the script will prompt you for them

then

./run.sh

The script will prompt whether you want to rebuild the project (maven). Then it will prompt whether to delete local state files (*.json). It will finally run through all the supported operations.

About

This is a sample implementation of an ERC20 like token in a Hedera Consensus Service(HCS) decentralised application

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 59.9%
  • Java 27.6%
  • Vue 10.8%
  • Shell 1.1%
  • HTML 0.6%