-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7547018
commit 7e16b49
Showing
8 changed files
with
139 additions
and
254 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/hardhat/artifacts/contracts/FootballGame.sol/FootballGame.dbg.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../build-info/c88bf9a7a4247ccbdfdb64e7d147a284.json" | ||
"buildInfo": "../../build-info/90aa1822c4e1fe324a84be9d2a6c51ca.json" | ||
} |
4 changes: 2 additions & 2 deletions
4
packages/hardhat/artifacts/contracts/FootballGame.sol/FootballGame.json
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
38 changes: 38 additions & 0 deletions
38
packages/hardhat/deployments/ten/solcInputs/9dde880d1facc405dc2f759889c6707a.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"language": "Solidity", | ||
"sources": { | ||
"@openzeppelin/contracts/token/ERC20/IERC20.sol": { | ||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n" | ||
}, | ||
"contracts/FootballGame.sol": { | ||
"content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract FootballGame {\n\taddress public owner;\n\tIERC20 public footballCoin;\n\tuint public timelockBlocks;\n\n\tenum Status {\n\t\tProposed,\n\t\tAccepted,\n\t\tFinished,\n\t\tFinishedByTimelock\n\t}\n\n\tstruct Game {\n\t\tuint256 gameId;\n\t\taddress challenger;\n\t\taddress opponent;\n\t\tuint256 wagerAmount;\n\t\tuint256[] challengerFormation;\n\t\tuint256[] opponentFormation;\n\t\tGameResult result;\n\t\tuint blockNumber;\n\t\tStatus status;\n\t}\n\n\tstruct GameResult {\n\t\tuint goalsHomeTeam;\n\t\tuint goalsAwayTeam;\n\t}\n\n\t///////////////\n\t// MAPPINGS //\n\t///////////////\n\n\tmapping(uint256 => uint256[]) private challenger_formation;\n\tmapping(uint256 => Game) public games;\n\tuint256 public gameCount;\n\n\tfunction getGameCount() public view returns (uint256) {\n\t\treturn gameCount;\n\t}\n\n\t///////////////\n\t// EVENTS //\n\t///////////////\n\n\tevent GameProposed(\n\t\tuint256 gameId,\n\t\taddress indexed sender,\n\t\taddress indexed recipient,\n\t\tuint256 wagerAmount,\n\t\tuint blockNumber\n\t);\n\n\tevent GameAccepted(\n\t\tuint256 gameId,\n\t\taddress indexed sender,\n\t\taddress indexed recipient,\n\t\tuint256 wagerAmount,\n\t\tuint blockNumber\n\t);\n\n\tevent GameFinished(\n\t\tuint256 gameId,\n\t\taddress indexed sender,\n\t\taddress indexed recipient\n\t);\n\n\tevent GameFinishedByTimelock(\n\t\tuint256 gameId,\n\t\taddress indexed sender,\n\t\taddress indexed recipient\n\t);\n\n\t///////////////\n\t// PLAYERS //\n\t///////////////\n\n\tstruct Player {\n\t\tuint256 player_id;\n\t\tuint256 team_id;\n\t\tuint256 position; // 0 = Empty, 1 = Goalkeeper, 2 = Defense, 3 = Midfield, 4 = Attack\n\t\tuint128 attack;\n\t\tuint128 defense;\n\t\tuint128 speed;\n\t\tuint128 power;\n\t\tuint128 stamina;\n\t\tuint128 technique;\n\t\tuint128 goalkeeping;\n\t}\n\n\tmapping(uint256 => Player) public players;\n\n\tfunction addPlayer(\n\t\tuint256 playerId,\n\t\tuint256 teamId,\n\t\tuint256 position,\n\t\tuint128 attack,\n\t\tuint128 defense,\n\t\tuint128 speed,\n\t\tuint128 power,\n\t\tuint128 stamina,\n\t\tuint128 technique,\n\t\tuint128 goalkeeping\n\t) public onlyOwner {\n\t\tPlayer memory newPlayer = Player({\n\t\t\tplayer_id: playerId,\n\t\t\tteam_id: teamId,\n\t\t\tposition: position,\n\t\t\tattack: attack,\n\t\t\tdefense: defense,\n\t\t\tspeed: speed,\n\t\t\tpower: power,\n\t\t\tstamina: stamina,\n\t\t\ttechnique: technique,\n\t\t\tgoalkeeping: goalkeeping\n\t\t});\n\n\t\tplayers[playerId] = newPlayer;\n\t}\n\n\t///////////////\n\t// CONSTRUCTOR //\n\t///////////////\n\n\tconstructor(IERC20 _footballCoin, uint _timelockBlocks) {\n\t\towner = msg.sender;\n\t\tfootballCoin = _footballCoin;\n\t\ttimelockBlocks = _timelockBlocks;\n\t}\n\tmodifier onlyOwner() {\n\t\trequire(msg.sender == owner, \"Caller is not the owner\");\n\t\t_;\n\t}\n\n\t///////////////\n\t// GAME FUNCTIONS //\n\t///////////////\n\n\tfunction proposeGame(\n\t\taddress opponent,\n\t\tuint256 wagerAmount,\n\t\tuint256[] memory formation\n\t) public {\n\t\trequire(\n\t\t\tfootballCoin.allowance(msg.sender, address(this)) >= wagerAmount,\n\t\t\t\"Insufficient allowance for wager\"\n\t\t);\n\t\tfor (uint i = 0; i < formation.length; i++) {\n\t\t\trequire(players[formation[i]].player_id != 0, \"Invalid player id\");\n\t\t}\n\n\t\t// Transfer the wager amount from the challenger to the contract\n\t\tfootballCoin.transferFrom(msg.sender, address(this), wagerAmount);\n\n\t\tuint256 newGameId = ++gameCount;\n\t\tgames[newGameId] = Game({\n\t\t\tgameId: newGameId,\n\t\t\tchallenger: msg.sender,\n\t\t\topponent: opponent,\n\t\t\twagerAmount: wagerAmount,\n\t\t\tchallengerFormation: new uint256[](0),\n\t\t\topponentFormation: new uint256[](0),\n\t\t\tresult: GameResult({ goalsHomeTeam: 0, goalsAwayTeam: 0 }),\n\t\t\tblockNumber: block.number,\n\t\t\tstatus: Status.Proposed\n\t\t});\n\n\t\tchallenger_formation[newGameId] = formation;\n\n\t\t// Emitting events to notify about the new game proposal\n\t\temit GameProposed(\n\t\t\tnewGameId,\n\t\t\tmsg.sender,\n\t\t\topponent,\n\t\t\twagerAmount,\n\t\t\tblock.number\n\t\t);\n\t}\n\n\tfunction acceptGame(uint256 gameId, uint256[] memory formation) public {\n\t\tGame storage game = games[gameId];\n\n\t\trequire(\n\t\t\tmsg.sender == game.opponent,\n\t\t\t\"Only the opponent can accept the game\"\n\t\t);\n\t\trequire(\n\t\t\tfootballCoin.allowance(msg.sender, address(this)) >=\n\t\t\t\tgame.wagerAmount,\n\t\t\t\"Insufficient allowance for wager\"\n\t\t);\n\t\trequire(game.status == Status.Proposed, \"Incorrect state\");\n\n\t\tfor (uint i = 0; i < formation.length; i++) {\n\t\t\trequire(players[formation[i]].player_id != 0, \"Invalid player id\");\n\t\t}\n\n\t\t// Transfer the wager amount from the opponent to the contract\n\t\tfootballCoin.transferFrom(msg.sender, address(this), game.wagerAmount);\n\n\t\tgame.opponentFormation = formation;\n\t\tgame.blockNumber = block.number;\n\t\tgame.status = Status.Accepted;\n\n\t\t// Notify about game acceptance\n\t\temit GameAccepted(\n\t\t\tgameId,\n\t\t\tmsg.sender,\n\t\t\tgame.challenger,\n\t\t\tgame.wagerAmount,\n\t\t\tblock.number\n\t\t);\n\t}\n\n\tfunction revealOutcome(uint256 gameId) public {\n\t\tGame storage game = games[gameId];\n\n\t\trequire(\n\t\t\tmsg.sender == game.challenger,\n\t\t\t\"Only the challenger can reveal the outcome\"\n\t\t);\n\t\trequire(game.status == Status.Accepted, \"Incorrect state\");\n\n\t\tgame.challengerFormation = challenger_formation[gameId];\n\n\t\tGameResult memory result = determineGameResult(game);\n\t\tgame.result = result;\n\n\t\tgame.status = Status.Finished;\n\n\t\taddress winner = determineWinner(game, result);\n\t\tpayoutWinners(game, winner);\n\n\t\temit GameFinished(gameId, msg.sender, game.opponent);\n\t}\n\n\tfunction opponentClaimTimelock(uint256 gameId) public {\n\t\tGame storage game = games[gameId];\n\n\t\trequire(\n\t\t\tmsg.sender == game.opponent,\n\t\t\t\"Only the opponent can claim the timelock\"\n\t\t);\n\t\trequire(\n\t\t\tblock.number > game.blockNumber + timelockBlocks,\n\t\t\t\"Opponent can claim timelock only after timelockBlocks have passed\"\n\t\t);\n\n\t\tgame.status = Status.FinishedByTimelock;\n\n\t\tpayoutWinners(game, game.opponent);\n\n\t\temit GameFinishedByTimelock(gameId, msg.sender, game.challenger);\n\t}\n\n\t///////////////\n\t// HELPER FUNCTIONS //\n\t///////////////\n\n\tfunction determineGameResult(\n\t\tGame storage game\n\t) private view returns (GameResult memory) {\n\t\tGameResult memory result = GameResult({\n\t\t\tgoalsHomeTeam: 0,\n\t\t\tgoalsAwayTeam: 0\n\t\t});\n\n\t\t// Player memory homeGoalkeeper = players[game.challengerFormation[1]];\n\t\t// Player memory awayGoalkeeper = players[game.opponentFormation[1]];\n\t\tbytes32 prevRandao = blockhash(block.number - 1);\n\t\tfor (uint i = 1; i < game.challengerFormation.length; i++) {\n\t\t\tPlayer memory homePlayer = players[game.challengerFormation[i]];\n\t\t\tPlayer memory awayPlayer = players[\n\t\t\t\tgame.opponentFormation[game.challengerFormation.length - i]\n\t\t\t];\n\t\t\tuint256 totalspeed = homePlayer.speed + awayPlayer.speed;\n\t\t\tuint256 randomSpeed = uint256(prevRandao) % totalspeed;\n\t\t\tif (homePlayer.speed < randomSpeed) {\n\t\t\t\t// Home player attacks\n\t\t\t\tif (homePlayer.attack > awayPlayer.defense) {\n\t\t\t\t\tresult.goalsHomeTeam++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Away player attacks\n\t\t\t\tif (awayPlayer.attack > homePlayer.defense) {\n\t\t\t\t\tresult.goalsAwayTeam++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tfunction determineWinner(\n\t\tGame storage game,\n\t\tGameResult memory result\n\t) private view returns (address) {\n\t\tif (result.goalsHomeTeam > result.goalsAwayTeam) {\n\t\t\treturn game.challenger;\n\t\t} else if (result.goalsHomeTeam < result.goalsAwayTeam) {\n\t\t\treturn game.opponent;\n\t\t}\n\t\treturn address(0); // It's a draw\n\t}\n\n\tfunction payoutWinners(Game storage game, address winner) private {\n\t\tif (winner == address(0)) {\n\t\t\trequire(\n\t\t\t\tfootballCoin.transfer(game.challenger, game.wagerAmount),\n\t\t\t\t\"Transfer to challenger failed\"\n\t\t\t);\n\t\t\trequire(\n\t\t\t\tfootballCoin.transfer(game.opponent, game.wagerAmount),\n\t\t\t\t\"Transfer to opponent failed\"\n\t\t\t);\n\t\t} else {\n\t\t\tuint256 totalPot = game.wagerAmount * 2;\n\t\t\trequire(\n\t\t\t\tfootballCoin.transfer(winner, totalPot),\n\t\t\t\t\"Transfer to winner failed\"\n\t\t\t);\n\t\t}\n\t}\n}\n" | ||
} | ||
}, | ||
"settings": { | ||
"optimizer": { | ||
"enabled": true, | ||
"runs": 200 | ||
}, | ||
"outputSelection": { | ||
"*": { | ||
"*": [ | ||
"abi", | ||
"evm.bytecode", | ||
"evm.deployedBytecode", | ||
"evm.methodIdentifiers", | ||
"metadata", | ||
"devdoc", | ||
"userdoc", | ||
"storageLayout", | ||
"evm.gasEstimates" | ||
], | ||
"": [ | ||
"ast" | ||
] | ||
} | ||
}, | ||
"metadata": { | ||
"useLiteralContent": true | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters