I tested Tezos Part. 4
This is the fourth part of our “I tested Tezos” serie. Please, first read:
- Part 1: https://medium.com/chain-accelerator/i-tested-tezos-b254504775be
- Part 2: https://medium.com/chain-accelerator/i-tested-tezos-part-2-da5d94ce1259
- Part 3: https://medium.com/chain-accelerator/i-tested-tezos-part-3-b1e73ef9e608
In the last article, we went deep into Michelson. At the end, we were able to develop an auction smart contract, with two versions: one without a deadline and one with a deadline. In this 4th part, we will deploy the smart contract with a deadline and interact with it. Basically, at the end of this part, you will know how to deploy the auction smart contract, how to make bids and how to collect funds, as the owner.
Your local node needs to be running, so please refer to the other parts before following this tutorial.
Deploying auctionWithDeadline
Run script
First, let’s use the run script
command in order to make sure everything is okay. To do so, we need to use the following command with our storage and input:
chainacc@tezos:~/tezos$ ./tezos-client run script simpleAuctionTimestamp.tz on storage '(Pair (Pair None 10) (Pair "tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq" "2019–08–01T16:30:00Z"))' and input '"tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq"'
Here, in our storage, we have a few different things:
None
: if you remember from the last article, this is supposed to be an optionalkey_hash
representing the last bidder. As we are deploying the contract, there is no bidder yet. Therefore, we useNone
.10
: this is our starting price,10 mutez
."tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq"
: this is the address of the item’s owner. In this case, this is my address.“2019–08–01T16:30:00Z”
: this is the timestamp for the deadline. It is in UTC, so please take this into account.
We also have an input, which would normally be the key_hash
of the person calling the contract (so the person can get refunded if she gets outbid — please read Part. 3 if you do not remember this), but to use run script
we can just use the same address as in storage, mine in this case.
When running this command, this is what we get:
Warning:This is NOT the Tezos Mainnet.The node you are connecting to claims to be running on the
Tezos Alphanet DEVELOPMENT NETWORK.
Do NOT use your fundraiser keys on this network.
Alphanet is a testing network, with free tokens.storage
(Pair (Pair (Some "tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq") 50000)
(Pair "tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq" "2019-08-01T16:30:00Z"))
emitted operations
Everything looks fine. If you notice it displays 50000
, it is a simple displaying bug. Actual value is the one you put, no worries.
We can now deploy the contract on the Alphanet.
Originating the contract
This is how you originate a contract:
originate contract <name> for <manager> transferring <quantity> from <source> running <program>
According to this command, let’s adapt it to originate our auction smart contract (be careful and remember to always use --dry-run
to simulate the command before actually executing it):
chainacc@tezos:~/tezos$ ./tezos-client originate contract auctionWithDeadline for Mathis transferring 0 from Mathis running simpleAuctionTimestamp.tz --init '(Pair (Pair None 10) (Pair "tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq" "2019-08-01T16:30:00Z"))' --burn-cap 0.872
We use the same storage
. There is no input
because we do not need one when deploying a contract. One last thing, Mathis
is the alias for my tz1
address. Also, don’t forget the --burn-cap
flag.
This is what we get:
Node is bootstrapped, ready for injecting operations.
Estimated gas: 26225 units (will add 100 for safety)
Estimated storage: 872 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'ooHN8tN54msnAwVMRmfdhP5AzyqGj7n2AmrvFLYVCYM7g1d7RWZ'
Waiting for the operation to be included...
Operation found in block: BLZDuRDZ1Mv2NXnznaZqER2MQjYok1TUDn2uhnN2ecXn8mZkq1T (pass: 3, offset: 2)
This sequence of operations was run:
Manager signed operations:
From: tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq
Fee to the baker: ꜩ0.003503
Expected counter: 150117
Gas limit: 26325
Storage limit: 892 bytes
Balance updates:
tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq ............. -ꜩ0.003503
fees(tz3gN8NTLNLJg5KRsUU47NHNVHbdhcFXjjaB,264) ... +ꜩ0.003503
Origination:
From: tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq
For: tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq
Credit: ꜩ0
Script:
{ parameter key_hash ;
storage (pair (pair (option key_hash) mutez) (pair address timestamp)) ;
code { UNPAIR ;
SWAP ;
DUP ;
CDAR ;
SENDER ;
IFCMPEQ
{ DUP ;
CDDR ;
NOW ;
ASSERT_CMPGT ;
DIP { DROP } ;
DUP ;
UNPPAIPAIR ;
IF_SOME
{ DROP ;
DIP { CONTRACT unit ; ASSERT_SOME } ;
UNIT ;
TRANSFER_TOKENS ;
NIL operation ;
DIIP { DROP } ;
SWAP ;
CONS }
{ DROP ; DROP ; DROP ; NIL operation } }
{ DUP ;
CDDR ;
NOW ;
ASSERT_CMPLT ;
DUP ;
CADR ;
AMOUNT ;
ASSERT_CMPGT ;
UNPPAIIR ;
IF_SOME
{ IMPLICIT_ACCOUNT ;
SWAP ;
UNIT ;
TRANSFER_TOKENS ;
NIL operation ;
SWAP ;
CONS }
{ DROP ; NIL operation } ;
DIP { SWAP ; SOME ; DIP { AMOUNT } ; PPAIIR } } ;
PAIR } }
Initial storage:
(Pair (Pair None 10)
(Pair "tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq" "2019-08-01T16:30:00Z"))
No delegate for this contract
This origination was successfully applied
Originated contracts:
KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6
Storage size: 615 bytes
Paid storage size diff: 615 bytes
Consumed gas: 26225
Balance updates:
tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq ... -ꜩ0.615
tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq ... -ꜩ0.257New contract KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6 originated.
The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for ooHN8tN54msnAwVMRmfdhP5AzyqGj7n2AmrvFLYVCYM7g1d7RWZ to be included --confirmations 30 --branch BM3ZXgFiNx7w7up1sRRYZa6GtefjVKMWmPDSD5zCH4d9hZS3GjQ
and/or an external block explorer.
Contract memorized as auctionWithDeadline.
See in bold? This is our KT1
address, aka our contract address. Let’s check it on the explorer: https://alphanet.tzscan.io/KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6
Pretty cool right? Our auction is LIVE.
We can now start interacting with it :)
Interacting with auctionWithDeadline
First bid
Let’s make our first bid with another account, Alice. Alice will bid 5 Tez.
Reminder: always use --dry-run
flag before executing a command.
Here is how to call our contract:
chainacc@tezos:~/tezos$ ./tezos-client transfer 5 from Alice to auctionWithDeadline --arg '"tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx"'
auctionWithDeadline
is the name of our contract, known by the client. Otherwise, you can just use the KT1
address of the contract here.
After the --arg
flag, we pass a parameter, our key_hash
(in this case, this is Alice’s one. When someone makes a bid, he has to provide his key_hash
in order to get refunded if someone makes a higher bid).
Let’s check the result:
Node is bootstrapped, ready for injecting operations.
Estimated gas: 24970 units (will add 100 for safety)
Estimated storage: no bytes added
Operation successfully injected in the node.
Operation hash is 'ooVHdpBSsq3hf2wm5qwZkfPEWg2mcEJ2k4kAZkrAFN1T8wHpPfp'
Waiting for the operation to be included...
Operation found in block: BLx4vGSP7h31GtuEjD94dmyboWhy83ipTpfM58jJMvK5i9XanJJ (pass: 3, offset: 4)
This sequence of operations was run:
Manager signed operations:
From: tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx
Fee to the baker: ꜩ0.002807
Expected counter: 303263
Gas limit: 25070
Storage limit: 0 bytes
Balance updates:
tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx ............. -ꜩ0.002807
fees(tz3WXYtyDUNL91qfiCJtVUX746QpNv5i5ve5,264) ... +ꜩ0.002807
Transaction:
Amount: ꜩ5
From: tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx
To: KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6
Parameter: "tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx"
This transaction was successfully applied
Updated storage:
(Pair (Pair (Some 0x000c21212a0f94eabafa271c32801791b48182d5f1) 5000000)
(Pair 0x0000a68bb0922947a9894a4118ea6b6e8f3d72870fd1 1564677000))
Storage size: 611 bytes
Consumed gas: 24970
Balance updates:
tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx ... -ꜩ5
KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6 ... +ꜩ5The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for ooVHdpBSsq3hf2wm5qwZkfPEWg2mcEJ2k4kAZkrAFN1T8wHpPfp to be included --confirmations 30 --branch BMNghTZFWyzmck4AtF1RqoGkoXV1iJjGdpRhbUEVjQubf4xefe5
and/or an external block explorer.
Everything seems fine. Now let’s check on the explorer to see our contract.
Great, we see a transaction (from Alice to the contract, with a bid of 5 tez), and we see the balance of 5 tez, meaning that this is our current bid.
Let’s also take a look at the storage of the contract.
Awesome, our storage has been updated. We have a key_hash
representing Alice, and her bid of 5 tez (but in mutez). We also have our address (contract’s owner address) with the timestamp, which do not get updated.
Let’s outbid Alice! ;)
Second bid
We will now bid with Bob account and see what happens. We need to call the contract again, but this time with Bob.
chainacc@tezos:~/tezos$ ./tezos-client transfer 8 from Bob to auctionWithDeadline --arg '"tz1iEyLKB6yHtVwq1yJhoAnwgdPXzhXU9RJZ"'
And here is the result we get:
Node is bootstrapped, ready for injecting operations.
Estimated gas: 35248 units (will add 100 for safety)
Estimated storage: no bytes added
Operation successfully injected in the node.
Operation hash is 'op8LzGd2qcaxpt2VC9VXTy7JYFt6T7nCpny5TYutgekwZtqn7xZ'
Waiting for the operation to be included...
Operation found in block: BM2LwqmnuGEpybM5W3id3JpjywuFFBCWYVPLtgULCRYmBEmUWBd (pass: 3, offset: 0)
This sequence of operations was run:
Manager signed operations:
From: tz1iEyLKB6yHtVwq1yJhoAnwgdPXzhXU9RJZ
Fee to the baker: ꜩ0.00126
Expected counter: 303296
Gas limit: 10000
Storage limit: 0 bytes
Balance updates:
tz1iEyLKB6yHtVwq1yJhoAnwgdPXzhXU9RJZ ............. -ꜩ0.00126
fees(tz3WXYtyDUNL91qfiCJtVUX746QpNv5i5ve5,264) ... +ꜩ0.00126
Revelation of manager public key:
Contract: tz1iEyLKB6yHtVwq1yJhoAnwgdPXzhXU9RJZ
Key: edpkvNTZavCiErq3aE93mVBQHsvH9G1FJcKADFLDPwYZLwzzGhQHGk
This revelation was successfully applied
Consumed gas: 10000
Manager signed operations:
From: tz1iEyLKB6yHtVwq1yJhoAnwgdPXzhXU9RJZ
Fee to the baker: ꜩ0.003739
Expected counter: 303297
Gas limit: 35348
Storage limit: 0 bytes
Balance updates:
tz1iEyLKB6yHtVwq1yJhoAnwgdPXzhXU9RJZ ............. -ꜩ0.003739
fees(tz3WXYtyDUNL91qfiCJtVUX746QpNv5i5ve5,264) ... +ꜩ0.003739
Transaction:
Amount: ꜩ8
From: tz1iEyLKB6yHtVwq1yJhoAnwgdPXzhXU9RJZ
To: KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6
Parameter: "tz1iEyLKB6yHtVwq1yJhoAnwgdPXzhXU9RJZ"
This transaction was successfully applied
Updated storage:
(Pair (Pair (Some 0x00f7ee85aec4b0067c8f9f26543f9e2cb46d44a340) 8000000)
(Pair 0x0000a68bb0922947a9894a4118ea6b6e8f3d72870fd1 1564677000))
Storage size: 611 bytes
Consumed gas: 25041
Balance updates:
tz1iEyLKB6yHtVwq1yJhoAnwgdPXzhXU9RJZ ... -ꜩ8
KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6 ... +ꜩ8
Internal operations:
Transaction:
Amount: ꜩ5
From: KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6
To: tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx
Parameter: Unit
This transaction was successfully applied
Consumed gas: 10207
Balance updates:
KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6 ... -ꜩ5
tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx ... +ꜩ5The operation has only been included 0 blocks ago.
We recommend to wait more.
Use command
tezos-client wait for op8LzGd2qcaxpt2VC9VXTy7JYFt6T7nCpny5TYutgekwZtqn7xZ to be included --confirmations 30 --branch BMLgt2eoSf47X2k7nP9GPXU5bBXKPo8hpUu6jJ7ZhoHAvbaCfLD
and/or an external block explorer.
Everything seems fine. Let’s now check our contract in the explorer.
We now have 3 transactions. Why? Well, Bob made a bid, so it’s a transaction. As his bid was higher than Alice’s one, we refunded Alice. Current bid is now 8 tez, and Alice got her 5 tez back.
We should also check the storage.
Perfect, storage has been updated with new key_hash
and current bid.
This little bid war between Alice and Bob could continue until we reach the deadline. You get how this work, so I won’t be making valid bids anymore.
I would rather focus on the error handling for now, and see if everything works. We need to check two different errors for now:
- new bid is less than last bid
- owner wants to collect funds before the end of the deadline
Checking smaller bid
Current bid is 8 tez. Let’s bid 6 tez with Alice and see what happens.
Again, here is the command:
chainacc@tezos:~/tezos$ ./tezos-client transfer 6 from Alice to auctionWithDeadline --arg '"tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx"'
Obviously, this won’t work. We get an error, because 6 is less than 8, so this is not a valid bid.
Node is bootstrapped, ready for injecting operations.
This simulation failed:
Manager signed operations:
From: tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx
Fee to the baker: ꜩ0
Expected counter: 303264
Gas limit: 800000
Storage limit: 60000 bytes
Transaction:
Amount: ꜩ6
From: tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx
To: KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6
Parameter: "tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx"
This operation FAILED.Runtime error in contract KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6:
01: { parameter key_hash ;
02: storage (pair (pair (option key_hash) mutez) (pair address timestamp)) ;
03: code { UNPAIR ;
04: SWAP ;
05: DUP ;
06: CDAR ;
07: SENDER ;
08: IFCMPEQ
09: { DUP ;
10: CDDR ;
11: NOW ;
12: ASSERT_CMPGT ;
13: DIP { DROP } ;
14: DUP ;
15: UNPPAIPAIR ;
16: IF_SOME
17: { DROP ;
18: DIP { CONTRACT unit ; ASSERT_SOME } ;
19: UNIT ;
20: TRANSFER_TOKENS ;
21: NIL operation ;
22: DIIP { DROP } ;
23: SWAP ;
24: CONS }
25: { DROP ; DROP ; DROP ; NIL operation } }
26: { DUP ;
27: CDDR ;
28: NOW ;
29: ASSERT_CMPLT ;
30: DUP ;
31: CADR ;
32: AMOUNT ;
33: ASSERT_CMPGT ;
34: UNPPAIIR ;
35: IF_SOME
36: { IMPLICIT_ACCOUNT ;
37: SWAP ;
38: UNIT ;
39: TRANSFER_TOKENS ;
40: NIL operation ;
41: SWAP ;
42: CONS }
43: { DROP ; NIL operation } ;
44: DIP { SWAP ; SOME ; DIP { AMOUNT } ; PPAIIR } } ;
45: PAIR } }
At line 33 characters 13 to 25,
script reached FAILWITH instruction
with Unit
Fatal error:
transfer simulation failed
As you can see, it fails at line 33 which is the ASSERT_CMPGT
instruction, which checks if the bid is higher than the last one. In this case, it fails because 6 is, again, less than 8.
Our first error was well handled. Let’s now check the timestamp.
Checking timestamp
We need to make sure our timestamp is working. Remember, the contract’s owner can only collect his funds AFTER the deadline has passed. Right now, we are still within the deadline, so we should not be able to collect our funds.
I will call the contract with my account and my tz1
address, like this:
chainacc@tezos:~/tezos$ ./tezos-client transfer 0 from Mathis to auctionWithDeadline --arg '"tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq"'
Since I am the owner, I can transfer 0 to the contract, as I actually don’t want to make a bid. Anyway, here is what we get:
Node is bootstrapped, ready for injecting operations.
This simulation failed:
Manager signed operations:
From: tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq
Fee to the baker: ꜩ0
Expected counter: 150118
Gas limit: 800000
Storage limit: 60000 bytes
Transaction:
Amount: ꜩ0
From: tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq
To: KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6
Parameter: "tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq"
This operation FAILED.Runtime error in contract KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6:
01: { parameter key_hash ;
02: storage (pair (pair (option key_hash) mutez) (pair address timestamp)) ;
03: code { UNPAIR ;
04: SWAP ;
05: DUP ;
06: CDAR ;
07: SENDER ;
08: IFCMPEQ
09: { DUP ;
10: CDDR ;
11: NOW ;
12: ASSERT_CMPGT ;
13: DIP { DROP } ;
14: DUP ;
15: UNPPAIPAIR ;
16: IF_SOME
17: { DROP ;
18: DIP { CONTRACT unit ; ASSERT_SOME } ;
19: UNIT ;
20: TRANSFER_TOKENS ;
21: NIL operation ;
22: DIIP { DROP } ;
23: SWAP ;
24: CONS }
25: { DROP ; DROP ; DROP ; NIL operation } }
26: { DUP ;
27: CDDR ;
28: NOW ;
29: ASSERT_CMPLT ;
30: DUP ;
31: CADR ;
32: AMOUNT ;
33: ASSERT_CMPGT ;
34: UNPPAIIR ;
35: IF_SOME
36: { IMPLICIT_ACCOUNT ;
37: SWAP ;
38: UNIT ;
39: TRANSFER_TOKENS ;
40: NIL operation ;
41: SWAP ;
42: CONS }
43: { DROP ; NIL operation } ;
44: DIP { SWAP ; SOME ; DIP { AMOUNT } ; PPAIIR } } ;
45: PAIR } }
At line 12 characters 13 to 25,
script reached FAILWITH instruction
with Unit
Fatal error:
transfer simulation failed
This time it fails at line 12, which is where we check if the deadline has passed or not. As of right now, deadline hasn’t pass yet, so the owner can not collect his funds as the auction is not over.
So far so good. Now, I will just wait for the deadline to be over, and we will make a valid bid with Alice, which shouldn’t go through since the auction is over. Then, we will collect funds with owner ;)
Bidding after the deadline
Final bid was 8 from Bob. Let’s bid 10 with Alice, knowing that the deadline is over. Same command:
chainacc@tezos:~/tezos$ ./tezos-client transfer 10 from Alice to auctionWithDeadline --arg '"tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx"'
Here is the result:
Node is bootstrapped, ready for injecting operations.
This simulation failed:
Manager signed operations:
From: tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx
Fee to the baker: ꜩ0
Expected counter: 303264
Gas limit: 800000
Storage limit: 60000 bytes
Transaction:
Amount: ꜩ10
From: tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx
To: KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6
Parameter: "tz1LkAVJVuC44PkSjHQpfmgNj2duQQ2kgctx"
This operation FAILED.Runtime error in contract KT1RbqyHCJrm3nNToybJLFp6NMSxrocaXyg6:
01: { parameter key_hash ;
02: storage (pair (pair (option key_hash) mutez) (pair address timestamp)) ;
03: code { UNPAIR ;
04: SWAP ;
05: DUP ;
06: CDAR ;
07: SENDER ;
08: IFCMPEQ
09: { DUP ;
10: CDDR ;
11: NOW ;
12: ASSERT_CMPGT ;
13: DIP { DROP } ;
14: DUP ;
15: UNPPAIPAIR ;
16: IF_SOME
17: { DROP ;
18: DIP { CONTRACT unit ; ASSERT_SOME } ;
19: UNIT ;
20: TRANSFER_TOKENS ;
21: NIL operation ;
22: DIIP { DROP } ;
23: SWAP ;
24: CONS }
25: { DROP ; DROP ; DROP ; NIL operation } }
26: { DUP ;
27: CDDR ;
28: NOW ;
29: ASSERT_CMPLT ;
30: DUP ;
31: CADR ;
32: AMOUNT ;
33: ASSERT_CMPGT ;
34: UNPPAIIR ;
35: IF_SOME
36: { IMPLICIT_ACCOUNT ;
37: SWAP ;
38: UNIT ;
39: TRANSFER_TOKENS ;
40: NIL operation ;
41: SWAP ;
42: CONS }
43: { DROP ; NIL operation } ;
44: DIP { SWAP ; SOME ; DIP { AMOUNT } ; PPAIIR } } ;
45: PAIR } }
At line 29 characters 13 to 25,
script reached FAILWITH instruction
with Unit
Fatal error:
transfer simulation failed
As you can see, it does not work. It fails on line 29, because the deadline has passed.
Collecting the funds
To end this article, let’s collect the funds:
chainacc@tezos:~/tezos$ ./tezos-client transfer 0 from Mathis to auctionWithDeadline --arg '"tz1apeCmwZ7Rzd2HugzhapLMA8LaYUZNUBWq"'
And now, let’s check our contract.
Balance is now empty, and the highest bid (8 tez) has been sent to my tz1
account.
We collected the funds, and now the auction is over. Awesome! ;)
Stay tuned for the next article.