My first token

Filip Koprivec
5 min readJan 16, 2023

--

Before starting, make sure that you have your .env file in order (it should contain the private key, otherwise the hardhat will compile).

The contract

Let’s start with a simple token.

Create a new file in the contracts/ directory and name it MyToken.sol and write the following code in it:

Run npx hardhat compile to compile our new contract. You should see something like this:

HURRAY! You just successfully wrote your first smart contract.

The code

Let’s dissect the contract code a bit, line by line.

// SPDX-License-Identifier: MIT

Solidity encourages programmers to use machine-readable SPDX license identifiers. In general, it is a good idea to include a license in your source code, and we will use a common MIT license.

pragma solidity ^0.8.9;

The compiler pragma is used to specify the version of the solidity language that the contract is written in.

We will use a quite recent version (0.8.9) as a starting point, but allow building contracts with newer versions of 0.8 as well.

This is the main part of our contract. We first define a contract called MyToken, even though the contract has the same name as the file, this is not required for the contract to be visible and usable to external contracts.

If you are familiar with popular object-oriented languages, you can think of a contract as a class.

We first declare and assign the name and symbol instance variables (fields). We are not going to change them (yet), so we declare them as constants and use public access modifier, thereby instructing the compiler, that they can be read (but not set) by anyone. Since solidity is a statically typed language, we also need to specify the type of the variables.

The next two lines only declare variables but do not assign any values to them. Think of them as fields in java and we will assign values to them in the constructor. Technically, they are implicitly assigned a 0 value when first used, as the EVM (Ethereum virtual machine — the virtual machine validators are running) automatically assigns 0 value to yet unused values when needed.

The types of variables are:

  • uint256: Unsigned integer of 256 bits, this is the processor word size on EVM.
  • address: Type denoting a public address on the blockchain. This can be an account address or a contract address.
constructor(uint256 _totalSupply, address _owner) {
totalSupply = _totalSupply;
owner = _owner;
}

Constructor is a special function that is called when the contract is created (when a contract instance is created). In our case, we just assign values from the arguments to the fields. We use the solidity coding style, where argument names start with an underscore.

Tests

Programming on the blockchain can be a dangerous business. The code is generally¹ immutable and cannot be changed once deployed, this means we can’t redeploy a buggy code at a later point. Even worse, if the contract is deployed, it is essentially public and anyone can exploit any bugs in the code. A quick google search can show how expensive the bugs can get.

To try and prevent this as much as possible, we will try to test our code and at least remove some obvious bugs and malfunctions².

Create a new file in the test/ directory and name it MyTokenTest.ts and write the following code in it:

Run npx hardhat test test the contract. You should see something green, like this:

HURRAY!

Let’s see what the test is really doing.

import { ethers } from 'hardhat';
import { BN } from "bn.js";
import { expect } from 'chai';

We first import the necessary things we will need for tests.

function bn(n: any){
return new BN(n.toString());
}

Since typescript (and javascript) uses double precision floating point numbers as numbers, we will use BN from bn.jsto represent our numbers.

const MyToken: MyTokenContract = artifacts.require("MyToken");

And finally, we use typechain artifacts to lever the awesomeness of typechecking directly in tests. Just import the contract from artifacts and boom, you get autocompletion and type checking for free.

describe("Token contract", function () {
it("Deployment should assign the total supply of tokens and owner", async function () {
...
});
});

Tests are grouped in describe blocks and each test is a seperate it block. The first arguments are used to indicate a human-readable description of the test. Each describe can have multiple it or describe blocks. Use them to structure tests in a reasonable way.

This is the meat of our test. We first get the first account from the list of accounts available in the hardhat network and assign it to owner variable. Next, we get the contract factory for our MyToken contract and assign it to Token variable.

We then deploy the contract using the deploy method of the Token factory. This calls the constructor with the arguments we pass in. The third parameter is optional during tests and can be used to specify additional data. We specify, that the transaction is sent from the owner account.

After the contract is deployed, we would expect, that both totalSupply and owner fields are set correctly.

Each public instance field in solidity contract implicitly defines a function with the same name, that can be used to read the value of the field. We use this to read the values of the fields and compare them to the expected values. As we use typescript, big numbers are automatically compared using the correct equality method.

Remix

The whole process can also be repeated in the remix IDE. Create a new project and folders contracts and test in it to match the structure of our project. Copy the MyToken.sol and MyTokenTest.ts files to the corresponding folders.

Open the solidity tab on the left side and select the compiler version between 0.8.9 and 0.8.XX.

Compile the MyToken.sol file and you should see an additional artifacts folder in the contracts folder.

Right-click on the MyTokenTest.ts file in the file explorer tab and click Run from the context menu and you should see the same result in the console as in the hardhat test.

Yay, you made your first token, well done.

Check the next part of the tutorial, where we release a proper ERC20 token that gets displayed nicely in blockscout.

[1]: There are patterns that can be used to make code mutable, but this is not the focus of this tutorial. Stay tuned for more.

[2]: There is a growing community of researchers that work with developing tools that try to assert, that contracts are provably correct. If you want to join them, shoot me an email.

--

--