Introduction to Tokens

Learn what tokens are, how to create them by using more-advanced Solidity data structures, and how to secure them by using third-party libraries like OpenZeppelin.

By the end of this post, readers will be able to:

  • Explain what a blockchain token is and how it can be used.
  • Distinguish the general difference between a coin and a token.
  • Build a Solidity smart contract that creates a simple token.
  • Use the mapping data structure to associate customer addresses with their individual information.
  • Import third-party OpenZeppelin libraries from GitHub into a Solidity smart contract.
  • Explain the roles that inheritance and composition play in object-oriented programming (OOP).

Let’s start off by introducing the idea of tokenomics, the nature of tokens on the blockchain and what gives them value, the relationship between tokens and smart contracts, the loose definitions of coins and tokens, and several examples.

Tokenomics and Tokenization

Tokenomics, or the economics of tokens, refers to how blockchain tokens get conceptualized, produced, valued, distributed, traded, and used. A blockchain token represents an asset or utility on a blockchain platform. Essentially, it’s a symbol of value.

On a blockchain, an asset can be tokenized, or represented as a token. Commodities, like gold and silver, and currencies, like the US dollar, can all be represented as tokens. Other types of goods and assets can also be tokenized. These include real-estate properties, cars, and even works of art. In fact, virtually anything that holds value can be represented as a token on a blockchain.

We create tokens on the Ethereum blockchain by using smart contracts. The token itself is the symbol of value. The ownership of a token by a blockchain participant (and thus their ownership of the value that the token symbolizes) gets represented in the participant’s wallet. The rules and logic that create and maintain the token get encoded in a token smart contract.

Imagine a digital wallet that contains records of all the assets that an individual owns, both digital and physical, in a single place. They can manage their home ownership, car payments, artwork, investments, video game items, and more with math that cryptographically proves their ownership of these items and that verifies any transactions associated with them.

Some people in the blockchain community use the terms token and coin interchangeably. However, they represent two similar but distinct concepts.

  • Coins represent cryptocurrencies that are native to their blockchains, such as BTC and ETH.
  • By contrast, tokens represent any tangible or intangible asset of value. They get created by deploying smart contracts over existing blockchain platforms.
  • Unlike most cryptocurrency coins, a token that holds a currency value can be designed to maintain a stable value.
    • These tokens, called stablecoins, are typically backed by a fiat, or government, currency. A stablecoin company often holds a stable currency, like US dollars, in its bank account and then issues tokens that are backed by those dollars.

Building Tokens with Solidity

Mapping

Think of a mapping as an association between two variables. For instance, we can map account balances to account addresses. The developer can thus associate a balance with a specific address and then retrieve the current balance for that account at any time.

  • A mapping conceptually resembles a Python dictionary with key-value pairs.

In Solidity, a mapping is a variable type that we define by using the following syntax:

`mapping(_KeyType => _ValueType)`

Mappings are flexible data types that allow us to efficiently link pieces of data together.

  • To send a transaction to the Ethereum blockchain, we have to pay a gas fee. That is, we have to pay for the computational power that’s required to execute the transaction.
  • A smart contract is a type of blockchain transaction. (And normally, it’s one that costs more gas than simply transferring ETH!)
  • Using a mapping generally requires less gas than using an array.
  • For that reason, and because they provide a straightforward way to link user accounts with their token balances, mappings are one of the primary data types used to create token contracts.

Create a Token Contract

pragma solidity ^0.5.0;

contract ArcadeToken {
    address payable owner = msg.sender;
    string public symbol = "ARCD";
    uint public exchange_rate = 100;

    mapping(address => uint) balances;

    function balance() public view returns(uint) {
        return balances[msg.sender];
    }

    function transfer(address recipient, uint value) public {
        balances[msg.sender] -= value;
        balances[recipient] += value;
    }

    function purchase() public payable {
        uint amount = msg.value * exchange_rate;
        balances[msg.sender] += amount;
        owner.transfer(msg.value);
    }

    function mint(address recipient, uint value) public {
        require(msg.sender == owner, "You do not have permission to mint tokens!");
        balances[recipient] += value;
    }
}

All the functions included in the token contract above gets displayed and accessed in the Remix IDE.

For testing purposes after deployment, use two addresses in the Remix IDE to test both the transfer of tokens and the require function that’s associated with the mint function.

Call the balance function several times to show how the balances of the different accounts change as different contract functions get used.

Importing OpenZeppelin Contracts

We can use third-party libraries to make our smart contracts both more secure and more efficient to write.

OpenZeppelin is a company that specializes in developing secure smart contracts that use Ethereum community standards. They provide several libraries for smart contract development.

The OpenZeppelin project includes many standardized smart contracts that the blockchain development community can adapt, customize, and build from. Developers can thus write more-secure and more-efficient Solidity code.

We could use the OpenZeppelin SafeMath library to help secure our smart contracts, but please note: SafeMath was used for compiler versions earlier than 0.8.0. After that compiler version, it is no longer needed as integer overflow and integer underflow are automatically taken care of in newer compiler versions.

Only the Remix IDE supports importing libraries directly from GitHub. Other IDEs require a different method of importing libraries, such as copying the code from the file that’s hosted on GitHub into the new contract file before creating your contract.

To import OpenZeppelin contracts from GitHub, follow the code example below:

pragma solidity ^0.5.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";

Inheritance and Composition

Writing smart contracts (like many programming activities) heavily relies on the object-oriented programming (OOP) principles of inheritance and composition.

There are two core targets that we want to achieve by using these principles:

  • The ability to easily scale or reuse code: Once we or others have designed robust and efficient code, we want to use it for other use cases without having to modify the code.
  • The reduction of the potential for bugs: Being able to reuse well-tested code allows us to become more efficient and reduce the chance for bugs in our code.

In OOP, we use inheritance when a particular type of relationship exists between classes. Specifically, this happens when one class is a specialized version of the other, more-general class.

  • With inheritance, is a is the key phrase. A truck is a vehicle. The Intel Core i9 is a processor.

In OOP, we use composition for cases where a class or object has elements of another class or object.

As the name suggests, composition emphasizes the composition of a class or object based on elements of other types. By contrast, inheritance emphasizes being of a certain type. Composition contains elements of other classes that provide the desired functionality.

  • With composition, has a is the key phrase. A computer has a processor.

Both approaches have their strengths and work better or worse for certain use cases. Inheritance makes sense when a large overlap (like 80%) exists between two classes—and one class is a specialized case of the more-general class. By contrast, composition is more flexible. With composition, we can choose the components that we want to use to construct a new class.

Until next time, here’s a twitter thread summary of this post:

Subscribe to jackofcrypto
Receive the latest updates directly to your inbox.
Verification
This entry has been permanently stored onchain and signed by its creator.