Fungible tokens on Everscale: Exploring the TIP-3 standard

Fungible tokens on Everscale: Exploring the TIP-3 standard

The adoption of EIP-20 (Ethereum improvement proposal) in the Ethereum network paved the way for implementing various fungible tokens built on the standard architecture. New kinds of tokens came in use for various purposes — voting in DAO, stablecoins, paying for the services of L2 solutions and simple transfers of value.

The architectural solutions applied in the ERC-20 standard, nonetheless, resulted in challenges that the Ethereum team is struggling to cope with. For example, every ERC-20 smart-contract stores information about every holder of the token, which can result in unconstrained growth to the user hashmap. This data must be stored in the blockchain where every action is paid for by blockchain actors.

The animation below demonstrates the unconstrained growth of the ERC-20 token holder hashmap:

Note: Throughout the article we interchangeably use two terms, smart-contract and account, which mean the same thing. This is due to the fact that each account in Everscale is a smart contract.

Also, to fully understand the article, please familiarise yourself with the following terms:

TokenRoot — a smart-contract storing the basic data of TIP-3 tokens. The contract is used to generate TokenWallet contracts.

TokenWallet — a smart-contract generated on the basis of the TokenRoot code. The contract is used to store TIP-3 tokens and transfer them between other TokenWallet contracts.

acceptMint() — a method of the TokenWallet contract to accept TIP-3 tokens minted by the TokenRoot owner. The method is mainly used to transfer initially minted tokens to an account of TokenRoot owner to enter tokens into circulation.

acceptBurn() — a method of the TokenRoot contract facilitating the reception of TIP-3 tokens from a TokenWallet contract and the subsequent burning of them, thus removing the burnt tokens from circulation.

burn() — a method of the TokenWallet contract to decrease the amount of TIP-3 tokens on its balance and to call the acceptBurn() method of the parent TokenRoot contract.

requestUpgradeWallet() — a method of the TokenRoot contract that is to be called by the TokenRoot owner to initiate an upgrade of the smart-contract logic.

setWalletCode() — a method of the TokenRoot contract that applies the changes, sent by the TokenRoot owner to the code of the TokenRoot contract.

upgrade() — a method of the TokenRoot contract to initiate actions in the Threaded Virtual Machine that result in adding new code to the new version of the TokenRoot.

Distributed Token Architecture in the Everscale blockchain and Venom blockchain: TIP-3

Everything is a smart-contract in Everscale and Venom and other Threaded Virtual Machine blockchains. Transactions generated by one smart-contract are bound to be validated in a shard (thread), which the smart-contract belongs to.

If fungible tokens in TVM-compatible blockchains had had a design similar to ERC-20 tokens, the processing of crypto transactions would have been limited to processing by one node from a group of validators responsible for validating the shard. That would have reduced the blockchain scaling potential, intrinsic for TVM (Threaded Virtual Machine) blockchains, literally to zero.

The animation below shows the 3-step interaction between the sender wallet, ERC-20 token smart-contract address, and the recipient wallet. In case a user of Ethereum blockchain wants to send some USDT to other address, this transaction will be bound to invoke USDT ERC-20 contract:

The mechanism granting almost infinite scalability to Everscale is called sharding. Sharding involves splitting a set of smart-contracts comprising one shard into two shards each validated by its own group of blockchain nodes. In order to make TIP-3 token operations scaling-ready, token operations must be distributed among several smart-contracts and should not have one mandatory node of interaction, like an ERC-20 smart-contract in the Ethereum network. Ideally, each smart-contract wallet, storing this or that token on its balance, must be a separate actor (smart-contract).

This is the design implemented in the TIP-3 token standard. Currently, Everscale recommends building TIP-3 tokens in accordance with the Broxus realization.

The TIP-3 token standard includes two types of smart-contracts — TokenRoot and TokenWallet. Looking further forward, the number of TokenWallet contracts existing in the blockchain is unlimited, which translates to unlimited blockchain scalability. First, let’s take a look at the TokenRoot contract.

TokenRoot: the Core of TIP-3 Fungible Tokens

In the TIP-3 token standard, TokenRoot is the main token contract. It bears similarities with the ERC-20 token contract, but there are also some differences based on the distributed nature of the standard.

Like in Ethereum, TokenRoot stores information about:

  • Token name;
  • Token ticker;
  • Size of the decimal part;
  • Address of the owner of the TokenRoot;
  • Total number of tokens that are currently in circulation.

The TokenRoot contract also has its own methods. Some of the methods can be called only by the TokenRoot owner. Calling constructor requires indicating the address of the TokenRoot owner smart-contract.

