Created
June 26, 2024 18:02
-
-
Save zulnabil/55aecc3eee151033826767dcbb7469c3 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.26+commit.8a97fa7a.js&optimize=false&runs=200&gist=
This file contains hidden or 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
| // SPDX-License-Identifier: UNLICENSED | |
| pragma solidity ^0.8.13; | |
| import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
| import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | |
| // Using SafeERC20 for IERC20 tokens to safely interact with ERC20 tokens. | |
| using SafeERC20 for IERC20; | |
| contract PredictionMarket { | |
| // Enum to define the type of event: Single (yes/no) or Multiple (multiple outcomes). | |
| enum EventType { Single, Multiple } | |
| // Struct to represent a Bet in the market. | |
| struct Bet { | |
| uint256 eventId; // The ID of the event the bet is placed on. | |
| uint256 outcome; // The chosen outcome of the bet. | |
| uint256 amount; // The amount of tokens bet. | |
| address payable user; // The address of the user who placed the bet. | |
| address tokenAddress; // The address of the ERC20 token used for the bet. | |
| bool isResolved; // Whether the bet has been resolved. | |
| bool won; // Whether the bet was a winning bet. | |
| } | |
| // Struct to represent an Outcome within an event. | |
| struct Outcome { | |
| uint256 id; // The ID of the outcome. | |
| string description; // Description of the outcome. | |
| uint256 totalAmount; // Total amount bet on this outcome. | |
| uint256 multiplier; // Multiplier for payout calculation. | |
| string imageUrl; // Image URL representing the outcome. | |
| } | |
| // Struct to represent an Event in the prediction market. | |
| struct Event { | |
| string description; // Description of the event. | |
| EventType eventType; // Type of the event (Single or Multiple). | |
| bool isResolved; // Whether the event has been resolved. | |
| uint256 winningOutcome; // The ID of the winning outcome. | |
| Outcome[] outcomes; // List of outcomes for the event. | |
| Bet[] bets; // List of bets placed on the event. | |
| string imageUrl; // Image URL representing the event. | |
| } | |
| mapping(uint256 => Event) public events; // Mapping of event IDs to events. | |
| uint256 public eventCount; // Total number of events created. | |
| uint256 public betCount; // Total number of bets placed. | |
| event EventCreated(uint256 indexed eventId, string description, string imageUrl, EventType eventType); // Event emitted when a new event is created. | |
| event OutcomeAdded(uint256 indexed eventId, uint256 outcomeId, string description, string imageUrl); // Event emitted when a new outcome is added. | |
| event BetPlaced(uint256 indexed eventId, uint256 indexed betId, uint256 outcome, uint256 amount, address user, address tokenAddress); // Event emitted when a bet is placed. | |
| event EventResolved(uint256 indexed eventId, uint256 winningOutcome); // Event emitted when an event is resolved. | |
| // Function to create a new event. | |
| function createEvent(string memory description, string memory imageUrl, EventType eventType) public { | |
| eventCount++; // Increment event count. | |
| Event storage newEvent = events[eventCount]; // Create a new event. | |
| newEvent.description = description; | |
| newEvent.eventType = eventType; | |
| newEvent.isResolved = false; | |
| newEvent.winningOutcome = 0; | |
| newEvent.imageUrl = imageUrl; | |
| // If the event type is Single, add default outcomes "Yes" and "No". | |
| if (eventType == EventType.Single) { | |
| newEvent.outcomes.push(Outcome({ id: 0, description: "Yes", totalAmount: 0, multiplier: 0, imageUrl: "" })); | |
| newEvent.outcomes.push(Outcome({ id: 1, description: "No", totalAmount: 0, multiplier: 0, imageUrl: "" })); | |
| } | |
| emit EventCreated(eventCount, description, imageUrl, eventType); // Emit event created event. | |
| } | |
| // Function to add an outcome to an existing event. | |
| function addOutcome(uint256 eventId, string memory description, string memory imageUrl) public { | |
| Event storage eventToUpdate = events[eventId]; | |
| require(eventToUpdate.eventType == EventType.Multiple, "Only multiple option events can add outcomes"); | |
| uint256 outcomeId = eventToUpdate.outcomes.length; // Get the new outcome ID. | |
| eventToUpdate.outcomes.push(Outcome({ | |
| id: outcomeId, | |
| description: description, | |
| totalAmount: 0, | |
| multiplier: 0, | |
| imageUrl: imageUrl | |
| })); | |
| emit OutcomeAdded(eventId, outcomeId, description, imageUrl); // Emit outcome added event. | |
| } | |
| // Function to place a bet on an event. | |
| function placeBet(uint256 eventId, uint256 outcome, uint256 amount, address tokenAddress) public { | |
| require(amount > 0, "Bet amount must be greater than zero"); // Ensure bet amount is greater than zero. | |
| Event storage eventToBet = events[eventId]; | |
| require(!eventToBet.isResolved, "Event already resolved"); // Ensure event is not resolved. | |
| require(outcome < eventToBet.outcomes.length, "Invalid outcome"); // Ensure outcome is valid. | |
| IERC20 token = IERC20(tokenAddress); // Get the token contract. | |
| uint256 allowance = token.allowance(msg.sender, address(this)); | |
| require(allowance >= amount, "Check the token allowance"); // Ensure sufficient allowance. | |
| uint256 balance = token.balanceOf(msg.sender); | |
| require(balance >= amount, "Insufficient token balance"); // Ensure sufficient token balance. | |
| token.safeTransferFrom(msg.sender, address(this), amount); // Transfer tokens from the user to the contract. | |
| // Create a new bet. | |
| Bet memory newBet = Bet({ | |
| eventId: eventId, | |
| outcome: outcome, | |
| amount: amount, | |
| user: payable(msg.sender), | |
| tokenAddress: tokenAddress, | |
| isResolved: false, | |
| won: false | |
| }); | |
| eventToBet.bets.push(newBet); // Add the bet to the event. | |
| eventToBet.outcomes[outcome].totalAmount += amount; // Update the total amount for the outcome. | |
| betCount++; // Increment the bet count. | |
| _updateMultipliers(eventId); // Update the multipliers for the event. | |
| emit BetPlaced(eventId, betCount, outcome, amount, msg.sender, tokenAddress); // Emit bet placed event. | |
| } | |
| // Internal function to update the multipliers for an event. | |
| function _updateMultipliers(uint256 eventId) internal { | |
| Event storage eventToUpdate = events[eventId]; | |
| uint256 totalPool = 0; | |
| // Calculate total pool amount. | |
| for (uint256 i = 0; i < eventToUpdate.outcomes.length; i++) { | |
| totalPool += eventToUpdate.outcomes[i].totalAmount; | |
| } | |
| // Calculate multipliers. | |
| for (uint256 i = 0; i < eventToUpdate.outcomes.length; i++) { | |
| if (eventToUpdate.outcomes[i].totalAmount > 0) { | |
| eventToUpdate.outcomes[i].multiplier = totalPool * 1e18 / eventToUpdate.outcomes[i].totalAmount; | |
| } else { | |
| eventToUpdate.outcomes[i].multiplier = 0; | |
| } | |
| } | |
| } | |
| // Function to resolve an event. | |
| function resolveEvent(uint256 eventId, uint256 winningOutcome) public { | |
| Event storage eventToResolve = events[eventId]; | |
| require(!eventToResolve.isResolved, "Event already resolved"); // Ensure event is not resolved. | |
| require(winningOutcome < eventToResolve.outcomes.length, "Invalid outcome"); // Ensure winning outcome is valid. | |
| eventToResolve.isResolved = true; // Mark event as resolved. | |
| eventToResolve.winningOutcome = winningOutcome; // Set the winning outcome. | |
| // Iterate through all bets and transfer rewards to winners. | |
| for (uint256 i = 0; i < eventToResolve.bets.length; i++) { | |
| if (eventToResolve.bets[i].outcome == winningOutcome) { | |
| eventToResolve.bets[i].won = true; | |
| uint256 reward = (eventToResolve.bets[i].amount * eventToResolve.outcomes[winningOutcome].multiplier) / 1e18; | |
| IERC20 token = IERC20(eventToResolve.bets[i].tokenAddress); | |
| token.safeTransfer(eventToResolve.bets[i].user, reward); | |
| } | |
| eventToResolve.bets[i].isResolved = true; | |
| } | |
| emit EventResolved(eventId, winningOutcome); // Emit event resolved event. | |
| } | |
| // Function to get all events. | |
| function getEvents() public view returns (Event[] memory) { | |
| Event[] memory result = new Event[](eventCount); | |
| for (uint256 i = 1; i <= eventCount; i++) { | |
| result[i - 1] = events[i]; | |
| } | |
| return result; | |
| } | |
| // Function to get a specific event by its ID. | |
| function getEventById(uint256 eventId) public view returns (Event memory) { | |
| require(eventId > 0 && eventId <= eventCount, "Event ID is out of range"); // Ensure event ID is valid. | |
| return events[eventId]; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment