Skip to content
On this page

Tickets

Tezos tickets are authenticated quantities issued by contracts. A ticket of type sp.ticket[t] has three elements:

  • Its ticketer, which is the contract that issued the ticket

  • Its contents of type t, also knowns as the wrapped value or payload, which can be any data type

  • Its amount of type sp.nat, which is an arbitrary number that represents a quantity or value for the ticket

A ticket's ticketer and contents cannot be changed.

Tickets themselves cannot be duplicated, but you can split one ticket into multiple tickets by creating duplicate tickets each with a portion of the original ticket's amount. The new tickets have the same ticketer and contents, and the sum of their amounts is always the amount of the original ticket. Similarly, you can join tickets with matching ticketers and contents into a single ticket with the sum of the joined tickets' amounts.

You cannot read the contents of a ticket directly; you must use sp.read_ticket to access it.

sp.ticket(contents: t, amount: sp.nat) → sp.ticket[t]

Create a ticket with the given contents and amount. The ticketer is always the contract's address via sp.self_address().

sp.read_ticket(ticket: sp.ticket[t]) → sp.pair[sp.record(ticketer=sp.address, contents=t, amount=sp.nat), sp.ticket[t]]

Reads the contents of a ticket and returns a pair of:

  • The ticket data, itself a record of the ticket's ticketer, contents, and amount.

  • A copy of the original ticket that can still be used.

Note that using sp.read_ticket on a ticket consumes it, destroying the original sp.ticket type. To access the ticket again, you muse use the copy that the function returns.

This example creates a ticket and then reads it:

smartpy
# Create ticket
ticket_contents = (sp.int(5), "hello")
ticket = sp.ticket(ticket_contents, 2)

# Read ticket
(ticket_data, new_ticket) = sp.read_ticket(ticket)
assert ticket_data.contents == ticket_contents
assert ticket_data.amount == 2
assert ticket_data.ticketer == sp.self_address()

Joining and splitting tickets

sp.join_tickets(t1: sp.ticket[t], t2: sp.ticket[t]) → sp.ticket[t]

Merges two tickets into one by adding their amounts. Fails if the tickets differ in their ticketer or contents.

sp.split_ticket(ticket: sp.ticket[t], amount1: sp.nat, amount2: sp.nat) → sp.pair[sp.ticket[t], sp.ticket[t]]

Splits a ticket into two parts with the specified amounts. Fails if amount1 + amount2 is not equal to the original ticket's amount.

For example, this code creates a ticket, splits it, and joins the split tickets:

smartpy
# Create ticket
ticket_contents = (sp.int(5), "hello")
big_ticket = sp.ticket(ticket_contents, 100)

# Split ticket
(small_ticket_1, small_ticket_2) = sp.split_ticket(big_ticket, 70, 30)

# Verify ticket amounts
(data_1, small_ticket_1_new) = sp.read_ticket(small_ticket_1)
assert data_1.contents == ticket_contents
assert data_1.amount == 70
(data_2, small_ticket_2_new) = sp.read_ticket(small_ticket_2)
assert data_2.contents == ticket_contents
assert data_2.amount == 30

## Join tickets
joined_ticket = sp.join_tickets(small_ticket_1_new, small_ticket_2_new)
(data_joined, joined_ticket_new) = sp.read_ticket(joined_ticket)
assert data_joined.amount == 100

Transferring tickets

To transfer a ticket, send it as a parameter to an entrypoint with sp.transfer as usual:

smartpy
contract_opt = sp.contract(sp.ticket[sp.pair[sp.int, sp.string]], contract_address, entrypoint = "accept_ticket")
with sp.match(contract_opt):
  with sp.case.Some as contract:
      sp.transfer(ticket, sp.mutez(0), contract)
  with None:
      sp.trace("Failed to find contract")