The Power of Native Hedera Tokens as ERC-20 Tokens: A step-by-step guide

In this tutorial, you’ll learn how to make Hedera native tokens work like Ethereum's ERC-20 tokens using the Hashio JSON-RPC instance.


Prerequisites


Table of Contents


Project Setup

To make the setup process simple, you'll use a pre-configured token wrapper project from the token-wrapper repository.

Open a terminal window and navigate to your preferred directory where your project will live. Run the following command to clone the repo and install dependencies to your local machine:

git clone https://github.com/Swiss-Digital-Assets-Institute/token-wrapper.git
cd token-wrapper
npm install

The dotenv package is used to manage environment variables in a separate .env file, which is loaded at runtime. This helps protect sensitive information like your private keys and API secrets, but it's still best practice to add .env to your .gitignore to prevent you from pushing your credentials to GitHub.


Project Configuration

In this step, you will update and configure the Hardhat configuration file that defines tasks, stores Hedera account private key information, and Hashio Testnet RPC URL. First, rename the .env.example file to .env. and update the .env files with the following code.

Environment Variables

The .env file defines environment variables used in the project. The MY_ACCOUNT_ID and MY_PRIVATE_KEY variables contains the ECDSA Account ID and DER Encoded Private Key, respectively for the Hedera Testnet account. The HEX_ENCODED_PRIVATE_KEY variable contains the HEX Encoded Private Key.

The JSON_RPC_RELAY_URL variable contains the HashIO Testnet endpoint URL. This is the JSON-RPC instance that will submit the transactions to the Hedera test network to test, create and deploy your smart contract.

.env
MY_ACCOUNT_ID =
MY_PRIVATE_KEY = 
HEX_ENCODED_PRIVATE_KEY = 
JSON_RPC_RELAY_URL = https://testnet.hashio.io/api

Project Contents

In this step, you'll examine the descriptions of the project contents in your existing project. If you don't need to review the project contents, you can proceed directly to Running the project.

This directory contains compiled smart contracts used for generating TypeScript bindings with Typechain. We compile these contracts using Hardhat, a versatile Ethereum development tool. You'll find the configuration in hardhat.config.js.

Think of Hardhat as your all-in-one environment for Ethereum development tasks like compiling, deploying, testing, and debugging.


Running the project

Now that you have your project set up and configured, we can run it.

To do so, run the following command:

npm run compile
ts-node scripts/ERC20.ts

The first command compiles the smart contracts and generates the typescript bindings. The second command runs the ERC20 script.

To see the transactions on the Hedera network, you can use the Hedera Testnet Explorer.

Note: At the top of the explorer page, remember to switch the network to TESTNET before you search for the transaction.

