This API release is scheduled to go live on Dec 12, 2019 12:00 UTC. Please update and test your integrations against https://api.staging.tzstats.com to be ready.

Tezos is rapidly evolving. Several exciting layer 2 projects are waiting to go live on mainnet soon and we want to be ready from day one. Our new API release (v005-2019-12-05) introduces a full bigmap index as well as a complete set of features to access raw and decoded smart contract data from storage, bigmaps and call parameters. This is an exciting and important milestone for Tezos, because it allows developers to write applications without the need to decode binary data or handle complex nested Michelson primitives. It is also the first API that lets you browse the full history of a contract's state at any given block in the past.

In this blog post I'll introduce the core features of this new API and show how you can efficiently use them in your applications. Before we jump in, there's a warning:

SECURITY WARNING

RAW AND DECODED SMART CONTRACT DATA MAY CONTAIN MALICIOUS CONTENT INTENDED TO ATTACK YOUR APPLICATIONS AND USERS!

Unlike other on-chain data where values and value ranges are predictable the contents of smart contract call parameters, storage keys/values and code/type annotations is entirely user-controlled and unpredictable. Be vigilant and sanitize all data before you process or display it.

Michelson Background

I start at the foundation for Tezos smart contracts, the Michelson language and it's type system. When you originate a contract on-chain its code gets published along with a type definition for storage and call parameters. Tezos calls this combination the script. To simplify serialization, a script is a single nested tree of Michelson primitives containing typedefs, opcodes and data. The script contains everything necessary, but it's painful to parse and much too verbose for application developers to digest.

