-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathcontractDuplex.sol
125 lines (100 loc) · 3.34 KB
/
contractDuplex.sol
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
pragma solidity ^0.4.3;
contract SmartDuplex {
address[2] public players;
mapping (address => uint) playermap;
// State, indexed by round
int bestRound = -1;
int net;
uint[2] balances;
uint lastPlayer; // For selfdestruct
// Can only be incremented by deposit() function
uint[2] public deposits;
// Can only be incremented by withdraw() function
uint[2] withdrawn;
event LogInit();
event LogTriggered(uint T1, uint T2);
event LogNewClaim(int r);
event LogPlayerOutcome(uint player, string outcome, uint payment);
event LogOutcome(int round, string outcome);
event LogPayment(uint player, uint payment);
uint T1;
uint T2;
modifier after_ (uint T) { if (T > 0 && block.number >= T) _; else throw; }
modifier before(uint T) { if (T == 0 || block.number < T) _; else throw; }
modifier onlyplayers { if (playermap[msg.sender] > 0) _; else throw; }
modifier beforeTrigger { if (T1 == 0) _; else throw; }
function get_balance() constant returns(uint) {
return this.balance;
}
function latestClaim() constant after_(T1) returns(int) {
return(bestRound);
}
function assert(bool b) internal {
if (!b) throw;
}
function verifySignature(address pub, bytes32 h, uint8 v, bytes32 r, bytes32 s) {
if (pub != ecrecover(h,v,r,s)) throw;
}
function SmartDuplex(address[2] _players) {
// Assume this channel is funded by the sender
for (uint i = 0; i < 2; i++) {
players[i] = _players[i];
playermap[_players[i]] = (i+1);
}
LogInit();
}
// Increment on new deposit
function deposit() onlyplayers beforeTrigger payable {
deposits[playermap[msg.sender]-1] += msg.value;
}
// Increment on withdrawal
function withdraw() {
// last player withdraws the entire remaining amount
if (lastPlayer > 0) {
assert(playermap[msg.sender] == lastPlayer);
selfdestruct(msg.sender);
}
uint i = playermap[msg.sender];
uint toWithdraw = 0;
// onlyplayers
assert(i-- > 0);
// Before finalizing, can withdraw balance
if (T2 == 0 || block.number < T2) {
toWithdraw = balances[i] - withdrawn[i];
}
// After finalizing, can withdraw deposit+net
else {
lastPlayer = 2 - i;
// positive net: Alice gets money
int net2 = (i == 0) ? net : -net;
var finalBalance = uint(int(deposits[i]) + net2);
toWithdraw = finalBalance - withdrawn[i];
}
withdrawn[i] = toWithdraw;
assert(msg.sender.send(toWithdraw));
}
// Only when it is time to finalize
function trigger() onlyplayers beforeTrigger {
T1 = block.number;
T2 = block.number + 10;
LogTriggered(T1, T2);
}
function update(uint[3] sig, int r, int _net, uint[2] _balances) onlyplayers before(T2) {
// Only update to states with larger round number
if (r <= bestRound) return;
bestRound = r;
// Check the signature of the other party
uint i = (3 - playermap[msg.sender]) - 1;
var _h = sha3(r, _net, _balances);
var V = uint8 (sig[0]);
var R = bytes32(sig[1]);
var S = bytes32(sig[2]);
verifySignature(players[i], _h, V, R, S);
// Store the new balances
for (uint j = 0; j < 2; j++) {
balances[j] = _balances[j];
}
net = _net;
LogNewClaim(r);
}
}