-
Notifications
You must be signed in to change notification settings - Fork 0
/
auction.dfy
71 lines (57 loc) · 1.97 KB
/
auction.dfy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
include "contract.dfy"
class Auction extends address {
var beneficiary: address
var auctionEnd: nat
var highestBidder: address?
var highestBid: nat
var pendingReturns: map<address, nat>
var ended: bool
predicate Valid()
reads this
{
(forall i :: i in pendingReturns ==> this.balance >= pendingReturns[i]) && this.balance >= highestBid
}
constructor(biddingTime: nat, seller: address)
ensures beneficiary == seller && auctionEnd == block.timestamp + biddingTime
{
beneficiary := seller;
msg := new Message();
block := new Block();
new;
auctionEnd := block.timestamp + biddingTime;
highestBidder := null;
highestBid := 0;
ended := false;
pendingReturns := map[];
}
method bid(bidder: address)
requires block.timestamp <= auctionEnd
requires bidder.msg.value > highestBid
requires highestBidder != bidder
requires Valid()
modifies this
ensures Valid()
{
if highestBidder in pendingReturns{
pendingReturns := pendingReturns[highestBidder:= (if highestBidder in pendingReturns then pendingReturns[highestBidder] else 0) + highestBid];
}else {
pendingReturns := pendingReturns[highestBidder := highestBid];
}
assert highestBidder in pendingReturns;
highestBidder := bidder;
highestBid := bidder.msg.value;
this.balance := this.balance + highestBid;
}
method withdraw(caller: address)
requires Valid()
modifies this, caller
ensures caller in pendingReturns ==> pendingReturns == old(pendingReturns)[caller := 0]
ensures Valid()
{
var amount := if caller in pendingReturns then pendingReturns[caller] else 0;
assert amount <= this.balance;
pendingReturns := pendingReturns[caller:= 0];
this.balance := this.balance - amount;
var sent := caller.send(amount);
}
}