Example script primitives for KT1ChNsEFxwyCbJyWGSL3KdjeXE28AY1Kaog (Baker Registry)
{
  "code": [
    {
      "args": [
        {
          "args": [
            {
              "annots": [
                "%set_data"
              ],
              "args": [
                {
                  "annots": [
                    "%delegate"
                  ],
                  "prim": "key_hash"
                },
                {
                  "args": [
                    {
                      "annots": [
                        "%data"
                      ],
                      "args": [
                        {
                          "args": [
                            {
                              "args": [
                                {
                                  "args": [
                                    {
                                      "annots": [
                                        "%bakerName"
                                      ],
                                      "prim": "bytes"
                                    },
                                    {
                                      "annots": [
                                        "%openForDelegation"
                                      ],
                                      "prim": "bool"
                                    }
                                  ],
                                  "prim": "pair"
                                },
                                {
                                  "annots": [
                                    "%bakerOffchainRegistryUrl"
                                  ],
                                  "prim": "bytes"
                                }
                              ],
                              "prim": "pair"
                            },
                            {
                              "args": [
                                {
                                  "args": [
                                    {
                                      "annots": [
                                        "%split"
                                      ],
                                      "prim": "nat"
                                    },
                                    {
                                      "annots": [
                                        "%bakerPaysFromAccounts"
                                      ],
                                      "args": [
                                        {
                                          "prim": "address"
                                        }
                                      ],
                                      "prim": "list"
                                    }
                                  ],
                                  "prim": "pair"
                                },
                                {
                                  "args": [
                                    {
                                      "args": [
                                        {
                                          "args": [
                                            {
                                              "annots": [
                                                "%minDelegation"
                                              ],
                                              "prim": "nat"
                                            },
                                            {
                                              "annots": [
                                                "%subtractPayoutsLessThanMin"
                                              ],
                                              "prim": "bool"
                                            }
                                          ],
                                          "prim": "pair"
                                        },
                                        {
                                          "args": [
                                            {
                                              "annots": [
                                                "%payoutDelay"
                                              ],
                                              "prim": "int"
                                            },
                                            {
                                              "args": [
                                                {
                                                  "annots": [
                                                    "%payoutFrequency"
                                                  ],
                                                  "prim": "nat"
                                                },
                                                {
                                                  "annots": [
                                                    "%minPayout"
                                                  ],
                                                  "prim": "int"
                                                }
                                              ],
                                              "prim": "pair"
                                            }
                                          ],
                                          "prim": "pair"
                                        }
                                      ],
                                      "prim": "pair"
                                    },
                                    {
                                      "args": [
                                        {
                                          "args": [
                                            {
                                              "annots": [
                                                "%bakerChargesTransactionFee"
                                              ],
                                              "prim": "bool"
                                            },
                                            {
                                              "annots": [
                                                "%paymentConfigMask"
                                              ],
                                              "prim": "nat"
                                            }
                                          ],
                                          "prim": "pair"
                                        },
                                        {
                                          "args": [
                                            {
                                              "annots": [
                                                "%overDelegationThreshold"
                                              ],
                                              "prim": "nat"
                                            },
                                            {
                                              "annots": [
                                                "%subtractRewardsFromUninvitedDelegation"
                                              ],
                                              "prim": "bool"
                                            }
                                          ],
                                          "prim": "pair"
                                        }
                                      ],
                                      "prim": "pair"
                                    }
                                  ],
                                  "prim": "pair"
                                }
                              ],
                              "prim": "pair"
                            }
                          ],
                          "prim": "pair"
                        }
                      ],
                      "prim": "option"
                    },
                    {
                      "annots": [
                        "%reporterAccount"
                      ],
                      "args": [
                        {
                          "prim": "address"
                        }
                      ],
                      "prim": "option"
                    }
                  ],
                  "prim": "pair"
                }
              ],
              "prim": "pair"
            },
            {
              "args": [
                {
                  "annots": [
                    "%set_fees"
                  ],
                  "args": [
                    {
                      "annots": [
                        "%signup_fee"
                      ],
                      "prim": "mutez"
                    },
                    {
                      "annots": [
                        "%update_fee"
                      ],
                      "prim": "mutez"
                    }
                  ],
                  "prim": "pair"
                },
                {
                  "annots": [
                    "%withdraw"
                  ],
                  "args": [
                    {
                      "prim": "unit"
                    }
                  ],
                  "prim": "contract"
                }
              ],
              "prim": "or"
            }
          ],
          "prim": "or"
        }
      ],
      "prim": "parameter"
    },
    {
      "args": [
        {
          "args": [
            {
              "args": [
                {
                  "prim": "key_hash"
                },
                {
                  "args": [
                    {
                      "args": [
                        {
                          "annots": [
                            "%data"
                          ],
                          "args": [
                            {
                              "args": [
                                {
                                  "args": [
                                    {
                                      "args": [
                                        {
                                          "annots": [
                                            "%bakerName"
                                          ],
                                          "prim": "bytes"
                                        },
                                        {
                                          "annots": [
                                            "%openForDelegation"
                                          ],
                                          "prim": "bool"
                                        }
                                      ],
                                      "prim": "pair"
                                    },
                                    {
                                      "annots": [
                                        "%bakerOffchainRegistryUrl"
                                      ],
                                      "prim": "bytes"
                                    }
                                  ],
                                  "prim": "pair"
                                },
                                {
                                  "args": [
                                    {
                                      "args": [
                                        {
                                          "annots": [
                                            "%split"
                                          ],
                                          "prim": "nat"
                                        },
                                        {
                                          "annots": [
                                            "%bakerPaysFromAccounts"
                                          ],
                                          "args": [
                                            {
                                              "prim": "address"
                                            }
                                          ],
                                          "prim": "list"
                                        }
                                      ],
                                      "prim": "pair"
                                    },
                                    {
                                      "args": [
                                        {
                                          "args": [
                                            {
                                              "args": [
                                                {
                                                  "annots": [
                                                    "%minDelegation"
                                                  ],
                                                  "prim": "nat"
                                                },
                                                {
                                                  "annots": [
                                                    "%subtractPayoutsLessThanMin"
                                                  ],
                                                  "prim": "bool"
                                                }
                                              ],
                                              "prim": "pair"
                                            },
                                            {
                                              "args": [
                                                {
                                                  "annots": [
                                                    "%payoutDelay"
                                                  ],
                                                  "prim": "int"
                                                },
                                                {
                                                  "args": [
                                                    {
                                                      "annots": [
                                                        "%payoutFrequency"
                                                      ],
                                                      "prim": "nat"
                                                    },
                                                    {
                                                      "annots": [
                                                        "%minPayout"
                                                      ],
                                                      "prim": "int"
                                                    }
                                                  ],
                                                  "prim": "pair"
                                                }
                                              ],
                                              "prim": "pair"
                                            }
                                          ],
                                          "prim": "pair"
                                        },
                                        {
                                          "args": [
                                            {
                                              "args": [
                                                {
                                                  "annots": [
                                                    "%bakerChargesTransactionFee"
                                                  ],
                                                  "prim": "bool"
                                                },
                                                {
                                                  "annots": [
                                                    "%paymentConfigMask"
                                                  ],
                                                  "prim": "nat"
                                                }
                                              ],
                                              "prim": "pair"
                                            },
                                            {
                                              "args": [
                                                {
                                                  "annots": [
                                                    "%overDelegationThreshold"
                                                  ],
                                                  "prim": "nat"
                                                },
                                                {
                                                  "annots": [
                                                    "%subtractRewardsFromUninvitedDelegation"
                                                  ],
                                                  "prim": "bool"
                                                }
                                              ],
                                              "prim": "pair"
                                            }
                                          ],
                                          "prim": "pair"
                                        }
                                      ],
                                      "prim": "pair"
                                    }
                                  ],
                                  "prim": "pair"
                                }
                              ],
                              "prim": "pair"
                            }
                          ],
                          "prim": "option"
                        },
                        {
                          "annots": [
                            "%reporterAccount"
                          ],
                          "args": [
                            {
                              "prim": "address"
                            }
                          ],
                          "prim": "option"
                        }
                      ],
                      "prim": "pair"
                    },
                    {
                      "annots": [
                        "%last_update"
                      ],
                      "prim": "timestamp"
                    }
                  ],
                  "prim": "pair"
                }
              ],
              "prim": "big_map"
            },
            {
              "args": [
                {
                  "annots": [
                    "%owner"
                  ],
                  "prim": "address"
                },
                {
                  "args": [
                    {
                      "annots": [
                        "%signup_fee"
                      ],
                      "prim": "mutez"
                    },
                    {
                      "annots": [
                        "%update_fee"
                      ],
                      "prim": "mutez"
                    }
                  ],
                  "prim": "pair"
                }
              ],
              "prim": "pair"
            }
          ],
          "prim": "pair"
        }
      ],
      "prim": "storage"
    },
    {
      "args": [
        [
          [
            [
              {
                "prim": "DUP"
              },
              {
                "prim": "CAR"
              },
              {
                "args": [
                  [
                    {
                      "prim": "CDR"
                    }
                  ]
                ],
                "prim": "DIP"
              }
            ]
          ],
          {
            "args": [
              [
                {
                  "prim": "DUP"
                },
                {
                  "prim": "CDR"
                },
                {
                  "prim": "CAR"
                },
                [
                  {
                    "args": [
                      [],
                      [
                        {
                          "prim": "CAR"
                        },
                        {
                          "prim": "DUP"
                        },
                        {
                          "prim": "CAR"
                        },
                        {
                          "prim": "CAR"
                        },
                        {
                          "prim": "SIZE"
                        },
                        {
                          "args": [
                            {
                              "prim": "nat"
                            },
                            {
                              "int": "61"
                            }
                          ],
                          "prim": "PUSH"
                        },
                        [
                          [
                            {
                              "prim": "COMPARE"
                            },
                            {
                              "prim": "GT"
                            }
                          ],
                          {
                            "args": [
                              [],
                              [
                                [
                                  {
                                    "prim": "UNIT"
                                  },
                                  {
                                    "prim": "FAILWITH"
                                  }
                                ]
                              ]
                            ],
                            "prim": "IF"
                          }
                        ],
                        {
                          "prim": "CDR"
                        },
                        {
                          "prim": "SIZE"
                        },
                        {
                          "args": [
                            {
                              "prim": "nat"
                            },
                            {
                              "int": "81"
                            }
                          ],
                          "prim": "PUSH"
                        },
                        [
                          [
                            {
                              "prim": "COMPARE"
                            },
                            {
                              "prim": "GT"
                            }
                          ],
                          {
                            "args": [
                              [],
                              [
                                [
                                  {
                                    "prim": "UNIT"
                                  },
                                  {
                                    "prim": "FAILWITH"
                                  }
                                ]
                              ]
                            ],
                            "prim": "IF"
                          }
                        ]
                      ]
                    ],
                    "prim": "IF_NONE"
                  }
                ],
                [
                  [
                    {
                      "prim": "DUP"
                    },
                    {
                      "prim": "CAR"
                    },
                    {
                      "args": [
                        [
                          {
                            "prim": "CDR"
                          }
                        ]
                      ],
                      "prim": "DIP"
                    }
                  ]
                ],
                [
                  {
                    "args": [
                      {
                        "int": "2"
                      },
                      [
                        {
                          "prim": "DUP"
                        }
                      ]
                    ],
                    "prim": "DIP"
                  },
                  {
                    "args": [
                      {
                        "int": "3"
                      }
                    ],
                    "prim": "DIG"
                  }
                ],
                {
                  "prim": "CAR"
                },
                [
                  {
                    "args": [
                      [
                        {
                          "prim": "DUP"
                        }
                      ]
                    ],
                    "prim": "DIP"
                  },
                  {
                    "prim": "SWAP"
                  }
                ],
                {
                  "annots": [
                    "@from_storage"
                  ],
                  "prim": "GET"
                },
                {
                  "args": [
                    [
                      {
                        "prim": "DUP"
                      },
                      {
                        "prim": "IMPLICIT_ACCOUNT"
                      },
                      {
                        "prim": "ADDRESS"
                      },
                      {
                        "prim": "SENDER"
                      },
                      [
                        [
                          {
                            "prim": "COMPARE"
                          },
                          {
                            "prim": "EQ"
                          }
                        ],
                        {
                          "args": [
                            [],
                            [
                              [
                                {
                                  "prim": "UNIT"
                                },
                                {
                                  "prim": "FAILWITH"
                                }
                              ]
                            ]
                          ],
                          "prim": "IF"
                        }
                      ],
                      [
                        {
                          "args": [
                            {
                              "int": "2"
                            },
                            [
                              {
                                "prim": "DUP"
                              }
                            ]
                          ],
                          "prim": "DIP"
                        },
                        {
                          "args": [
                            {
                              "int": "3"
                            }
                          ],
                          "prim": "DIG"
                        }
                      ],
                      [
                        {
                          "prim": "CDR"
                        },
                        {
                          "prim": "CDR"
                        },
                        {
                          "annots": [
                            "%signup_fee"
                          ],
                          "prim": "CAR"
                        }
                      ],
                      {
                        "prim": "AMOUNT"
                      },
                      [
                        [
                          {
                            "prim": "COMPARE"
                          },
                          {
                            "prim": "EQ"
                          }
                        ],
                        {
                          "args": [
                            [],
                            [
                              [
                                {
                                  "prim": "UNIT"
                                },
                                {
                                  "prim": "FAILWITH"
                                }
                              ]
                            ]
                          ],
                          "prim": "IF"
                        }
                      ]
                    ],
                    [
                      [
                        {
                          "prim": "CAR"
                        },
                        {
                          "annots": [
                            "%reporterAccount"
                          ],
                          "prim": "CDR"
                        }
                      ],
                      {
                        "args": [
                          [
                            {
                              "args": [
                                {
                                  "prim": "bool"
                                },
                                {
                                  "prim": "False"
                                }
                              ],
                              "prim": "PUSH"
                            }
                          ],
                          [
                            {
                              "prim": "SENDER"
                            },
                            {
                              "prim": "COMPARE"
                            },
                            {
                              "prim": "EQ"
                            }
                          ]
                        ],
                        "prim": "IF_NONE"
                      },
                      {
                        "args": [
                          [
                            {
                              "prim": "DUP"
                            },
                            {
                              "prim": "IMPLICIT_ACCOUNT"
                            },
                            {
                              "prim": "ADDRESS"
                            },
                            {
                              "prim": "SENDER"
                            },
                            {
                              "prim": "COMPARE"
                            },
                            {
                              "prim": "EQ"
                            }
                          ]
                        ],
                        "prim": "DIP"
                      },
                      {
                        "prim": "OR"
                      },
                      [
                        {
                          "args": [
                            [],
                            [
                              [
                                {
                                  "prim": "UNIT"
                                },
                                {
                                  "prim": "FAILWITH"
                                }
                              ]
                            ]
                          ],
                          "prim": "IF"
                        }
                      ],
                      [
                        {
                          "args": [
                            {
                              "int": "2"
                            },
                            [
                              {
                                "prim": "DUP"
                              }
                            ]
                          ],
                          "prim": "DIP"
                        },
                        {
                          "args": [
                            {
                              "int": "3"
                            }
                          ],
                          "prim": "DIG"
                        }
                      ],
                      [
                        {
                          "prim": "CDR"
                        },
                        {
                          "prim": "CDR"
                        },
                        {
                          "annots": [
                            "%update_fee"
                          ],
                          "prim": "CDR"
                        }
                      ],
                      {
                        "prim": "AMOUNT"
                      },
                      [
                        [
                          {
                            "prim": "COMPARE"
                          },
                          {
                            "prim": "EQ"
                          }
                        ],
                        {
                          "args": [
                            [],
                            [
                              [
                                {
                                  "prim": "UNIT"
                                },
                                {
                                  "prim": "FAILWITH"
                                }
                              ]
                            ]
                          ],
                          "prim": "IF"
                        }
                      ]
                    ]
                  ],
                  "prim": "IF_NONE"
                },
                {
                  "args": [
                    [
                      {
                        "prim": "NOW"
                      },
                      {
                        "prim": "SWAP"
                      },
                      {
                        "prim": "PAIR"
                      },
                      {
                        "prim": "SOME"
                      },
                      {
                        "args": [
                          [
                            [
                              [
                                {
                                  "prim": "DUP"
                                },
                                {
                                  "prim": "CAR"
                                },
                                {
                                  "args": [
                                    [
                                      {
                                        "prim": "CDR"
                                      }
                                    ]
                                  ],
                                  "prim": "DIP"
                                }
                              ]
                            ]
                          ]
                        ],
                        "prim": "DIP"
                      }
                    ]
                  ],
                  "prim": "DIP"
                },
                {
                  "prim": "UPDATE"
                },
                {
                  "prim": "PAIR"
                },
                {
                  "args": [
                    {
                      "prim": "operation"
                    }
                  ],
                  "prim": "NIL"
                },
                {
                  "prim": "PAIR"
                }
              ],
              [
                [
                  {
                    "args": [
                      [
                        {
                          "prim": "DUP"
                        }
                      ]
                    ],
                    "prim": "DIP"
                  },
                  {
                    "prim": "SWAP"
                  }
                ],
                [
                  {
                    "prim": "CDR"
                  },
                  {
                    "annots": [
                      "%owner"
                    ],
                    "prim": "CAR"
                  }
                ],
                {
                  "prim": "SENDER"
                },
                [
                  [
                    {
                      "prim": "COMPARE"
                    },
                    {
                      "prim": "EQ"
                    }
                  ],
                  {
                    "args": [
                      [],
                      [
                        [
                          {
                            "prim": "UNIT"
                          },
                          {
                            "prim": "FAILWITH"
                          }
                        ]
                      ]
                    ],
                    "prim": "IF"
                  }
                ],
                {
                  "prim": "AMOUNT"
                },
                {
                  "args": [
                    {
                      "prim": "mutez"
                    },
                    {
                      "int": "0"
                    }
                  ],
                  "prim": "PUSH"
                },
                [
                  [
                    {
                      "prim": "COMPARE"
                    },
                    {
                      "prim": "EQ"
                    }
                  ],
                  {
                    "args": [
                      [],
                      [
                        [
                          {
                            "prim": "UNIT"
                          },
                          {
                            "prim": "FAILWITH"
                          }
                        ]
                      ]
                    ],
                    "prim": "IF"
                  }
                ],
                {
                  "args": [
                    [
                      {
                        "prim": "SWAP"
                      },
                      [
                        {
                          "prim": "DUP"
                        },
                        {
                          "args": [
                            [
                              {
                                "annots": [
                                  "@%%"
                                ],
                                "prim": "CDR"
                              },
                              [
                                {
                                  "annots": [
                                    "@%%"
                                  ],
                                  "prim": "CAR"
                                },
                                {
                                  "annots": [
                                    "%@",
                                    "%"
                                  ],
                                  "prim": "PAIR"
                                }
                              ]
                            ]
                          ],
                          "prim": "DIP"
                        },
                        {
                          "annots": [
                            "@%%"
                          ],
                          "prim": "CAR"
                        },
                        {
                          "annots": [
                            "%@",
                            "%@"
                          ],
                          "prim": "PAIR"
                        }
                      ],
                      {
                        "args": [
                          {
                            "prim": "operation"
                          }
                        ],
                        "prim": "NIL"
                      },
                      {
                        "prim": "PAIR"
                      }
                    ],
                    [
                      {
                        "prim": "BALANCE"
                      },
                      {
                        "prim": "UNIT"
                      },
                      {
                        "prim": "TRANSFER_TOKENS"
                      },
                      {
                        "args": [
                          {
                            "prim": "operation"
                          }
                        ],
                        "prim": "NIL"
                      },
                      {
                        "prim": "SWAP"
                      },
                      {
                        "prim": "CONS"
                      },
                      {
                        "prim": "PAIR"
                      }
                    ]
                  ],
                  "prim": "IF_LEFT"
                }
              ]
            ],
            "prim": "IF_LEFT"
          }
        ]
      ],
      "prim": "code"
    }
  ],
  "storage": {
    "args": [
      {
        "int": "17"
      },
      {
        "args": [
          {
            "bytes": "0000176e8f231f39c20a1cbd1ce3cee7806abf52914e"
          },
          {
            "args": [
              {
                "int": "1500000"
              },
              {
                "int": "500000"
              }
            ],
            "prim": "Pair"
          }
        ],
        "prim": "Pair"
      }
    ],
    "prim": "Pair"
  }
}