Via the TokenRoot contract the owner can mint tokens, enable and disable, pause and resume, as well as burn tokens. Calling acceptMint() or acceptBurn() methods will increase or decrease the amount of tokens on the selected TokenWallet smart-contract owned by the TokenRoot owner. This mechanism allows orchestrating the total circulation of the tokens according to, for example, decentralized voting, which results in economic implications affecting all token holders.

TokenRoot contracts also facilitate easy upgrades to their logic. Upgrading TokenRoot code requires calling the following methods: requestUpgradeWallet(), setWalletCode(), upgrade(). Needless to say, the methods can be called only by a smart-contract with the address of the TokenRoot owner.

Another method built in the TokenRoot contract is deployWallet(). This method is public, i.e. can be called by any smart-contract. The method creates a new smart-contract capable of holding the TokenRoot contract tokens (e.g stEVERr) on its balance and transferring them to other TokenWallet contracts. The method can be called only by an internal message.

If an Everscale blockchain user wishes to own TIP-3 $USDC tokens, they actually invoke the following algorithm in the network:

1. The wallet application sends an external message to the TokenRoot contract.

2. The method deployWallet() of the TokenRoot contract is called. The parameters of the method include the user’s crypto wallet address.

3. The deployWallet method combines the TokenRoot address and the address of the user’s wallet and calculates an address for the user’s $USDC TokenWallet contract.

4. Now, every other $USDC TokenWallet contract recognizes the user’s wallet, as the address of the TokenRoot is hashed in its address. If the transferToWallet() method is used from a non-USDC wallet, the message will be declined by the USDC account.

In the animation below, you can see how TokenWallets are created by sending messages from user accounts, as well as TokenWallet-to-TokenWallet interactions to transfer TIP-3 tokens. Sending tokens between wallets does not require interactions with the TokenRoot contract:

TokenWallet: Interactions Independent from TokenRoot

Now, as we have numerous smart-contracts that are used as a storage for TIP-3 tokens, we no longer need to interact with TokenRoot to transfer tokens to each other. Every $USDC TokenWallet recognizes other $USDC TokenWallets as they share the same parent code — $USDC TokenRoot transformed to their addresses by means of hashing. If someone tries to send you, say, $USDT, your TokenWallet will not accept the transfer as $USDT and $USDC have different TokenRoot contract addresses.

Moreover, having a discrete smart-contract for each user facilitates the transfer of tokens from different shards, which is the recipe for the Everscale blockchain’s infinite scalability as well as that of the Venom blockchain.

The animation below demonstrates the process of token exchange between several TokenWallet contracts during low network workload and high network workload conditions. When the workload is low, all the contracts are validated in a single shard. When the workload is high, smart-contracts can be allocated between several shards when the split mechanism is triggered in the network:

Low workload

High workload

As you can recall from the TokenRoot section, the parent smart-contract does not have a token holder hashmap. The TokenRoot smart-contract simply has no need to store the balance of each TokenWallet. Every TokenWallet contract is responsible for storing information on its balance. This resolves the issue of token holder hashmaps growing astronomically.

However, if there is an unlimited number of blockchain smart-contracts, at least one smart-contract for one user and one TIP-3 token, wouldn’t the network be even more congested in comparison to EVM-compatible blockchains? It actually would not. Each smart-contract pays a storage fee for blockchain data storage. If a user becomes inactive in the blockchain and abandons their smart-contract with some fractions of tokens, a process of smart-contract deletion is set in motion. Every second of storing a bit of information will consume $EVER and once the $EVER balance of a TokenWallet reaches -0.1, the smart-account gets frozen and later erased from the network state. The animation below demonstrates how it actually works in one particular shard.

It may seem frustrating, but storage fees are minimal and have very little effect on active users. What is more important is that the storage fee eliminates potential situations when current active users pay to store data belonging to long-abandoned accounts. Moreover, there is no opportunity to pile excessive amounts of unused data inside the blockchain.

If you look through the TokenWallet code, you might be wondering why a contract that is designed to transfer and accept tokens would have acceptMint() and burn() methods. The answer lies in the parameters of the TokenRoot contract. It has no balance, which means that the developer of the TIP-3 token cannot store initially minted tokens inside the TokenRoot. Even the TokenRoot contract owner needs to deploy their own TokenWallet and orchestrate circulation using a discrete wallet. Of course, any crypto wallet address that shares the same TokenRoot can serve as a recipient for newly minted tokens, which can be convenient for, say, conducting airdrops.

As we can see, the TIP-3 token standard is a realization of a new vision of token architecture, powered by the willingness to address the challenges of older blockchains and take advantage of the capacity of the Threaded Virtual Machine.

Read More