Skip to content

Instantly share code, notes, and snippets.

@danielkhoo
Created February 7, 2022 06:16
Show Gist options
  • Save danielkhoo/a6c82654d195d7df3208c5ec65a23a42 to your computer and use it in GitHub Desktop.
Save danielkhoo/a6c82654d195d7df3208c5ec65a23a42 to your computer and use it in GitHub Desktop.
pragma solidity >=0.8.0 <0.9.0;
/**
* @notice Function for players to reveal their choice. The first player to reveal sets a deadline for the second player
* this is prevent players for abandoning the game once they know they have lost based on the revealed hash.
* At the end of the deadline, the player who committed can trigger a "win-by-default".
* If both players reveal in time, the second player's reveal will call determineWinner() and advance the game to the result phase
* @notice Unlike commit, players can only reveal once
* @param salt - a player chosen secret string from the "commit" phase used to prove their choice via a hash match
*/
function reveal(string memory salt)
public
validGameState(activeGame[msg.sender], GameState.RevealPhase)
{
// Get the game hash from active game mapping
address gameHash = activeGame[msg.sender];
bool isPlayer1 = games[gameHash].player1 == msg.sender;
// Check that player hasn't already revealed
if (isPlayer1) {
require(games[gameHash].reveal1 == 0, "Already revealed");
} else {
require(games[gameHash].reveal2 == 0, "Already revealed");
}
// Verify that one of the choices + salt hashes matches commit hash
// Compare all three possible choices so they don't have to enter their choice again
bytes32 verificationHashRock = keccak256(abi.encodePacked("rock", salt));
bytes32 verificationHashPaper = keccak256(abi.encodePacked("paper", salt));
bytes32 verificationHashScissors = keccak256(
abi.encodePacked("scissors", salt)
);
bytes32 commitHash = isPlayer1
? games[gameHash].commit1
: games[gameHash].commit2;
require(
verificationHashRock == commitHash ||
verificationHashPaper == commitHash ||
verificationHashScissors == commitHash,
"Reveal hash doesn't match commit hash. Salt not the same as commit."
);
// Work backwards to infer their choice
string memory choice;
if (verificationHashRock == commitHash) {
choice = "rock";
} else if (verificationHashPaper == commitHash) {
choice = "paper";
} else {
choice = "scissors";
}
// Save the revealed hash w/o salt
if (isPlayer1) {
games[gameHash].reveal1 = keccak256(abi.encodePacked(choice));
} else {
games[gameHash].reveal2 = keccak256(abi.encodePacked(choice));
}
// if both players revealed, determine winner
if (games[gameHash].reveal1 != 0 && games[gameHash].reveal2 != 0) {
games[gameHash].gameResult = determineWinner(
games[gameHash].reveal1,
games[gameHash].reveal2
);
games[gameHash].gameState = GameState.ResultPhase;
} else {
// Set deadline for other player to reveal
games[gameHash].revealDeadline = block.timestamp + 3 minutes;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment