Competition

Introduction#

This contract collects competitors' scores, and distribute prize to top scores. Submitted scores must be signed by an external oracle to be registered.

You may see this contract in action in the 2048 competition DApp example.

API#

Storage#

NameTypeDescription
organizeraddressAddress of the organizer.
prizetezPrize value in tez.
oraclekeyKey of the score oracle.
submissioncollectionA submission is defined by:
  • a competitor address
  • a score
  • a timestamp
_statestatesContract state, one of Created, InProgress, Closed.

Entrypoints#

NameParametersDescription
confirmedCalled by organizer to open the competition. Prize must be transferred.
submitpacked_score, signed_scoreAdds a submission; packed_score is packed version of the pair competitor address and score; signed_score is this packed data signed by oracle.

It fails if the data is not signed by oracle; it updates the score of the competitor if score already exists.
closeSets contract state to Closed and distribute prize to top scores:
  • 50%, 30%, 20% if more than 3 submissions
  • 60%, 40% if 2 submissions
  • 100% if only one submission

Code#

competition.arl
archetype competition(
organizer : address,
prize : tez,
oracle : key,
)
asset submission {
competitor : address;
score : nat;
timestamp : date;
}
(* state machine *)
states =
| Created initial
| InProgress
| Closed
transition confirm () {
called by organizer
from Created to InProgress
when { transferred = prize }
}
entry submit (packed_score : bytes, signed_score : signature) {
require {
c1 : state = InProgress;
}
effect {
if check_signature(oracle, signed_score, packed_score) then (
match unpack<address * nat>(packed_score) with
| some(s) ->
submission.addupdate(s[0], {
score = s[1];
timestamp = now
})
| none -> fail("CANNOT_UNPACK_SCORE")
end
) else fail("NOT_SIGNED_BY_ORACLE");
}
}
transition close () {
called by organizer
from InProgress to Closed
with effect {
var submissions = submission.sort(desc(score), timestamp);
if submissions.count() >= 3 then begin
var first = submissions.nth(0);
var second = submissions.nth(1);
var third = submissions.nth(2);
var q1 = 50% * prize;
var q2 = 30% * prize;
var q3 = 20% * prize;
transfer q1 to first;
transfer q2 to second;
transfer q3 to third;
transfer (prize - q1 - q2 - q3) to organizer
end else if submissions.count() >= 2 then begin
var first = submissions.nth(0);
var second = submissions.nth(1);
var q1 = 60% * prize;
var q2 = 40% * prize;
transfer q1 to first;
transfer q2 to second;
transfer (prize - q1 - q2) to organizer
end else if submissions.count() >= 1 then begin
var first = submissions.nth(0);
transfer prize to first
end else transfer prize to organizer
}
}