Type Definitions

Like other popular smart contract languages Michelson allows a developer to export multiple functions (entrypoints) and define their input parameters. Types can range from simple scalars, lists, sets and keyed maps to complex constructs composed from nested pairs and optional arguments. Contracts can persist data in private storage or a key-value store (bigmap), both of them require type definition to initialize. These types form the basis for our generic data extraction layer. Without them we would had to rely on unpleasant implementation details like it's the case when you parse Ethereum ERC20 data from logs.

Annotations and Unboxing

The other nice thing about Michelson is that developers can add human readable labels to entrypoints, types and data. These annotations make it possible to extract structured data from raw primitives.

When available, the API uses type annotations to decompose Michelson primitives into nested JSON objects, a process we call unboxing. This works for all contract-related data such as call parameters, entrypoints, storage and bigmap entries. Type annotations become JSON property names and values are represented in the type's native form instead of less expressive binary or integer data (e.g. a base58check address or ISO timestamp instead of bytes and int).

Well designed smart contracts (like the baker registry) use annotations to make their data easy to consume outside the blockchain. Unfortunately not all developers annotate their contracts just yet, but we believe the availability and simplicity of our new API provides a strong incentive to do so in the future.

Before: Original Storage Type Spec as Michelson JSON (Tezos RPC)
{
  "args": [
    {
      "args": [
        {
          "args": [
            {
              "prim": "key_hash"
            },
            {
              "args": [
                {
                  "args": [
                    {
                      "annots": [
                        "%data"
                      ],
                      "args": [
                        {
                          "args": [
                            {
                              "args": [
                                {
                                  "args": [
                                    {
                                      "annots": [
                                        "%bakerName"
                                      ],
                                      "prim": "bytes"
                                    },
                                    {
                                      "annots": [
                                        "%openForDelegation"
                                      ],
                                      "prim": "bool"
                                    }
                                  ],
                                  "prim": "pair"
                                },
                                {
                                  "annots": [
                                    "%bakerOffchainRegistryUrl"
                                  ],
                                  "prim": "bytes"
                                }
                              ],
                              "prim": "pair"
                            },
                            {
                              "args": [
                                {
                                  "args": [
                                    {
                                      "annots": [
                                        "%split"
                                      ],
                                      "prim": "nat"
                                    },
                                    {
                                      "annots": [
                                        "%bakerPaysFromAccounts"
                                      ],
                                      "args": [
                                        {
                                          "prim": "address"
                                        }
                                      ],
                                      "prim": "list"
                                    }
                                  ],
                                  "prim": "pair"
                                },
                                {
                                  "args": [
                                    {
                                      "args": [
                                        {
                                          "args": [
                                            {
                                              "annots": [
                                                "%minDelegation"
                                              ],
                                              "prim": "nat"
                                            },
                                            {
                                              "annots": [
                                                "%subtractPayoutsLessThanMin"
                                              ],
                                              "prim": "bool"
                                            }
                                          ],
                                          "prim": "pair"
                                        },
                                        {
                                          "args": [
                                            {
                                              "annots": [
                                                "%payoutDelay"
                                              ],
                                              "prim": "int"
                                            },
                                            {
                                              "args": [
                                                {
                                                  "annots": [
                                                    "%payoutFrequency"
                                                  ],
                                                  "prim": "nat"
                                                },
                                                {
                                                  "annots": [
                                                    "%minPayout"
                                                  ],
                                                  "prim": "int"
                                                }
                                              ],
                                              "prim": "pair"
                                            }
                                          ],
                                          "prim": "pair"
                                        }
                                      ],
                                      "prim": "pair"
                                    },
                                    {
                                      "args": [
                                        {
                                          "args": [
                                            {
                                              "annots": [
                                                "%bakerChargesTransactionFee"
                                              ],
                                              "prim": "bool"
                                            },
                                            {
                                              "annots": [
                                                "%paymentConfigMask"
                                              ],
                                              "prim": "nat"
                                            }
                                          ],
                                          "prim": "pair"
                                        },
                                        {
                                          "args": [
                                            {
                                              "annots": [
                                                "%overDelegationThreshold"
                                              ],
                                              "prim": "nat"
                                            },
                                            {
                                              "annots": [
                                                "%subtractRewardsFromUninvitedDelegation"
                                              ],
                                              "prim": "bool"
                                            }
                                          ],
                                          "prim": "pair"
                                        }
                                      ],
                                      "prim": "pair"
                                    }
                                  ],
                                  "prim": "pair"
                                }
                              ],
                              "prim": "pair"
                            }
                          ],
                          "prim": "pair"
                        }
                      ],
                      "prim": "option"
                    },
                    {
                      "annots": [
                        "%reporterAccount"
                      ],
                      "args": [
                        {
                          "prim": "address"
                        }
                      ],
                      "prim": "option"
                    }
                  ],
                  "prim": "pair"
                },
                {
                  "annots": [
                    "%last_update"
                  ],
                  "prim": "timestamp"
                }
              ],
              "prim": "pair"
            }
          ],
          "prim": "big_map"
        },
        {
          "args": [
            {
              "annots": [
                "%owner"
              ],
              "prim": "address"
            },
            {
              "args": [
                {
                  "annots": [
                    "%signup_fee"
                  ],
                  "prim": "mutez"
                },
                {
                  "annots": [
                    "%update_fee"
                  ],
                  "prim": "mutez"
                }
              ],
              "prim": "pair"
            }
          ],
          "prim": "pair"
        }
      ],
      "prim": "pair"
    }
  ],
  "prim": "storage"
}

