Interacting with Tolar HashNET (part 2)

Igor Jerkovic
TolarHashNETDev
Published in
8 min readNov 9, 2021

This is a continuation post for part 1, which is the prerequisite for this tutorial — click here.

In this post we will show how to generate a new Tolar address, request Tolar Testnet tokens, and finally send a transaction to another address. Also, for any interaction with the Tolar HashNET blockchain that alters the state, this is a requirement, as without funds such transactions would not pass — since all transactions that alter the blockchain state need to pay gas fees to the network that is executing the transactions, which are the Tolar master nodes (briefly mentioned in part1).

Generating a new Tolar private/public key pair

When someone in the crypto space mentions “just create a new address, its straightforward” — they usually refer to creating a private key which is known only to the person (or entity) that generated it. From the private key, a public key is generated, using an algorithm called Elliptic Curve Digital Signature Algorithm (ECDSA). From the public key, an address is generated using a oneway hashing function (sha3).

Let’s create a new Tolar address (private/public key pair): First make sure the thin node binary is running. If it is not, simply start it:

Open up a new terminal tab, from which the grpcurl tool will be used. Just a reminder on listing all the available services:

Today we will concentrate on tolar.proto.AccountService since it is the service that has all the methods for key pair handling and signing transactions. Lets take a glance at available methods:

If you are creating a new keystore (that is pointing to a new keystore directory which is not initialized), this request will initialize it:

If you are getting an error, common error is that in your config a wrong path to the keystore directory is specified and/or the keystore directory might be missing — in which case simply create a directory and set it in the config.json and re-run the thin node binary with the new config file. Also, if keystore directory is already there, this request will return error message indicating that keystore already exists. In that case, we need to send Open request to unlock the keystore before using it. Keystore can’t be used without opening it first.

Since we called the Create method, it also opened the keystore, but if the keystore is closed, you will need to call the Open method as well. If the keystore is already opened you will get an error:

Also, we initialized the keystore without a master password (which is not recommended). This master password (if defined) will be needed when opening the keystore and when signing/sending transactions. In order to create a keystore with a master password do it like this:

Now, lets create a new private/public key pair, aka a new Tolar address:

The response is base64 encoded, lets see how it looks decoded. Copy the address from response (“NTQ1MjU3Yjk3ZTNhMzBjMTFmNGMwNGU5ZmUzZTAwZGI0ZDAzZTk4ZmExOWFkYjRkNWM=”):

You can also use some online encoder/decoder for base64 like this one.

NTQ1MjU3Yjk3ZTNhMzBjMTFmNGMwNGU5ZmUzZTAwZGI0ZDAzZTk4ZmExOWFkYjRkNWM= is base64 encoded form of:

545257b97e3a30c11f4c04e9fe3e00db4d03e98fa19adb4d5c

which is the Tolar address in the most used form.

Tolar address format

Tolar address is formatted in the following way:

Capital letter T (1 byte) — unique address space (20 bytes) — checksum part (4 bytes)

In the example above, 545257b97e3a30c11f4c04e9fe3e00db4d03e98fa19adb4d5c

consists of the starting 54 (which is ASCII code for capital letter T),

next 20 bytes are 5257b97e3a30c11f4c04e9fe3e00db4d03e98fa1

and the checksum is 9adb4d5c (which is calculated by calculating a sha3 hash of the previous 20 bytes, and then hashing that hash once more with sha3, and finally taking the rightmost 4 bytes of the second sha3 output)

The unique address directly maps to an Ethereum address and is compatible with it, meaning that anyone having an Ethereum private key, its private key can sign Tolar transactions — only the public key (the address) would need to be used in Tolar format, for which we also have a convenient address converter on the official Tolar website.

Sending your first TOL tokens

In order to send some Tolar tokens, you will first need to obtain testnet tokens.

We have built a testnet faucet just for this purpose. Go to the faucet and paste your Tolar address in the request form and simply request the tokens. Here is the faucet.

