-
Notifications
You must be signed in to change notification settings - Fork 2
/
RPS.sol
116 lines (102 loc) · 4.43 KB
/
RPS.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
/**
* @title Rock Paper Scissors Lizard Spock
* @author Clément Lesaege - <clement@lesaege.com>
*/
/* This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://www.wtfpl.net/ for more details. */
pragma solidity ^0.4.26;
contract RPS{
address public j1; // The first player creating the contract.
address public j2; // The second player.
enum Move {Null, Rock, Paper, Scissors, Spock, Lizard} // Possible moves. Note that if the parity of the moves is the same the lower one wins, otherwise the higher one.
bytes32 public c1Hash; // Commitment of j1.
Move public c2; // Move of j2. Move.Null before he played.
uint256 public stake; // Amout bet by each party.
uint256 public TIMEOUT = 5 minutes; // If some party takes more than TIMEOUT to respond, the other can call TIMEOUT to win.
uint256 public lastAction; // The time of the last action. Usefull to determine if someone has timed out.
/** @dev Constructor. Must send the amount at stake when creating the contract. Note that the move and salt must be saved.
* @param _c1Hash Must be equal to keccak256(c1,salt) where c1 is the move of the j1.
*/
function RPS(bytes32 _c1Hash, address _j2) payable {
stake = msg.value; // La mise correspond à la quantité d'ethers envoyés.
j1=msg.sender;
j2=_j2;
c1Hash=_c1Hash;
lastAction=now;
}
/** @dev To be called by j2 and provided stake.
* @param _c2 The move submitted by j2.
*/
function play(Move _c2) payable {
require(c2==Move.Null); // J2 has not played yet.
require(_c2!=Move.Null); // A move is selected.
require(msg.value==stake); // J2 has paid the stake.
require(msg.sender==j2); // Only j2 can call this function.
c2=_c2;
lastAction=now;
}
/** @dev To be called by j1. Reveal the move and send the ETH to the winning party or split them.
* @param _c1 The move played by j1.
* @param _salt The salt used when submitting the commitment when the constructor was called.
*/
function solve(Move _c1, uint256 _salt) {
require(_c1!=Move.Null); // J1 should have made a valid move.
require(c2!=Move.Null); // J2 must have played.
require(msg.sender==j1); // J1 can call this.
require(keccak256(_c1,_salt)==c1Hash); // Verify the value is the commited one.
// If j1 or j2 throws at fallback it won't get funds and that is his fault.
// Despite what the warnings say, we should not use transfer as a throwing fallback would be able to block the contract, in case of tie.
if (win(_c1,c2))
j1.send(2*stake);
else if (win(c2,_c1))
j2.send(2*stake);
else {
j1.send(stake);
j2.send(stake);
}
stake=0;
}
/** @dev Let j2 get the funds back if j1 did not play.
*/
function j1Timeout() {
require(c2!=Move.Null); // J2 already played.
require(now > lastAction + TIMEOUT); // Timeout time has passed.
j2.send(2*stake);
stake=0;
}
/** @dev Let j1 take back the funds if j2 never play.
*/
function j2Timeout() {
require(c2==Move.Null); // J2 has not played.
require(now > lastAction + TIMEOUT); // Timeout time has passed.
j1.send(stake);
stake=0;
}
/** @dev Is this move winning over the other.
* @param _c1 The first move.
* @param _c2 The move the first move is considered again.
* @return w True if c1 beats c2. False if c1 is beaten by c2 or in case of tie.
*/
function win(Move _c1, Move _c2) constant returns (bool w) {
if (_c1 == _c2)
return false; // They played the same so no winner.
else if (_c1==Move.Null)
return false; // They did not play.
else if (uint(_c1)%2==uint(_c2)%2)
return (_c1<_c2);
else
return (_c1>_c2);
}
}
contract Hasher{
/** @dev Give the commitement. Must only be called locally.
* @param _c The move.
* @param _salt The salt to increase entropy.
*/
function hash(uint8 _c, uint256 _salt) constant returns(bytes32) {
return keccak256(_c,_salt);
}
}