Skip to main content
Version: Next

Maps and BigMaps

Learn how to:

  • Fetch data from a Map datatype on a Tezos Smart Contract
  • Fetch data from a BigMap datatype on a Tezos Smart Contract
  • Initialize Map data while originating a new contract to the Tezos Blockchain
  • Use Pairs as a key to access Map and BigMap values
  • Why Michelson Map and BigMap don't look like a Javascript Map

Taquito provides MichelsonMap to make it easy for developers to work with the native Michelson map datatypes. MichelsonMap supports initialization, get and set methods to Maps using primitive datatypes and pairs as keys.

Michelson offers two variants of Maps that are semantically the same but have different implementations and trade-offs in terms of gas and storage costs on a contract. A Map uses more storage but costs less gas, whereas a BigMap consumes less storage but has higher gas costs during the Smart Contract's execution.

A Contract with a single Map for storage

Origination of the contract with an initial storage

This example builds on the Ligo Lang Taco Shop learning resources.

The storage of the contract used in the following example is a map where a key is a natural number (a nat), and a value is a pair composed of two values representing the quantity of stock and tez tokens, respectively. The contract's source code is available here. In the example, the contract is originated with initial values using the MichelsonMap class' set method.

Live Editor
Result

The fromLiteral convenience method can be used instead of using set for each element. Here is the same origination operation but using fromLiteral to create our MichelsonMap.

Live Editor
Result

Accessing the values of the map

This example loads the same type of Taco Shop contract (we created this one earlier). Taquito provides a get method of the MichelsonMap on storage of type Map, and in this case, we access the value stored with a key of 1.

The example calls the Contracts main function of the contract using the key 1 as its parameter. Remember, we can only change contract storage by calling the function provided by the contract. The main function on this Smart Contract is decreasing the value of the current_stock associated with the key 1. We use the get method of the MichelsonMap class to see the difference in storage after the method call.

Live Editor
Result

A Contract with a Map using an unannotated pair/tuple as a key

Here we have the storage of our contract defined in Michelson.

It has a Map with the annotated name %theMap. This Map uses a pair consisting of a natural number and an address as its key (1, tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx). Its value is also a pair of values, consisting of an int (annotated as %quantity) and mutez (annotated as %amount).

(pair (pair (address %theAddress)
(map %theMap (pair nat address) (pair (mutez %amount) (int %quantity))))
(int %theNumber))

Origination of the contract with Pair as Map keys

Since the key of the map has no annotations, MichelsonMap requires that we use an index value starting at 0 to initialize its elements.

Live Editor
Result

Accessing Map values using Pairs

The get method of the MichelsonMap class accesses values of the map for a specified key.

This example accesses the map using its theMap annotation. If the storage does not annotate its properties, the caller must use numeric indexes instead.

Recall that this contract does not annotate the pairs of the key pair either. We use numeric indexes for this also.

Live Editor
Result

A Map with nested Pairs as keys

This contract schema has a key with eight nested pairs and the value of an int. This example type of key is impractical, but we offer it as an example to illustrate how to work with complex keys.

The Michelson storage schema with a map using eight pairs as a key:

(map (pair int
(pair nat
(pair string
(pair bytes
(pair mutez
(pair bool
(pair key_hash
(pair timestamp address)))))))) int)

Origination of a contract with complex keys

In this example, the contract schema does not have map annotations, which means that each value needs to have an index as a property name.

Live Editor
Result

Accessing Map values with complex keys

The get method of the MichelsonMap class accesses values of the map for a specified key.

Reminder

Taquito will handle timestamps with the milliseconds as 2019-09-06T15:08:29.000Z rather than 2019-09-06T15:08:29Z which is crucial when accessing maps with complex keys

Live Editor
Result

BigMaps

Map and BigMap are semantically the same except for everything you learned about Maps applies to working with BigMaps. The only difference is that when calling get on a bigMap will return a Javascript Promise, whereas get on a Map returns directly. In this example, the contract schema does not have map annotations, which means that each value needs to have an index as a property name.

Contract storage containing a map and a bigMap

The MichelsonMap class also supports the bigMap type. The following example uses a contract containing both a map and a bigMap in its storage. Here is the Michelson definition of storage for this example:

(pair (big_map %thebigmap (pair nat address) int) (map %themap (pair nat address) int))

Origination of the contract with an initial storage

Live Editor
Result

Accessing the values of the map and the bigMap

The get method of the MichelsonMap class accesses the values of the map and values of the bigMap. The difference is that the value gets returned directly for a map while the get method on a bigMap returns a promise.

Live Editor
Result

Local packing for big maps

By default, a call to an RPC node is used to pack data when fetching values from a big map. Big map keys need to be serialized or packed and Taquito relies on the PACK functionality of a Tezos RPC node to pack the big map keys. This may be considered inefficient as it adds a request to a remote node to fetch data.

Now, Taquito allows you to pack the required data locally to fetch values from a big map. By relying on the local pack implementation, Taquito eliminates one RPC roundtrip when fetching big map values. This feature makes fetching big map values 50% faster.

Implementing this feature is a very easy 2 step process:

  1. Importing the MichelCodecPacker class from @taquito/taquito
  2. Creating an instance of the MichelCodecPacker class and passing it to the setPackerProvider method of the TezosToolkit instance.

Here is an example:

import { MichelCodecPacker } from '@taquito/taquito';
const Tezos = new TezosToolkit(RPC_URL);
Tezos.setPackerProvider(new MichelCodecPacker());

After that, Taquito will automatically pack the keys locally when you want to fetch the values of a big map.

Fetch multiple big map values at once

It is possible to fetch multiple big map values using Taquito with one call using the getMultipleValues method of the BigMapAbstraction class. Taquito will ensure that all fetched big maps come from the same block to ensure a consistent state.

The method takes an array of keys to query as a parameter and an optional block level and returns a MichelsonMap containing the keys and their value in a well-formatted JSON object format. The accepted types for the keys are string, number or object (the last one is used when the type of the keys in the big map is a Michelson pair).

In the following example, we will fetch 4 big map values at once. The Michelson type of the big map key is an address and the type of its value is a pair made of a nat and a map. We see in the example that the address tz1QZ6KY7d3BuZDT1d19dUxoQrtFPN2QJ3hn is not a key of the big map, so its value is set to undefined in the returned MichelsonMap.

Live Editor
Result

Provide detailed feedback