After successfully requesting TOL tokens, wait a few seconds for the transaction to end up on the blockchain. You can check the balance of your address on the testnet blockchain explorer. Just copy/paste your address in the search text field and refresh the page until you see your address balance changed.

Lets see how to fetch the balance of the address from this tutorial via a gRPC request through thin node.

For balance inquiry we’ll be reading blockchain state, for which no gas is needed to be paid. The balance read request resides on tolar.proto.BlockchainService. As a reminder from part1, blockchain service consists of these methods:

Lets make a GetBalance request. In our case specifically:

grpcurl --plaintext -d '{"address": "NTQ1MjU3Yjk3ZTNhMzBjMTFmNGMwNGU5ZmUzZTAwZGI0ZDAzZTk4ZmExOWFkYjRkNWM="}' 127.0.0.1:9200 tolar.proto.BlockchainService.GetLatestBalance

Again the response is base64 encoded. Decoded output would be in hex, and we want it in decimal format, so we can get it like this:

python3 -c “import base64; print(int.from_bytes(base64.b64decode(‘ArXjrxaxiAAA’), ‘big’))”

This is how to convert it from terminal. You can also do this by converting the decimal to hex number and then the output hex number, can be converted to base64.

The balance is 50 * 10¹⁸ AttoTolars or simply 50 TOL. 1 TOL equals 10¹⁸ AttoTOL. Atto is a common way of displaying 10^-18. The faucet is dripping 50 TOL per request so this result makes sense.

Now lets send 10 TOL to another address.

Generate a new address first:

Our new generated address is 54e5b4fd17386b305673c47f2eddc55824953b0720abca4584

Lets check its balance first (which should be 0):

grpcurl — plaintext -d ‘{“address”: “NTRlNWI0ZmQxNzM4NmIzMDU2NzNjNDdmMmVkZGM1NTgyNDk1M2IwNzIwYWJjYTQ1ODQ=”}’ 127.0.0.1:9200 tolar.proto.BlockchainService.GetLatestBalance

The result is:

{“balance”: “AA==”}

Which is 0 in base64.

Now lets send 10 TOL from 545257b97e3a30c11f4c04e9fe3e00db4d03e98fa19adb4d5c

We will use tolar.proto.AccountService.SendFundTransferTransaction

By examining the gRPC documentation for AccountService, you will notice few arguments need to be passed in (sender_address, receiver_address, amount, sender_address_password, gas, gas_price and nonce).

The sender and receiver address in base64 format can be found in this post. The amount we want to send — 10 TOL is 10¹⁹ AttoTOL, which we need to encode to base64. In python this can be done like this:

