Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/public/imgs/BigLevel29.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions client/public/imgs/Level29.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions client/src/gamedata/authors.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,20 @@
"websites": [
"https://www.linkedin.com/in/kstasi/"
]
},
"heavydeveloper": {
"name": [
"Yonathan suarez"
],
"emails": [
"heavydeveloper@gmail.com"
],
"websites": [
"https://disrup3.com/",
"https://opensea.io/collection/mrcrypto-by-racksmafia"
]
}


}
}
9 changes: 9 additions & 0 deletions client/src/gamedata/en/descriptions/levels/disrupbet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Could you bet even though the betting time limit has expired? Keep in mind that you already know the winning option and you could "Cheat" and collect the bet plus the profit.

The objective of this level is to be able to bet on the winning team and claim the prize with your winnings even if the time limit for betting is over.


 
things that can help
* Solidity Remix IDE
* Timestamp
18 changes: 18 additions & 0 deletions client/src/gamedata/en/descriptions/levels/disrupbet_complete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

Very good, you were able to collect your bet.!! Congratulations. Surely you thought that this is a very silly error that you just violated, right? But do not believe these basic errors are made very often and there are many vulnerable contracts due to a simple oversight. They are errors that a basic test would not detect. So from now on, pay close attention to the details so that it doesn't happen to you.


```
//------- MODIFIERS ----------
modifier onlyOwner() {
require(msg.sender == owner, "Onlyowner: user not owner");
_;
}
// I am missing the onlyOwner in this function

function setDateFinish(uint256 newDate) external <--------- Error: onlyOwner //
{
START_WORLDCUP_FINALMATCH = newDate;
}

```
9 changes: 9 additions & 0 deletions client/src/gamedata/es/descriptions/levels/disrupbet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
¿Podrías apostar aunque el tiempo limite de apuesta haya finalizo?. Ten en cuenta que ya sabes la opción ganadora y podrías "Hacer trampa" y cobrar lo apostado mas la ganancia.

El objetivo de este nivel es poder apostar por el equipo ganador y reclamar el premio con tu ganancia aunque el tiempo limite para apostar este finalizado.


&nbsp;
Cosas que pueden ayudar
* Solidity Remix IDE
* Timestamp
18 changes: 18 additions & 0 deletions client/src/gamedata/es/descriptions/levels/disrupbet_complete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

Muy bien, pudiste cobrar tu apuesta.!! Te felicito. Seguro que pensaste que es un error muy tonto este que acabas de vulnerar, ¿verdad? Pero no te creas estos errores básicos se comenten muy de seguido y existen muchos contratos vulnerables por un simple descuido. Son errores que un test básico no detectaria. Así que de ahora en adelante fíjate muy bien en los detalles para que no te pase.

```
//------- MODIFIERS ----------
modifier onlyOwner() {
require(msg.sender == owner, "Onlyowner: user not owner");
_;
}
// Falto el onlyOwner en esta función

function setDateFinish(uint256 newDate) external <--------- Error: onlyOwner //
{
START_WORLDCUP_FINALMATCH = newDate;
}

```

