Null ticket

A common pattern for a contract is to hold some tickets, and when it receives more tickets of the same kind, to join them with the ticket in its storage.

Unfortunately, the contract can typically not be originated with a ticket already in its storage, which means an option type must be used, and the option value pattern matched every time it’s used.

To simplify this pattern, we could use a “null ticket” with the following properties:

  1. a null ticket can be specified in a smart-contract’s initial storage during an origination
  2. a null ticket can be created using a Michelson instruction NULL_TICKET : 'a -> 'a ticket
  3. a null ticket’s ticketer is the null address (tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU), its amount is always 0
  4. a null ticket can be joined with any other kind of ticket so long as the value matches (the ticketer is ignored)

This makes a lot of code patterns much easier, but it also means being a bit more careful with invariants around tickets. I don’t think it breaks invariants we deeply care about, but it’s important to be careful about such things.


That would also be a great idea when getting a ticket from a big_map. Currently, when using GET_AND_UPDATE to get a ticket from a big_map, I have to replace the actual ticket with a “fake” ticket. I also have to check the ticket I get is not a fake one, so the value must be obviously fake (for example, I am working on a use case with a timestamp stored in the ticket, so I set it to 0 for the fake ticket).
A null ticket would require less imagination to set a fake value and would produce less IF_SOME as well.

Why not just remove it from the map?

It wouldn’t change the behaviour of GET_AND_UPDATE, if I want to get a ticket out of the big map, I have to replace it with a value of the same type, although I don’t need that value in the first place. Maybe a GET_AND_REMOVE instruction would be useful then :slight_smile:

You can just pass None

Passing None requires having optional values in the big_map, which adds more complexity to the contract and extra nested IF_SOME when getting these values. A NULL ticket wouldn’t require being wrapped in an optional value (if I understood the concept correctly).

No, it doesn’t. The map already returns to you optional values and treats None as a way to delete a value.

Interesting, I will test that in the contract I am working on at the moment and document it, thanks!