python3 -c “import base64; b = int(10000000000000000000); print(‘encoded “{}”: {}’.format(b, base64.b64encode(b.to_bytes((b.bit_length() + 7) // 8, ‘big’))))”

The output is “iscjBInoAAA=”.

For gas we will set 21000 AttoTOL which is the minimum gas price requirement for simple transfers (simple meaning that basic value transfer is happening, and not a contract interaction).

Again use the above python script and 21000 is “Ugg=” in base64.

For gas_price we need to set at least 10¹² AttoTOL as this is the minimum for making a transaction pass on the public Tolar testnet. For someone running their own private testnet this value could be set upon initiating the master nodes.

10¹² is “6NSlEAA=” in base64.

For nonce we need to set 0 which is empty string. With the nonce you are setting the order of your transactions in which they will execute. If you would like to know more about the nonce read this article.

Now we have everything ready to send our first transaction:

grpcurl — plaintext -d ‘{“sender_address”: “NTQ1MjU3Yjk3ZTNhMzBjMTFmNGMwNGU5ZmUzZTAwZGI0ZDAzZTk4ZmExOWFkYjRkNWM=”, “receiver_address”: “NTRlNWI0ZmQxNzM4NmIzMDU2NzNjNDdmMmVkZGM1NTgyNDk1M2IwNzIwYWJjYTQ1ODQ=”, “amount”: “iscjBInoAAA=”, “gas”: “Ugg=”, “gas_price”: “6NSlEAA=”, “nonce”: “”}’ 127.0.0.1:9200 tolar.proto.AccountService.SendFundTransferTransaction

The response is:

{“transactionHash”: “MDAzMTlhNjhjYTdlYTM4MTA4YTU4MzhjMTE4ZGQyMjBlYzk0NjE5NDBiZTUwMWE2OGJkYmVmNDVhOWZlNjI5YQ==”}

We can now make a read request to the BlockchainService and once the transaction ends up on the blockchain inspect in what block it ended up.

grpcurl — plaintext -d ‘{“transaction_hash”: “MDAzMTlhNjhjYTdlYTM4MTA4YTU4MzhjMTE4ZGQyMjBlYzk0NjE5NDBiZTUwMWE2OGJkYmVmNDVhOWZlNjI5YQ==”}’ 127.0.0.1:9200 tolar.proto.BlockchainService.GetTransactionReceipt

The response is:

{“blockHash”: “NjZiMDIzMzZhMzFjOTY3YzY5NjFmMGQyN2VhZDI3MjliYzExYjIzNDdkZWU1MGMzZjFmZGZkOWZlMzBkYjJkOQ==”,“blockIndex”: “2213108”,“transactionHash”: “MDAzMTlhNjhjYTdlYTM4MTA4YTU4MzhjMTE4ZGQyMjBlYzk0NjE5NDBiZTUwMWE2OGJkYmVmNDVhOWZlNjI5YQ==”,“senderAddress”: “NTQ1MjU3Yjk3ZTNhMzBjMTFmNGMwNGU5ZmUzZTAwZGI0ZDAzZTk4ZmExOWFkYjRkNWM=”,“receiverAddress”: “NTRlNWI0ZmQxNzM4NmIzMDU2NzNjNDdmMmVkZGM1NTgyNDk1M2IwNzIwYWJjYTQ1ODQ=”,“newAddress”: “NTQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMjMxOTllMmI=”,“gasUsed”: “Ugg=”}

The block hash is 66b02336a31c967c6961f0d27ead2729bc11b2347dee50c3f1fdfd9fe30db2d9

The block index is 2213108.

Lets also make a balance inquiry on the receiver address:

grpcurl — plaintext -d ‘{“address”: “NTRlNWI0ZmQxNzM4NmIzMDU2NzNjNDdmMmVkZGM1NTgyNDk1M2IwNzIwYWJjYTQ1ODQ=”}’ 127.0.0.1:9200 tolar.proto.BlockchainService.GetLatestBalance

The response is:

{“balance”: “iscjBInoAAA=”}

Lets decode this output:

python3 -c “import base64; print(int.from_bytes(base64.b64decode(‘iscjBInoAAA=’), ‘big’))”

As expected the balance of 54e5b4fd17386b305673c47f2eddc55824953b0720abca4584 is now 10000000000000000000 AttoTOL (or in shorter form 10 TOL).

Lets also check the balance of sender address which was 50 TOL before making this transaction:

grpcurl — plaintext -d ‘{“address”: “NTQ1MjU3Yjk3ZTNhMzBjMTFmNGMwNGU5ZmUzZTAwZGI0ZDAzZTk4ZmExOWFkYjRkNWM=”}’ 127.0.0.1:9200 tolar.proto.BlockchainService.GetLatestBalance

The response:

{“balance”: “AirR8K6jV4AA”}

Using our python script to convert back to decimal:

python3 -c “import base64; print(int.from_bytes(base64.b64decode(‘AirR8K6jV4AA’), ‘big’))”

We get: 39979000000000000000

A careful reader may ask, why didn’t we get 40*10¹⁸ as an answer. The reason is that the sender address also paid 21000 * 10¹² AttoTOL for gas fees.

Recap

In this blog post we have shown how to generate new private/public keypairs and how to send transactions. As making gRPC requests from terminal might be a bit cumbersome, in the next blog post we will focus on using the web3js library which is a collection of modules that contain specific functionality for the Tolar ecosystem. For anyone using Ethereum’s web3js it should be quite familiar.

--

--