15 changes: 15 additions & 0 deletions client/src/gamedata/gamedata.json
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,21 @@
"deployId": "28",
"instanceGas": 1000000,
"author": "KStasi"
},
{
"name": "Bets",
"created": "2023-01-25",
"difficulty": "1",
"description": "disrupbet.md",
"completedDescription": "disrupbet_complete.md",
"levelContract": "DisrupBetFactory.sol",
"instanceContract": "DisrupBet.sol",
"revealCode": true,
"deployParams": [],
"deployFunds": 0,
"deployId": "29",
"instanceGas": 450000,
"author": "heavydeveloper"
}
]
}
87 changes: 87 additions & 0 deletions contracts/contracts/levels/DisrupBet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract DisrupBet {
uint256 START_WORLDCUP_FINALMATCH = 1653765302; // Unix Timestamp
uint256 public totalBettedAmount = 0;
uint256 public winnerId = 1;
TeamInfo[4] public teamList;
mapping(uint256 => mapping(address => uint256)) teamUserBets;

struct TeamInfo {
uint256 id;
string name;
uint256 amountBetted;
}
modifier isBettingOpen() {
require(
block.timestamp <= START_WORLDCUP_FINALMATCH,
"Bet out of time range"
);
_;
}

constructor() {
initializeTeams(["Barcelona FC","Real Madrid","Manchester City","PSG"]);
teamList[3].amountBetted += 1000 * (1 ether);
teamUserBets[3][msg.sender] += 1;
totalBettedAmount += 1;
}

modifier validTeamId(uint256 teamId) {
require(teamId <= 4, "team ID must be between 0 and 4");
_;
}

function bet(uint256 teamId)
external
payable
validTeamId(teamId)
isBettingOpen
{
require(msg.value > 0, "nothing to bet");
require(winnerId <= 4);
teamList[teamId].amountBetted += msg.value;
teamUserBets[teamId][msg.sender] += msg.value;
totalBettedAmount += msg.value;
}

//check for reentrancy
function withdraw() external {
require(winnerId < 4);
uint256 userOwedAmount = (teamUserBets[winnerId][msg.sender] *
totalBettedAmount) / teamList[winnerId].amountBetted;
require(userOwedAmount > 0, "nothing to withdraw");
teamUserBets[winnerId][msg.sender] = 0;
transferEth();
}

//------- INTERNAL -------
function transferEth() internal {
(bool success, ) = msg.sender.call{value: address(this).balance}("");
require(success, "something went wrong");
}

function initializeTeams(string[4] memory _teamList) internal {
for (uint256 i = 0; i < _teamList.length; ) {
unchecked {
teamList[i].name = _teamList[i];
teamList[i].amountBetted = 0;
teamList[i].id = i;
++i;
}
}
}

function setDateFinish(uint256 newDate) external
{
START_WORLDCUP_FINALMATCH = newDate;
}

function TeamBets(uint256 _team) public view returns (uint256) {
unchecked {
uint256 amount = teamList[_team].amountBetted;
return amount;
}
}
}
21 changes: 21 additions & 0 deletions contracts/contracts/levels/DisrupBetFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "hardhat/console.sol";
import './DisrupBet.sol';
import './base/Level.sol';

contract DisrupBetFactory is Level {

function createInstance(address _player) override public payable returns (address) {
_player;
DisrupBet instance = new DisrupBet();
return address(instance);
}

function validateInstance(address payable _instance, address _player) override public view returns (bool) {
DisrupBet instance = DisrupBet(_instance);
uint256 TotalBets = instance.TeamBets(1);
return TotalBets > 0 ? true : false;
}
}
41 changes: 41 additions & 0 deletions contracts/test/levels/DisrupBet.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const DisrupBetFactory = artifacts.require('./levels/DisrupBetFactory.sol');
const DisrupBet = artifacts.require('./levels/DisrupBet.sol');
const utils = require('../utils/TestUtils');


contract('DisrupBet', function (accounts) {
let ethernaut;
let level;
let player = accounts[0];

beforeEach(async function () {
ethernaut = await utils.getEthernautWithStatsProxy();
level = await DisrupBetFactory.new();
await ethernaut.registerLevel(level.address);

});

it("check bets", async () => {
const instance = await utils.createLevelInstance(
ethernaut,
level.address,
player,
DisrupBet,
{ from: player }
);
const betTxn = await instance.totalBettedAmount();
assert(betTxn > 0, "the amount bet must be greater than 0")
})

it("Return error bet", async () => {
const instance = await utils.createLevelInstance(
ethernaut,
level.address,
player,
DisrupBet,
{ from: player }
);
await expect(instance.bet(1, {value: '00001'})).to.be.revertedWith("Bet out of time range")

})
});