Edo Period print of Nagasaki Bay and Dejima (https://www.japanvisitor.com/japanese-culture/history/edo-japan-history)

Tickets on Tezos — Part 1

Introduction to Tezos’ new support for “tickets” in Edo

Eli Guenzburger
TQ Tezos
Published in
13 min readJan 13, 2021

--

By Eli Guenzburger

Introduction

Last month, the latest Tezos protocol upgrade proposal, “Edo” was announced and injected and testing on the new test network “Edonet” began soon after.

One of Edo’s most exciting features is tickets, the subject of this tutorial series. Tickets provide a convenient mechanism for smart contracts to grant portable permissions or issue tokens without requiring the token holder or permission grantee to interact with a centralized contract.

At its core, a ticket is a way for a smart contract to authenticate data with respect to a Tezos address. It is impossible for a contract to “forge” a ticket by creating one that appears to have been created by a different address, or duplicate an existing ticket using the DUP instruction. Tickets can be controlled with the following 4 new Michelson opcodes.

  • TICKET creates a ticket that contains the address of the contract that created the ticket, some value and some natural number amount.
  • Two tickets created by the same address that also wrap the same value can be joined using the JOIN_TICKET opcode. Doing so results in a new ticket of the same type with an amount equal to the sum of the amounts of the previous two tickets, which are then destroyed.
  • SPLIT_TICKET is the inverse of JOIN_TICKET and breaks a single ticket into two new tickets of the same address and value with quantities that sum to the original, which is destroyed.
  • Finally, READ_TICKET can be used to read the contents of a ticket.

Below, we explore how tickets differ from existing token standards like FA1.2 or FA2 and present an example NFT based on tickets and a simple NFT auction demo.

Key Resources

Tickets as tokens

The relationship between ticket based assets and traditional Tezos assets (FA1.2, FA2) is comparable to the relationship between cash and money in a bank account. When someone purchases a cup of coffee with a debit card, the coffee shop must communicate with the bank and ask them to subtract the price of the coffee from the customer’s account and transfer it to the coffee shop’s account. Similarly, transferring some FA2 token to an address means users must make a call to the FA2 contract asking it to execute the transfer. Then, to query their balance, users will need to make a call to the FA2 contract and ask it to call the user back, along with their balance. This pattern can become both expensive and can potentially introduce security vulnerabilities in Tezos unless a smart contract writer takes great care.

In contrast, users can send ticket-based assets directly from their wallets to the wallets of other users wallets or contracts, without communicating with the originating contract as they would need to with traditional FA2s. The receiver of a ticket can know with certainty who created it, as tickets are non-forgeable, like physical money.

Tickets are perfectly suited for representing assets where users are in full control of their tokens. Tickets are less suited for cases like permissioned assets in which an admin or set of admins have control over the token lifecycle of the tokens, such as freezing (although this is an area that is being explored). Additional work to explore the wrapping of FA1.2 / FA2 tokens as tickets and vice versa is underway.

Ticket-Based NFT Auction

NFTs are an increasingly popular way to represent unique digital assets. Tickets make it especially easy to create NFTs and auction them off without having to maintain maps of ownership or requiring purchasers to interact with a centralized contract to manage their NFT. An FA2-based auction example of an auction with traditional Tezos FA2 like assets here.

NFT Auctions can be performed using tickets with only a single NFT ticket-auction contract, and ticket-wallets for auction participants. We will auction off Ticket-NFTs using a Dutch, descending price auction implemented in Ligo.

https://github.com/tqtezos/ticket-tutorials/blob/7a4f421cb7349e94566b4aedae342ae8f48cc4db/tutorials/auction/ligo/nft_auction.mligo

Then, users who deploy an NFT wallet like the one we implemented in Ligo below can create NFTs, configure auctions with them using the contract above, and trade NFTs amongst themselves. All of the NFTs a user owns will actually be in their wallet’s storage, rather than in a separate contract. It should be noted that these wallet contracts are just examples of what a ticket wallet might look like (creating standards for ticket wallets is being explored). Also, there are important concerns about front-running on Tezos and in DeFi in general that this type of auction may be vulnerable to without further refinement.

https://github.com/tqtezos/ticket-tutorials/blob/7a4f421cb7349e94566b4aedae342ae8f48cc4db/tutorials/auction/ligo/nft_wallet.mligo

Demo

We will demonstrate an auction using the contracts written above. The steps of the auction are simple. Alice creates an NFT in her wallet and auctions it off using her auction contract. No one purchases the NFT at the starting price of 100 mutez, so she drops the price to 90 mutez. Then, Bob purchases the NFT resulting in it being sent to his wallet and his 90 mutez being sent to Alice. You can view the github repo containing these contracts and the full output of this demo here and see the wallet contracts and the auction contract on tzstats’ edonet explorer.

1. Alice originates nft-auction contract

$ tezos-client originate contract nft-auction transferring 0 from alice running "$(pwd)/michelson/nft_auction.tz" --dry-run --init "Pair (Pair \"tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt\" (Pair 0 (Pair 0 (Pair False ( Pair 0 0))))) {}" --burn-cap 1

Waiting for the node to be bootstrapped...
Current head: BLjqDeA5khok (timestamp: 2021-01-06T00:27:58.000-00:00, validation: 2021-01-06T00:28:15.004-00:00)
Node is bootstrapped.
Estimated gas: 12295.862 units (will add 100 for safety)
Estimated storage: 2534 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'oofgtQf3UjQPnZ67LV9erMR7ijhKs3EZPJmckEWeec746TAUDRq'
Waiting for the operation to be included...
Operation found in block: BL4Dgpq8B8idYiCBRBgj41Ck3LXqR1CHCkhJujDcWWjAvexuXXY (pass: 3, offset: 0)
This sequence of operations was run:
Manager signed operations:
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
Fee to the baker: ꜩ0.003734
Expected counter: 103191
Gas limit: 12396
Storage limit: 2554 bytes
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ............ -ꜩ0.003734
fees(tz1aWXP237BLwNHJcCD4b3DutCevhqq2T1Z9,50) ... +ꜩ0.003734
Origination:
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
Credit: ꜩ0
Script:
{ parameter
(or (or (or (contract %buy (ticket nat)) (contract %cancel (ticket nat)))
(or (pair %configure
(nat %opening_price)
(pair (nat %set_reserve_price)
(pair (timestamp %set_start_time) (pair (int %set_round_time) (ticket %ticket nat)))))
(nat %drop_price)))
(unit %start)) ;
storage
(pair (pair %data
(address %admin)
(pair (nat %current_price)
(pair (nat %reserve_price)
(pair (bool %in_progress) (pair (timestamp %start_time) (int %round_time))))))
(big_map %tickets nat (ticket nat))) ;
code { ... }
Initial storage:
(Pair (Pair "tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt" (Pair 0 (Pair 0 (Pair False (Pair 0 0)))))
{})
No delegate for this contract
This origination was successfully applied
Originated contracts:
KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG
Storage size: 2277 bytes
Updated big_maps:
New map(139) of type (big_map nat (ticket nat))
Paid storage size diff: 2277 bytes
Consumed gas: 12295.862
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ... -ꜩ0.56925
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ... -ꜩ0.06425

New contract KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG originated.
The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for oofgtQf3UjQPnZ67LV9erMR7ijhKs3EZPJmckEWeec746TAUDRq to be included --confirmations 30 --branch BLjqDeA5khokn71SHexRDVESL8tQrdZdKqK2ZdDQo5M7Z7fGMX4
and/or an external block explorer.
Contract memorized as nft-auction.

2. Alice originates her nft-wallet contract and sets herself as the admin

$ tezos-client originate contract nft-wallet transferring 0 from alice running "$(pwd)/michelson/nft_wallet.tz" --init "Pair \"tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt\" (Pair {} (Pair 0 {}))" --burn-cap 0.305

Waiting for the node to be bootstrapped...
Current head: BMFHdefZKb5g (timestamp: 2021-01-06T01:26:38.000-00:00, validation: 2021-01-06T01:27:00.749-00:00)
Node is bootstrapped.
Estimated gas: 7763.475 units (will add 100 for safety)
Estimated storage: 1725 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'opEQ4YGA2W4HNK3aT7KEwRaWwUYUwYX96Vx1A57PxtqsUvvDCeR'
Waiting for the operation to be included...
Operation found in block: BMGXejtwcaBnVhVyVPngrRszStasV3uzpGpwTq358rrSwJdCBfx (pass: 3, offset: 0)
This sequence of operations was run:
Manager signed operations:
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
Fee to the baker: ꜩ0.002437
Expected counter: 103193
Gas limit: 7864
Storage limit: 1745 bytes
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ............ -ꜩ0.002437
fees(tz1VWasoyFGAWZt5K2qZRzP3cWzv3z7MMhP8,50) ... +ꜩ0.002437
Origination:
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
Credit: ꜩ0
Script:
{ parameter
(or (or (or (pair %auction
(contract %destination
(pair (nat %opening_price)
(pair (nat %set_reserve_price)
(pair (timestamp %set_start_time) (pair (int %set_round_time) (ticket %ticket nat))))))
(pair (nat %opening_price)
(pair (nat %reserve_price)
(pair (timestamp %start_time) (pair (int %round_time) (nat %ticket_id))))))
(nat %burn))
(or (map %mint string bytes) (ticket %receive nat)))
(pair %send (contract %destination (ticket nat)) (nat %ticket_id))) ;
storage
(pair (address %admin)
(pair (big_map %tickets nat (ticket nat))
(pair (nat %current_id) (big_map %token_metadata nat (pair nat (map string bytes)))))) ;
code { ... }
Initial storage:
(Pair "tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt" (Pair {} (Pair 0 {})))
No delegate for this contract
This origination was successfully applied
Originated contracts:
KT1EAMUQC1yJ2sRPNPpLHVMGCzroYGe1C1ea
Storage size: 1468 bytes
Updated big_maps:
New map(141) of type (big_map nat (pair nat (map string bytes)))
New map(140) of type (big_map nat (ticket nat))
Paid storage size diff: 1468 bytes
Consumed gas: 7763.475
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ... -ꜩ0.367
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ... -ꜩ0.06425

New contract KT1EAMUQC1yJ2sRPNPpLHVMGCzroYGe1C1ea originated.
The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for opEQ4YGA2W4HNK3aT7KEwRaWwUYUwYX96Vx1A57PxtqsUvvDCeR to be included --confirmations 30 --branch BMFHdefZKb5gWUoDW9gEJ7Z2Y5NZgFthsGKzZCq9VNa8nV7xyhW
and/or an external block explorer.
Contract memorized as nft-wallet.

3. Alice mints herself a ticket based nft with metadata

$ tezos-client transfer 0 from alice to nft-wallet --entrypoint "mint" --arg "{Elt \"\" 0x68747470733a2f2f6769746875622e636f6d2f747174657a6f732f7469636b65742d7475746f7269616c732f747265652f6d61696e2f7475746f7269616c732f61756374696f6e2f6c69676f}" --burn-cap 1

Waiting for the node to be bootstrapped...
Current head: BMYZUPD6fiFC (timestamp: 2021-01-06T01:27:38.000-00:00, validation: 2021-01-06T01:27:56.209-00:00)
Node is bootstrapped.
Estimated gas: 9679.058 units (will add 100 for safety)
Estimated storage: 262 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'opZoMEUqAQPRysiY9dKLduwwdurQNRFufSNSDWuquEiYgdHzsQd'
Waiting for the operation to be included...
Operation found in block: BL1zqiPMAk6x5ezZ5XZ7QrWAsSW4XUr57mbNgPkjK8SKBZq1ZTJ (pass: 3, offset: 0)
This sequence of operations was run:
Manager signed operations:
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
Fee to the baker: ꜩ0.001332
Expected counter: 103194
Gas limit: 9780
Storage limit: 282 bytes
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ............ -ꜩ0.001332
fees(tz1Na5QB98cDA3BC1SQU4w3iiWGVGktU14LE,50) ... +ꜩ0.001332
Transaction:
Amount: ꜩ0
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
To: KT1EAMUQC1yJ2sRPNPpLHVMGCzroYGe1C1ea
Entrypoint: mint
Parameter: { Elt ""
0x68747470733a2f2f6769746875622e636f6d2f747174657a6f732f7469636b65742d7475746f7269616c732f747265652f6d61696e2f7475746f7269616c732f61756374696f6e2f6c69676f }
This transaction was successfully applied
Updated storage:
{ 0x00000d4f0cf2fae2437f924120ef030f53abd4d4e520 ; 140 ; 1 ; 141 }
Updated big_maps:
Set map(141)[0] to (Pair 0
{ Elt ""
0x68747470733a2f2f6769746875622e636f6d2f747174657a6f732f7469636b65742d7475746f7269616c732f747265652f6d61696e2f7475746f7269616c732f61756374696f6e2f6c69676f })
Set map(140)[0] to (Pair 0x013d32a903fa4cf753f0d7075a7ab8395c501a2caf00 (Pair 0 1))
Storage size: 1730 bytes
Paid storage size diff: 262 bytes
Consumed gas: 9679.058
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ... -ꜩ0.0655

The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for opZoMEUqAQPRysiY9dKLduwwdurQNRFufSNSDWuquEiYgdHzsQd to be included --confirmations 30 --branch BMYZUPD6fiFCZ2rpncMoCb9DrAdKCVdyHc8HNFJYwnFtFcdk4Vy
and/or an external block explorer.

4. Alice auctions off her ticket based nft through her wallet, which sends her nft to her auction contract and configures various auction settings. The starting price of the auction is 100 mutez.

$ tezos-client transfer 0 from alice to nft-wallet --entrypoint "auction" --arg "Pair \"KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG%configure\" (Pair 100 (Pair 10 (Pair 0 (Pair 600 0))))" --burn-cap 1

Waiting for the node to be bootstrapped...
Current head: BLUeXUpmoSFg (timestamp: 2021-01-06T01:29:38.000-00:00, validation: 2021-01-06T01:30:07.976-00:00)
Node is bootstrapped.
Estimated gas: 34374.951 units (will add 100 for safety)
Estimated storage: 102 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'ooK5QXMJBWXPvEZDzaMs89D9UYFYfYmQNoaKuB4zgqCj1Tei8ci'
Waiting for the operation to be included...
Operation found in block: BKmS5cCwUGtDkrv4iEqS1YJXo9WLSsxYACfzmmpPTJrDQusTxE2 (pass: 3, offset: 0)
This sequence of operations was run:
Manager signed operations:
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
Fee to the baker: ꜩ0.003785
Expected counter: 103195
Gas limit: 34475
Storage limit: 122 bytes
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ............ -ꜩ0.003785
fees(tz1Na5QB98cDA3BC1SQU4w3iiWGVGktU14LE,50) ... +ꜩ0.003785
Transaction:
Amount: ꜩ0
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
To: KT1EAMUQC1yJ2sRPNPpLHVMGCzroYGe1C1ea
Entrypoint: auction
Parameter: (Pair "KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG%configure"
(Pair 100 (Pair 10 (Pair 0 (Pair 600 0)))))
This transaction was successfully applied
Updated storage:
{ 0x00000d4f0cf2fae2437f924120ef030f53abd4d4e520 ; 140 ; 1 ; 141 }
Updated big_maps:
Unset map(140)[0]
Storage size: 1630 bytes
Consumed gas: 20672.886
Internal operations:
Transaction:
Amount: ꜩ0
From: KT1EAMUQC1yJ2sRPNPpLHVMGCzroYGe1C1ea
To: KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG
Entrypoint: configure
Parameter: { 100 ;
10 ;
0 ;
600 ;
Pair 0x013d32a903fa4cf753f0d7075a7ab8395c501a2caf00 (Pair 0 1) }
This transaction was successfully applied
Updated storage:
(Pair { 0x00000d4f0cf2fae2437f924120ef030f53abd4d4e520 ;
100 ;
10 ;
False ;
0 ;
600 }
139)
Updated big_maps:
Set map(139)[0] to (Pair 0x013d32a903fa4cf753f0d7075a7ab8395c501a2caf00 (Pair 0 1))
Storage size: 2379 bytes
Paid storage size diff: 102 bytes
Consumed gas: 13702.065
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ... -ꜩ0.0255

The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for ooK5QXMJBWXPvEZDzaMs89D9UYFYfYmQNoaKuB4zgqCj1Tei8ci to be included --confirmations 30 --branch BM82CX9HwyUfhxLT4zUmhQj3KhUKhNCeGvcAmnHfgCiG8XHhYEd
and/or an external block explorer.

5. Alice starts her nft-auction by calling the nft-auction contract directly

$ tezos-client transfer 0 from alice to nft-auction --entrypoint "start" --burn-cap 1  

Waiting for the node to be bootstrapped...
Current head: BLZh6tEhMq6n (timestamp: 2021-01-06T01:38:08.000-00:00, validation: 2021-01-06T01:38:27.055-00:00)
Node is bootstrapped.
Estimated gas: 14131.842 units (will add 100 for safety)
Estimated storage: 4 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'opMf6wPTpaWmufemQnGyvbM7onTifqB296UffHokBwrxDaSXomj'
Waiting for the operation to be included...
Operation found in block: BLts9co3ToRazepdtna9dUXUNKEAR73ZZK6FfPmgyAqH1TnNy3k (pass: 3, offset: 0)
This sequence of operations was run:
Manager signed operations:
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
Fee to the baker: ꜩ0.001687
Expected counter: 103196
Gas limit: 14232
Storage limit: 24 bytes
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ............ -ꜩ0.001687
fees(tz1VWasoyFGAWZt5K2qZRzP3cWzv3z7MMhP8,50) ... +ꜩ0.001687
Transaction:
Amount: ꜩ0
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
To: KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG
Entrypoint: start
This transaction was successfully applied
Updated storage:
(Pair { 0x00000d4f0cf2fae2437f924120ef030f53abd4d4e520 ;
100 ;
10 ;
True ;
1609897118 ;
600 }
139)
Updated big_maps:
Set map(139)[0] to (Pair 0x013d32a903fa4cf753f0d7075a7ab8395c501a2caf00 (Pair 0 1))
Storage size: 2383 bytes
Paid storage size diff: 4 bytes
Consumed gas: 14131.842
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ... -ꜩ0.001

The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for opMf6wPTpaWmufemQnGyvbM7onTifqB296UffHokBwrxDaSXomj to be included --confirmations 30 --branch BLZh6tEhMq6nwcNvZHsduc3jeA99MdUmWCAeMrjAz66NWTStihL
and/or an external block explorer.

6. Bob originates his nft wallet and sets himself as the admin

$ tezos-client originate contract nft-wallet-bob transferring 0 from bob running "$(pwd)/michelson/nft_wallet.tz" --init "Pair \"tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y\" (Pair {} (Pair 0 {}))" --burn-cap 1

Waiting for the node to be bootstrapped...
Current head: BL6uqjE8sD1y (timestamp: 2021-01-06T01:49:38.000-00:00, validation: 2021-01-06T01:49:43.592-00:00)
Node is bootstrapped.
Estimated gas: 7763.475 units (will add 100 for safety)
Estimated storage: 1725 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'opTMzFwbY9HvmQpTff5ViujAFVqguz5TwZE9FoKWmGT9onsnCmq'
Waiting for the operation to be included...
Operation found in block: BLjD53iKVbm8eA166a7Py8bLN1SGqA7xhsfk1Gfmx92dk1gq8Br (pass: 3, offset: 0)
This sequence of operations was run:
Manager signed operations:
From: tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y
Fee to the baker: ꜩ0.000359
Expected counter: 103189
Gas limit: 1000
Storage limit: 0 bytes
Balance updates:
tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y ............ -ꜩ0.000359
fees(tz1dAfFc4QAre74yrPU2jFBLcgaAs9MLHryD,50) ... +ꜩ0.000359
Revelation of manager public key:
Contract: tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y
Key: edpkuj3qiKfzbptop91V44ia1NBomcQKgfgDk6mhT9EB73SEmgY6N7
This revelation was successfully applied
Consumed gas: 1000
Manager signed operations:
From: tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y
Fee to the baker: ꜩ0.002341
Expected counter: 103190
Gas limit: 7864
Storage limit: 1745 bytes
Balance updates:
tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y ............ -ꜩ0.002341
fees(tz1dAfFc4QAre74yrPU2jFBLcgaAs9MLHryD,50) ... +ꜩ0.002341
Origination:
From: tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y
Credit: ꜩ0
Script:
{ parameter
(or (or (or (pair %auction
(contract %destination
(pair (nat %opening_price)
(pair (nat %set_reserve_price)
(pair (timestamp %set_start_time) (pair (int %set_round_time) (ticket %ticket nat))))))
(pair (nat %opening_price)
(pair (nat %reserve_price)
(pair (timestamp %start_time) (pair (int %round_time) (nat %ticket_id))))))
(nat %burn))
(or (map %mint string bytes) (ticket %receive nat)))
(pair %send (contract %destination (ticket nat)) (nat %ticket_id))) ;
storage
(pair (address %admin)
(pair (big_map %tickets nat (ticket nat))
(pair (nat %current_id) (big_map %token_metadata nat (pair nat (map string bytes)))))) ;
code { ... }
Initial storage:
(Pair "tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y" (Pair {} (Pair 0 {})))
No delegate for this contract
This origination was successfully applied
Originated contracts:
KT1QQukCBULzFu6samB5FpbLNBXmNzArSpTs
Storage size: 1468 bytes
Updated big_maps:
New map(143) of type (big_map nat (pair nat (map string bytes)))
New map(142) of type (big_map nat (ticket nat))
Paid storage size diff: 1468 bytes
Consumed gas: 7763.475
Balance updates:
tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y ... -ꜩ0.367
tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y ... -ꜩ0.06425

New contract KT1QQukCBULzFu6samB5FpbLNBXmNzArSpTs originated.
The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for opTMzFwbY9HvmQpTff5ViujAFVqguz5TwZE9FoKWmGT9onsnCmq to be included --confirmations 30 --branch BL6uqjE8sD1yM7dtNxWzN6DqKWJb3CSMe5vpTiPYA1hqZuunbZH
and/or an external block explorer.
Contract memorized as nft-wallet-bob.

7. After the time of one round has passed without anyone buying the nft, Alice drops the price of her nft to 90 mutez.

$ tezos-client transfer 0 from alice to nft-auction --entrypoint "drop_price" --arg 90 --burn-cap


Waiting for the node to be bootstrapped...
Current head: BLxDjvZH2LVC (timestamp: 2021-01-06T01:52:58.000-00:00, validation: 2021-01-06T01:53:18.405-00:00)
Node is bootstrapped.
Estimated gas: 13244.841 units (will add 100 for safety)
Estimated storage: no bytes added
Operation successfully injected in the node.
Operation hash is 'ooPRGpr5VxKuLiVtpf2XTAfrRFKV12nYS92zu1WLEaiqSp6mTpd'
Waiting for the operation to be included...
Operation found in block: BLrEgcoRiqTBQ4FYnnoZUhdN8XqxqSbqYTfLuUKcnSfEgYfnbvB (pass: 3, offset: 0)
This sequence of operations was run:
Manager signed operations:
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
Fee to the baker: ꜩ0.001604
Expected counter: 103197
Gas limit: 13345
Storage limit: 0 bytes
Balance updates:
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ............ -ꜩ0.001604
fees(tz1aWXP237BLwNHJcCD4b3DutCevhqq2T1Z9,50) ... +ꜩ0.001604
Transaction:
Amount: ꜩ0
From: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
To: KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG
Entrypoint: drop_price
Parameter: 90
This transaction was successfully applied
Updated storage:
(Pair { 0x00000d4f0cf2fae2437f924120ef030f53abd4d4e520 ;
90 ;
10 ;
True ;
1609898008 ;
600 }
139)
Storage size: 2383 bytes
Consumed gas: 13244.841

The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for ooPRGpr5VxKuLiVtpf2XTAfrRFKV12nYS92zu1WLEaiqSp6mTpd to be included --confirmations 30 --branch BLxDjvZH2LVC9StR6oUvP131Yj27zrn1xCZ8D3spz16ApxBxuCS
and/or an external block explorer.

8. Bob buys the nft by sending 90 mutez to the auction contract, calling the buy entrypoint, and sending the address of his wallet contract. The nft is sent to Bob’s wallet and Alice is sent the 90 mutez.

$ tezos-client transfer 0.00009 from bob to nft-auction --entrypoint "buy" --arg "\"KT1QQukCBULzFu6samB5FpbLNBXmNzArSpTs%receive\"" --burn-cap 1

Waiting for the node to be bootstrapped...
Current head: BKkprtNFhPvu (timestamp: 2021-01-06T01:56:58.000-00:00, validation: 2021-01-06T01:57:02.519-00:00)
Node is bootstrapped.
Estimated gas: 31703.675 units (will add 100 for safety)
Estimated storage: 100 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'oopZR4d3gjdbt21UKBDGYJtZtjZkACU6QFWhRN5yPisQiCQU5Df'
Waiting for the operation to be included...
Operation found in block: BLz11WgtY8kzmif7weCJ8Qucgc4dEbHJUUy7RcHf2j5nDvXt6FH (pass: 3, offset: 0)
This sequence of operations was run:
Manager signed operations:
From: tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y
Fee to the baker: ꜩ0.00349
Expected counter: 103191
Gas limit: 31804
Storage limit: 120 bytes
Balance updates:
tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y ............ -ꜩ0.00349
fees(tz1Na5QB98cDA3BC1SQU4w3iiWGVGktU14LE,50) ... +ꜩ0.00349
Transaction:
Amount: ꜩ0.00009
From: tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y
To: KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG
Entrypoint: buy
Parameter: "KT1QQukCBULzFu6samB5FpbLNBXmNzArSpTs%receive"
This transaction was successfully applied
Updated storage:
(Pair { 0x00000d4f0cf2fae2437f924120ef030f53abd4d4e520 ;
90 ;
10 ;
False ;
1609898008 ;
600 }
139)
Updated big_maps:
Unset map(139)[0]
Storage size: 2283 bytes
Consumed gas: 20805.897
Balance updates:
tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y ... -ꜩ0.00009
KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG ... +ꜩ0.00009
Internal operations:
Transaction:
Amount: ꜩ0.00009
From: KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG
To: tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt
This transaction was successfully applied
Consumed gas: 1427
Balance updates:
KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG ... -ꜩ0.00009
tz1LrQB9HrJcUaD9NKEvV65tnaiU8trPXwmt ... +ꜩ0.00009
Transaction:
Amount: ꜩ0
From: KT1HWaMyNmjVGMBPUSm3QxJnFRLi4LQJi1tG
To: KT1QQukCBULzFu6samB5FpbLNBXmNzArSpTs
Entrypoint: receive
Parameter: (Pair 0x013d32a903fa4cf753f0d7075a7ab8395c501a2caf00 (Pair 0 1))
This transaction was successfully applied
Updated storage:
{ 0x0000b2d8083a660b2a77efe28a71bf09a933cd85613b ; 142 ; 1 ; 143 }
Updated big_maps:
Set map(142)[0] to (Pair 0x013d32a903fa4cf753f0d7075a7ab8395c501a2caf00 (Pair 0 1))
Storage size: 1568 bytes
Paid storage size diff: 100 bytes
Consumed gas: 9470.778
Balance updates:
tz1bwfmSYqrhUTAoybGdhWBBefsbuhNdcC2Y ... -ꜩ0.025

The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for oopZR4d3gjdbt21UKBDGYJtZtjZkACU6QFWhRN5yPisQiCQU5Df to be included --confirmations 30 --branch BKkprtNFhPvuUWTDn1mfML8TTPTYCeVX6vjHWPfGPCQ2nQrbSP4
and/or an external block explorer.

Huge thanks to everyone who helped with this article by giving feedback/edits and helping with the code in the demo — including Michael Klein, Arthur Breitman, Gabriel Alfour, Francois Maurel, Roland Zumkeller, Jacob Arluck, and Claude Barde.

--

--