This tutorial will give an overview of how to read and understand the inputs and outputs of everything solidity smart contract related. In general this will relate to transaction data such as the transaction input and the generated logs of a transaction. For all of the following no ABIs are needed as suggested by similar resources. We will be looking at some use cases and examples mainly focusing on the HRC-20 token standard and the Uniswap V2 protocol.
In the following there will be a lot of hexadecmial trickery so previous understanding will help out. As a short recap if you are unfamiliar:
Our usual system is called decimal and uses a base of 10, which means you have 10 digits (0-9). Hexadecmial means a base of 16 corresponding to the 16 digits you might see in your ETH style wallet address (0-9 A-F). The capitalization doesn't matter (unless you are building a checksum address). When working with hexadecimal be aware of the following sizes:
1Byte = 8bits
4bits = 1 nibble
1 nibble = 1 hex digit
A 0x
prefix simply describes that the following is to be interpreted as hexadecmial, so 0xDEAD
doesn't mean anything has died but the hexadecimal representation of the number 57005
.
On Harmony, as on many other blockchains, your wallet can be represented by two different address formats. A Harmony style format like one1fxq3s96lyjlntelrufq433mpa28397x5x9947n
and an ETH style format like 0x498118175F24BF35E7E3E24158C761EA8F12F8D4
. The underlying data is the exact same. Both addresses are just different representations of the same wallet. With the ETH style you can easily see that the address are 20Bytes and thus it's the simplest way of representing a wallet address. The Harmony style is a format called a bech32 address which originates from BTC. As you might have noticed all BTC addresses begin with bc1
and all Harmony addresses with one1
. This first part is called the Human Readable Part (HRP) and the 1 infix. Where as an address in ETH style might be a wallet on any EVM compatible chain (like ETH, BNB, ONE) you can be certain that if someone hands you a one1...
address that the wallet belongs to a Harmony user.
As most programmers surely have heard before: Calculating with floating point numbers can be inaccurate! This is why the entire blockchain always deals in whole numbers. To send fractions of some currency (be that native ONE or a token like 1ETH) the creators decide on some amount of fixed decimals. For Harmony (as well as many other tokens and chains) this decimal count is 18, so if you receive a transaction with the value 9500000000000000000
you aren't quite rich yet. You haven't received 9.5 quintillion ONE, but only 9.5 ONE, because the first 18 places are fixed decimal places. The same applies to HRC-20 tokens, but remember that a token can define it's own amount of fixed decimal places.
Whenever something is interfacing with a solidity smart contract all values will be encoded in hexadecimal format. In general every value will be of the size 256bit/32Byte which will be called a word from here on (Note: this is true for the purposes of this tutorial but know that this gets more complicated when looking deeper into solidity and it's memory management). Values can be of different types, but the most prominents are: numbers, addresses, strings and arrays of those types. Lets call numbers and addresses simple types and the others offset types for reasons that will become clear later.
Multiple words can be visualized like this:
00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
20: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
40: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000002
60: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000003
80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000004
A0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000005
C0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000006
First of all everything here is in hexadecimal format. The first column lists the offset. As always we start by counting from 0 and increment by 32 since one word is 32 bytes.