Off-chain events and Tezos tokens indexing

Baking Bad
Coinmonks
4 min readAug 28, 2020

--

In this article an approach to the token balance accounting is presented. This is a development of the ideas presented earlier taking into account the upcoming contract metadata standard TZIP-16.

In a few words, there is a problem when indexing operations that alter token balances: if the invoked method is not standardized (currently we have only FA1.2/FA2 transfer), or if there is an initial token distribution at the origination - it's not possible for the indexer to determine which particular balances have changed and how.

ULTIMATE GOAL
Get the list of changed token balances from the operation content and result.

The current approach is using custom handlers for known contracts. Obviously, it is tied to a specific indexer implementation and is not scalable, so we need a better alternative that is:

  1. Flexible enough to cover the majority of cases;
  2. Simple enough to implement/integrate with existing codebase;
  3. Not tied to any specific entity nor implementation.

Off-chain events

The solution lies on the surface: we need to take all the custom logic out of the indexer, as well as to give the developers of the contracts the opportunity to edit it themselves.
This is effectively the concept of external (off-chain) views: a piece of Michelson code that is applied to the contract storage. Actually, one can write those external scripts in LIGO, SmartPy, Lorentz, or other high-level language and then compile down to Michelson.
The upcoming TZIP-16 standardizes off-chain views and defines two kinds that can be used in the contract metadata.

NOTE
The task of indexing metadata is beyond the scope of this article, we simply assume that for a particular contract we have a TZIP-16 compliant data file.

The existing view kinds are not enough for our needs, so we suggest adding some new ones. Below we will list cases that require the use of off-chain views, and the according implementation examples.

DEFINITION
In this article we use the term off-chain event (suggested by Seb Mondet) implying that this is a workaround until a native event logging system is implemented (suggested by Gabriel Alfour).

Initial storage

Let us consider a case when tokens are pre-minted and distributed when deploying a contract.

Except for the case when the entire ledger is copied from another contract ( Big_map copy, we’ll deal with it later), everything we need is in the resulting storage ( Big_map items are already included).

Let’s take the storage type of the sample contract above:

The according event script would have:

  • unit parameter type;
  • Storage type similar to one in the target contract, except all big_map occurrences are replaced by map;
  • Code must end with a FAILWITH instruction and there must be a value of type map address balance on top of the stack.

This value is actually all the balances changed during a contract call, and for each change indexer needs to know:

  • Holder address;
  • Token ID (in case there are more than one token within the contract);
  • Resulting balance.

Note that we can omit token ID e.g. for FA1.2 or other contracts with a single token. Otherwise we have to put map (pair address nat) nat instead.

Here is a script that derives token balances from the given contract storage:

Invoking the script with Unit parameter and origination storage we get an expected runtime error with:

Finally, the metadata file would look like:

Note that we have a single view item that is responsible for deriving token balance updates and multiple implementations which are used depending on the situation.

Originally published at https://baking-bad.org on August 28, 2020, where you can find full version of the article.

Also, Read

--

--

Baking Bad
Coinmonks

Baking-bad.org, Audit & Rating of Tezos bakers. Active Tezos tools contributor. Author of better-call.dev, Pytezos, Netezos, TzKT.io, atomex.me