After: Decoded (Unboxed) Storage Type (TzStats API)
{
  "storage_type": {
    "0@big_map": {
      "0": "key_hash",
      "1": {
        "data@option": {
          "bakerChargesTransactionFee": "bool",
          "bakerName": "bytes",
          "bakerOffchainRegistryUrl": "bytes",
          "bakerPaysFromAccounts@list": "address",
          "minDelegation": "nat",
          "minPayout": "int",
          "openForDelegation": "bool",
          "overDelegationThreshold": "nat",
          "paymentConfigMask": "nat",
          "payoutDelay": "int",
          "payoutFrequency": "nat",
          "split": "nat",
          "subtractPayoutsLessThanMin": "bool",
          "subtractRewardsFromUninvitedDelegation": "bool"
        },
        "last_update": "timestamp",
        "reporterAccount@option": "address"
      }
    },
    "owner": "address",
    "signup_fee": "mutez",
    "update_fee": "mutez"
  }
}

To access all static and dynamic data about a smart contract we have added some new API endpoints. These endpoints allow you to access the decoded/unboxed data per default and optionally the original Michelson primitives (add prim=true to your query).

# New Smart Contract API Endpoints
GET /explorer/contract/{hash}          // read contract metadata (incl ids of bigmaps owned)
GET /explorer/contract/{hash}/script   // read code, storage type and entrypoints
GET /explorer/contract/{hash}/storage  // read current or historic storage state
GET /explorer/contract/{hash}/calls    // list contract calls with decoded params, storage and bigmap updates