console check ✅
- The token ID is: 0.0.2576296
- Alice account id created: 0.0.2576297
- tokenIdAddress 0000000000000000000000000000000000274fa8
- accountAddress 0x398520c72090d7aaBe37e2c49ab1cAe8e662AEa0
- contractVaultId 0.0.2576303
- tokenAssociateReceipt SUCCESS
- Transfer {
	to: '0x0000000000000000000000000000000000274Fa8',
	from: '0x398520c72090d7aaBe37e2c49ab1cAe8e662AEa0',
	contractAddress: '0x0000000000000000000000000000000000274Fa8',
	transactionIndex: 1,
	gasUsed: BigNumber { _hex: '0x0c3500', _isBigNumber: true },
	logsBloom: '0x00000000000000040000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000080000000000000000000000008000000000000000000000000000000000000000000000000000020000000000000000000100000000000000000000010000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000080000000000000000',
	blockHash: '0xe9714ef3227d3c809981ce42eb81d9c0fcd8e8082f4931628ab1d296b3e0d5bd',
	transactionHash: '0x5b730724e757a45b21f833a2f8bf8ae510cb7fa61d5defcde68f4432dfcf9940',
	logs: [
	{
		transactionIndex: 1,
		blockNumber: 2490825,
		transactionHash: '0x5b730724e757a45b21f833a2f8bf8ae510cb7fa61d5defcde68f4432dfcf9940',
		address: '0x0000000000000000000000000000000000274Fa8',
		topics: [Array],
		data: '0x000000000000000000000000000000000000000000000000000000000000000a',
		logIndex: 0,
		blockHash: '0xe9714ef3227d3c809981ce42eb81d9c0fcd8e8082f4931628ab1d296b3e0d5bd'
	}
	],
	blockNumber: 2490825,
	confirmations: 1,
	cumulativeGasUsed: BigNumber { _hex: '0x0c3500', _isBigNumber: true },
	effectiveGasPrice: BigNumber { _hex: '0x03179fcad000', _isBigNumber: true },
	status: 1,
	type: 2,
	byzantium: true,
	events: [
	{
		transactionIndex: 1,
		blockNumber: 2490825,
		transactionHash: '0x5b730724e757a45b21f833a2f8bf8ae510cb7fa61d5defcde68f4432dfcf9940',
		address: '0x0000000000000000000000000000000000274Fa8',
		topics: [Array],
		data: '0x000000000000000000000000000000000000000000000000000000000000000a',
		logIndex: 0,
		blockHash: '0xe9714ef3227d3c809981ce42eb81d9c0fcd8e8082f4931628ab1d296b3e0d5bd',
		args: [Array],
		decode: [Function (anonymous)],
		event: 'Transfer',
		eventSignature: 'Transfer(address,address,uint256)',
		removeListener: [Function (anonymous)],
		getBlock: [Function (anonymous)],
		getTransaction: [Function (anonymous)],
		getTransactionReceipt: [Function (anonymous)]
	}
	]
}
- Balance from Alice using the SDK 10
- Balance from Alice using the ERC20 10
- Associate {
	to: '0x0000000000000000000000000000000000274faF',
	from: '0x398520c72090d7aaBe37e2c49ab1cAe8e662AEa0',
	contractAddress: '0x0000000000000000000000000000000000274faF',
	transactionIndex: 0,
	gasUsed: BigNumber { _hex: '0x0c3500', _isBigNumber: true },
	logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
	blockHash: '0x2a7393098da0e5f82da2230dfecb124b5be86d52bea2bb45924658c8c8a83ad3',
	transactionHash: '0x513f8ecbd25c8326c52c161e47d56f9f40d59e179ca670ec49bf0d316561d863',
	logs: [],
	blockNumber: 2490828,
	confirmations: 1,
	cumulativeGasUsed: BigNumber { _hex: '0x0c3500', _isBigNumber: true },
	effectiveGasPrice: BigNumber { _hex: '0x03179fcad000', _isBigNumber: true },
	status: 1,
	type: 2,
	byzantium: true,
	events: []
}
- Deposit tokens to the Vault contract {
	to: '0x0000000000000000000000000000000000274Fa8',
	from: '0x398520c72090d7aaBe37e2c49ab1cAe8e662AEa0',
	contractAddress: '0x0000000000000000000000000000000000274Fa8',
	transactionIndex: 0,
	gasUsed: BigNumber { _hex: '0x0c3500', _isBigNumber: true },
	logsBloom: '0x00800000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000008000000000000000000000000000000000000000000000004000000000000000000000000100000000000000000000010000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000080000000000000000',
	blockHash: '0xb8553decd07d595c77eaa17c019e0f506ab0632da614971b006a6b1353d5e57a',
	transactionHash: '0x3b312bb272236d00e750294d81d3c7441208b84c9f6f97b2a25757d19c0b444f',
	logs: [
	{
		transactionIndex: 0,
		blockNumber: 2490831,
		transactionHash: '0x3b312bb272236d00e750294d81d3c7441208b84c9f6f97b2a25757d19c0b444f',
		address: '0x0000000000000000000000000000000000274Fa8',
		topics: [Array],
		data: '0x00000000000000000000000000000000000000000000000000000000000003e8',
		logIndex: 0,
		blockHash: '0xb8553decd07d595c77eaa17c019e0f506ab0632da614971b006a6b1353d5e57a'
	}
	],
	blockNumber: 2490831,
	confirmations: 2,
	cumulativeGasUsed: BigNumber { _hex: '0x0c3500', _isBigNumber: true },
	effectiveGasPrice: BigNumber { _hex: '0x03179fcad000', _isBigNumber: true },
	status: 1,
	type: 2,
	byzantium: true,
	events: [
	{
		transactionIndex: 0,
		blockNumber: 2490831,
		transactionHash: '0x3b312bb272236d00e750294d81d3c7441208b84c9f6f97b2a25757d19c0b444f',
		address: '0x0000000000000000000000000000000000274Fa8',
		topics: [Array],
		data: '0x00000000000000000000000000000000000000000000000000000000000003e8',
		logIndex: 0,
		blockHash: '0xb8553decd07d595c77eaa17c019e0f506ab0632da614971b006a6b1353d5e57a',
		args: [Array],
		decode: [Function (anonymous)],
		event: 'Transfer',
		eventSignature: 'Transfer(address,address,uint256)',
		removeListener: [Function (anonymous)],
		getBlock: [Function (anonymous)],
		getTransaction: [Function (anonymous)],
		getTransactionReceipt: [Function (anonymous)]
	}
	]
}
- Balance of the Vault contract before the withdraw 1000
- Withdraw tokens from the Vault contract {
	to: '0x0000000000000000000000000000000000274faF',
	from: '0x398520c72090d7aaBe37e2c49ab1cAe8e662AEa0',
	contractAddress: '0x0000000000000000000000000000000000274faF',
	transactionIndex: 0,
	gasUsed: BigNumber { _hex: '0x0c3500', _isBigNumber: true },
	logsBloom: '0x00800000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000008000000000000000000000000000000000000000000000004000000000000000000000000100000000000000000000010000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000080000000000000000',
	blockHash: '0x3de5a72720f9b221d5e436b2ccaf3b1219436d653a943528a20569ba94ee397b',
	transactionHash: '0x7a661f21f9dd4a99764b4f5f216f29ff5a20207cd4f57d0ca1a25f12af2e6d2b',
	logs: [
	{
		transactionIndex: 0,
		blockNumber: 2490835,
		transactionHash: '0x7a661f21f9dd4a99764b4f5f216f29ff5a20207cd4f57d0ca1a25f12af2e6d2b',
		address: '0x0000000000000000000000000000000000274Fa8',
		topics: [Array],
		data: '0x00000000000000000000000000000000000000000000000000000000000003e8',
		logIndex: 0,
		blockHash: '0x3de5a72720f9b221d5e436b2ccaf3b1219436d653a943528a20569ba94ee397b'
	}
	],
	blockNumber: 2490835,
	confirmations: 1,
	cumulativeGasUsed: BigNumber { _hex: '0x0c3500', _isBigNumber: true },
	effectiveGasPrice: BigNumber { _hex: '0x03179fcad000', _isBigNumber: true },
	status: 1,
	type: 2,
	byzantium: true,
	events: [
	{
		transactionIndex: 0,
		blockNumber: 2490835,
		transactionHash: '0x7a661f21f9dd4a99764b4f5f216f29ff5a20207cd4f57d0ca1a25f12af2e6d2b',
		address: '0x0000000000000000000000000000000000274Fa8',
		topics: [Array],
		data: '0x00000000000000000000000000000000000000000000000000000000000003e8',
		logIndex: 0,
		blockHash: '0x3de5a72720f9b221d5e436b2ccaf3b1219436d653a943528a20569ba94ee397b',
		removeListener: [Function (anonymous)],
		getBlock: [Function (anonymous)],
		getTransaction: [Function (anonymous)],
		getTransactionReceipt: [Function (anonymous)]
	}
	]
}
- Balance of the Vault contract after the withdraw 0

Congratulations! 🎉 You have successfully learned to use native Hedera tokens as ERC20 tokens. Feel free to reach out if you have any questions:

Last updated