In the FA2 example (https://smartpy.io/ide?template=FA2.py) with multiple assets, we are using a big map of pairs (of user and token). Another option might be storing big map mapping users to another map for token.

Which is a better approach? What things should we consider before using one of those?

Thanks in advance :)

3 Answers 3


Big maps are lazy while regular maps are not:

  • If you have big_map (pair nat address) nat, each big_map update will consume O(1) gas¹.
  • If you have big_map nat (map address nat) (where nat key is token_id), each big_map update will cost O(size(map address nat)) for the corresponding token_id. So the operation cost will grow as the number of token holders grows.
  • If you have big_map (address (map nat nat) (i. e. map from address to map from token_id to the balance), the cost of each update will be proportional to the total number of token_ids the address has (which can be hard limited in some tokens).

¹ that's not precisely correct because nats have arbitrary precision and may consume unbounded amount of gas, but if we limit the maximal nat value it should be O(1).

  • In the 3rd point (map from address to map from token to balance), what if I use big_map in both (ie. big_map of big_map)? That way the cost will be O(1) I guess I'm trying to understand why using pair<address,token> as key in big_map is better...
    – tichnas
    May 28, 2021 at 10:59
  • 1
    big maps are not allowed inside big maps. May 28, 2021 at 11:00
  • 1
    @RaphaëlCauderlier Tbh, I thought the same, but it somehow worked: smartpy.io/…
    – tichnas
    May 28, 2021 at 11:14
  • If you try to originate the contract from the SmartPy IDE you get the following error: failed(permanent: proto.009-PsFLoren.michelson_v1.ill_formed_type), (permanent: proto.009-PsFLoren.michelson_v1.unexpected_lazy_storage) May 29, 2021 at 21:14

The advantage of big_map a (map b c) over big_map (pair a b) c is that it allows to iterate over all the bs of a specific a. In your case, IIUC, this means iterating over all the token ids that a given address owns. I guess this might be useful in some occasions but here is what it costs:

  • storage cost: if you want to minimize the amount of tez that is burnt to interact with your contract you should avoid storing information that you don't need. Typically when using big maps this means putting as much as possible in the type of the keys of the big map because big map keys are not stored. In your case, using big_map address (map nat nat) has an additional storage cost over big_map (pair address nat) nat, because for each address in the big map, all the token ids owned by this address are stored.

  • gas cost: see the answer of Ivan Gromakovskii


I believe you are talking about the ledger property.

The spec specifies this:

Single asset contract

big_map %ledger address nat

where key is the owner's address and value is the amount of tokens owned.

Multi-asset contract

big_map %ledger (pair address nat) nat

where key is the pair [owner's address, token ID] and value is the amount of tokens owned.

NFT asset contract

big_map %ledger nat address

where key is the token ID and value is owner's address.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.