TzStats Bigmap Index

Bigmaps are key-value stores for large data collections that are lazy-loaded on access. Since Babylon, smart contracts can own multiple bigmaps, copy them, pass them in calls and use a wide range of key types to store data. Knowing key and value types from a storage spec we can easily unbox bigmap entries in a similar way to the type unboxing above.

Before: Bigmap Key and Value as Michelson Primitives (only the value is exported by the Tezos RPC)
{
  "key": {
    "bytes": "00002fe7db5218a1d674c88dd9d9421ac60b8eb3e5"
  },
  "value": {
    "args": [
      {
        "args": [
          {
            "args": [
              {
                "args": [
                  {
                    "args": [
                      {
                        "args": [
                          {
                            "bytes": "54657a6f732053656f756c"
                          },
                          {
                            "prim": "False"
                          }
                        ],
                        "prim": "Pair"
                      },
                      {
                        "bytes": ""
                      }
                    ],
                    "prim": "Pair"
                  },
                  {
                    "args": [
                      {
                        "args": [
                          {
                            "int": "10000"
                          },
                          []
                        ],
                        "prim": "Pair"
                      },
                      {
                        "args": [
                          {
                            "args": [
                              {
                                "args": [
                                  {
                                    "int": "1000000"
                                  },
                                  {
                                    "prim": "True"
                                  }
                                ],
                                "prim": "Pair"
                              },
                              {
                                "args": [
                                  {
                                    "int": "6"
                                  },
                                  {
                                    "args": [
                                      {
                                        "int": "1"
                                      },
                                      {
                                        "int": "0"
                                      }
                                    ],
                                    "prim": "Pair"
                                  }
                                ],
                                "prim": "Pair"
                              }
                            ],
                            "prim": "Pair"
                          },
                          {
                            "args": [
                              {
                                "args": [
                                  {
                                    "prim": "False"
                                  },
                                  {
                                    "int": "16383"
                                  }
                                ],
                                "prim": "Pair"
                              },
                              {
                                "args": [
                                  {
                                    "int": "100"
                                  },
                                  {
                                    "prim": "True"
                                  }
                                ],
                                "prim": "Pair"
                              }
                            ],
                            "prim": "Pair"
                          }
                        ],
                        "prim": "Pair"
                      }
                    ],
                    "prim": "Pair"
                  }
                ],
                "prim": "Pair"
              }
            ],
            "prim": "Some"
          },
          {
            "prim": "None"
          }
        ],
        "prim": "Pair"
      },
      {
        "int": "0"
      }
    ],
    "prim": "Pair"
  }
}

