Testing tickets
Testing code that uses tickets requires extra steps because of how tickets are used in Tezos operations.
LIGO provides the Proxy_ticket
module to help you test with tickets.
The problem with testing tickets
Tickets have specific limitations on the Tezos platform that affect how they can be used in LIGO tests. For example, tickets always have the address of the contract that created it as the ticketer field. Also, their data payload cannot be changed after the ticket is created.
As a result, you can't create a ticket in a LIGO test with Tezos.Next.Ticket.create
and use it to test smart contract origination or entrypoints.
If LIGO allowed you to create and use tickets in this way, you could edit the ticket or assign a ticketer that was not the contract that created it.
If you try to use such a ticket in smart contract operations, the operations fail.
You also can't compile LIGO expressions that include tickets and use the compiled Michelson. If you compile an expression that includes a ticket, the value is represented in Michelson as pairs. For example, this code compiles a ticket with a binary value as its payload:
The result (within an option type) is represented in pairs, showing the address of the ticketer, the payload, and the amount of the ticket:
If you pass this value for the parameter of an operation that requires a ticket, the Tezos protocol blocks the operation and does not recognize this value as a ticket because doing so could allow you edit and submit a false ticket.
LIGO testing tools to provide ways to create tickets via a proxy contract so you can use tickets in tests.
Proxy ticket contracts
The LIGO test library provides a Proxy_ticket
module which helps in working with tickets in the test framework.
Instead of creating tickets yourself, you use a proxy contract to create tickets and send them with operations.
The Proxy_ticket
module provides these functions:
init_transfer
: Creates a proxy contract that you can use as the source of tickets in test operationstransfer
: Uses a proxy contract to create a ticket and send it as the parameter of a smart contract calloriginate
: Uses a proxy contract to originate a smart contract with initial storage that includes a ticket
Due to a limitation in the testing framework, you can use the proxy ticket contract only with contracts that contain a single entrypoint.
Originating contracts with tickets
To originate a contract with one or more tickets in its storage, you can use a proxy contract to generate the tickets and include them in the origination operation.
For example, this contract stores an integer and a ticket. It provides an entrypoint that reads the ticket and adds its amount to the integer in storage:
To originate this contract, you need a ticket for its initial storage value. To create this ticket, you use a proxy ticket contract.
To create a proxy ticket contract, create a function that returns a value of the initial storage for the contract or the parameter for the smart contract call. In this example, the function returns zero for the integer and a ticket created by the proxy. Then, the test uses the proxy contract to originate the contract to test:
To verify that the ticket is in the contract storage, you must use the Test.Proxy_ticket.get_storage
function to retrieve the ticket from the contract storage.
This function provides tickets as unforged tickets, which are tickets that you can read freely without destroying them and recreating them with the Tezos.Next.Ticket.read
function.
In this code, the test retrieves the ticket from the contract and verifies its contents:
Note that because this is a single-entrypoint contract, the LIGO compiler renames the entrypoint to default
.
Calling entrypoints with tickets
To test entrypoints that accept tickets, you use a proxy contract to create the ticket and send the call to the entrypoint. The process is similar to originating a contract with a proxy: you create a function that returns the parameter for the entrypoint and create a proxy based on that function.
For example, this contract has an entrypoint that receives an integer and a ticket that contains an integer. It multiplies the integer in the first parameter with the integer in the ticket payload and with the ticket amount and adds the result to the integer in storage:
To test the contract, originate it as usual. Then create a function that returns the parameter for the entrypoint, create a proxy based on this function, and use the proxy to call the entrypoint: