Raw File
timelock_flip.tz
# This contract emulates a time constrained "guess who" game using timelocks.
# The goal of the game if for the challenger to guess which value was stored by
# the game initiator. The challenger only has one guess, and must submit it
# within 10 blocks of the game initialization.
#
# More particularly, the game relies on a timelock primitive using a difficulty
# set to 1_024 and a hardwritten threshold for guessing of 10 blocks. Beware,
# this contract is for education purpose only to demonstrate the use of
# timelock. In particular, the contract may not be secure, the game can be
# reinitialised at any time and the timelock difficulty and threshold values
# were chosen arbitrarily.
#
# Its storage consists of 4 values: the level and timelock chest, in which the
# value to guess is stored, set up at the game's initialization, the guess
# written in bytes, and the message to know the game status and result.
#
# The game unfolds as such:
# 1) Initilialising the game with a timelock chest:
# User A publishes a timelock chest to start a game, the contract
# initializes the storage's level to the current level and the guess and
# message to a hardcoded value (0xA0).
# 2) Submitting the guess:
# User B publishes a guess, the guess is saved if and only if the current
# level is lower than the contract's plus 10 blocks (else the game is blocked
# but the contract can be reinitialised with a new timelock chest at anytime),
# we also update the message to another hardcoded value (0xB0).
# Note the guess can be updated several times and that no verification is made
# on who is sending it.
# 3) Revealing the time-locked value:
# Finally, user A (or B) submits a chest_key. If the timelock opening is
# successful, the contract compares the guess to the timelock message. If the
# bytes are equal, the message is updated to 0x00 else 0x01. If the opening
# fails, the message is updated to 0x10.

storage (pair (nat %level) chest (bytes %guess) (bytes %result));
parameter ( or (chest %initialize_game) (or (bytes %guess) (chest_key %finish_game)));
code { UNPAIR 5;
       IF_LEFT { # If we receive a chest,
                 # we reinitialise the storage
                 # with the new chest and current level.
                 DIP {DROP 4};
                 PUSH bytes 0xA0;
                 DUP;
                 PAIR;
                 SWAP;
                 LEVEL;
                 PAIR 3}
               { IF_LEFT { # If we receive a guess,
                           SWAP;
                           DUP;
                           PUSH nat 10;
                           ADD;
                           LEVEL;
                           COMPARE;
                           LE;
                           IF { # we store the guess if current level < stored level + 10
                                DIP 2 {PUSH bytes 0xB0};
                                DIP {PAIR; SWAP; PAIR};
                                PAIR;
                                DIP {DROP 2};
                              }
                              { # else we keep the storage unchanged.
                                SWAP;
                                DROP;
                                PAIR 4};
                          }
                         { # If we receive a chest_key,
                           # we open the chest.
                           DIP 4 {DROP};
                           DUP 3;
                           SWAP;
                           DIP 2 {PUSH nat 1024};
                           OPEN_CHEST;
                           IF_SOME { # If the chest opens successfully,
                                     # we compare the guess with the locked value.
                                     DUP 4;
                                     COMPARE;
                                     EQ;
                                     IF { # If they are equal we store 0x00
                                          PUSH bytes 0x00}
                                        { # else we store 0x01
                                          PUSH bytes 0x01}}
                                   { # We store 0x10 in case of failure
                                     PUSH bytes 0x10};
                           DIG 3;
                           PAIR;
                           DIG 2;
                           PAIR;
                           DIG 1;
                           PAIR;
                          };
               };
       NIL operation;
       PAIR;
     }
back to top