After: Unboxed Bigmap Entry using property names from storage type annotations (TzStats API)
{
  "key": "tz1Kf25fX1VdmYGSEzwFy1wNmkbSEZ2V83sY",
  "key_hash": "expruAS8RTHsR5mjPZDTsJ5vbLYN1MHAss5dcxWJAqWHa7smDPwdKX",
  "key_binary": "00002fe7db5218a1d674c88dd9d9421ac60b8eb3e5",
  "value": {
    "data": {
      "bakerChargesTransactionFee": false,
      "bakerName": "54657a6f732053656f756c",
      "bakerOffchainRegistryUrl": "",
      "bakerPaysFromAccounts": [],
      "minDelegation": "1000000",
      "minPayout": "0",
      "openForDelegation": false,
      "overDelegationThreshold": "100",
      "paymentConfigMask": "16383",
      "payoutDelay": "6",
      "payoutFrequency": "1",
      "split": "10000",
      "subtractPayoutsLessThanMin": true,
      "subtractRewardsFromUninvitedDelegation": true
    },
    "last_update": "1970-01-01T00:00:00Z",
    "reporterAccount": null
  },
  "meta": {
    "contract": "KT1ChNsEFxwyCbJyWGSL3KdjeXE28AY1Kaog",
    "bigmap_id": 17,
    "time": "2019-11-19T01:04:33Z",
    "height": 699579,
    "block": "BL24Redh4iuX5YvGfnK3688C6AoPKkXLoVHXmg6Jnn4mfCY8vBv",
    "is_replaced": false,
    "is_removed": false
  }
}

Bigmaps are easy use in smart contracts, but outside access via the Tezos RPC is cumbersome. The only supported RPC operation is reading the value for a known key. Even if we assume a developer knows the key of interest, instead of the original typed key (e.g. an address like tz1Kf25fX1VdmYGSEzwFy1wNmkbSEZ2V83sY) the RPC requires a script expression hash (e.g. expruAS8RTHsR5mjPZDTsJ5vbLYN1MHAss5dcxWJAqWHa7smDPwdKX). This is not ideal and we don't see the reason for this limitation. That's why our bigmap API supports multiple key variants.

When a contract writes or deletes a bigmap entry, the corresponding change is exported as a big_map_diff in the operation receipt. Our indexer parses these updates and tracks every change to a bigmap, building a complete and browsable history. This allows you to

  • access bigmap values by key hash, native or binary encoded key
  • list all keys/values stored in a bigmap
  • list all updates to a bigmap, optionally starting at a certain block
  • access and list historic bigmap content at a block in the past
  • get native primitives, decoded and optionally unpacked data for keys and values

Here's a list of new API endpoints you can use to work with bigmaps. See our API documentation for a detailed description.

# Bigmap API Endpoints

GET /explorer/bigmap/{id}                // read bigmap metadata
GET /explorer/bigmap/{id}/type           // read bigmap type specification
GET /explorer/bigmap/{id}/keys           // list bigmap keys
GET /explorer/bigmap/{id}/values         // list bigmap key/value pairs
GET /explorer/bigmap/{id}/updates        // list bigmap updates
GET /explorer/bigmap/{id}/{key}          // read single bigmap value
GET /explorer/bigmap/{id}/{key}/updates  // list bigmap updates for a single key

Packed Data

Unlike Ethereum, Tezos does not support return types but contracts can work around this limitation by passing custom callback functions and data as parameters (called lambda). Lambdas are a powerful concept but in order to ship data alongside code the data needs to be packed.

Packing creates another layer of binary serialization which is easy to handle inside a contract using PACK/UNPACK instructions, but hard to digest outside. Packed data is still typed, but unfortunately there is no way to express a type specification or annotations right now. Even more unfortunate is that some contract developers store packed data as binary blobs in bigmap keys and values. Inspecting such contracts provides little insights unless you unpack everything.

For this reason the TzStats API supports a new query argument unpack=true which makes the API try to unpack any embedded value that looks like its packed. Without a type spec this is not ideal, but leads to surprisingly satisfying results.

Before: Michelson primitives for a packed entry from bigmap 14
{
  "key": {
    "bytes": "050100000005734d657461"
  },
  "value": {
    "bytes": "050707010000000d4453205465737420546f6b656e07070100000003445354000c"
  }
}

After: Unboxed and Unpacked Version (TzStats API)
{
  "key": "050100000005734d657461",
  "key_hash": "exprupRyLDyQCCK2jxCTQaSpNDKU9XhprJtCBTMh1fNScU1f2aGGaw",
  "key_binary": "050100000005734d657461",
  "key_unpacked": "sMeta",
  "key_pretty": "sMeta",
  "value": {
    "0@bytes": "050707010000000d4453205465737420546f6b656e07070100000003445354000c"
  },
  "value_unpacked": {
    "0@string": "DS Test Token",
    "1@string": "DST",
    "2@int": "12"
  },
  "meta": {
    "contract": "KT1RHkGHmMTvi4wimZYEbuV1gfY9MGm8meWg",
    "bigmap_id": 14,
    "time": "2019-10-25T22:00:51Z",
    "height": 665824,
    "block": "BLnJv58bSf5czFrG6G97XqrTJj8ea6tfvXLfaBzMvRTJFT3V5iH",
    "is_replaced": false,
    "is_removed": false
  }
}

Closing Remarks

The introduced API features are brand new and there are likely some bugs or corner cases that don't work just yet. The documentation on Michelson is notoriously scarce and most of our work is based on reverse-engineering and observing existing data on mainnet and different testnets.

If you find a bug, if some data from your contracts is missing or if you like to help us test more examples and edge cases, please contact us on Discord or Twitter.

If you are an application developer and would like to learn more about the API please read our API documentation and reach out to us.