Created
June 19, 2025 12:56
-
-
Save coderwithsense/ca14e2e0cba046962cc27a28eacd954d 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.30+commit.73712a01.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: MIT | |
pragma solidity ^0.8.20; | |
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; | |
contract PredictionGame { | |
enum Side { BULL, BEAR } | |
address public immutable creator; // e.g., 0xYourWallet | |
string public tokenPair; // e.g., "ETH/USD" | |
uint256 public immutable targetPrice; // e.g., 2900 | |
uint256 public immutable expiry; // e.g., block.timestamp + 2 days | |
uint256 public immutable creatorFee; // e.g., 100 (1%) | |
uint256 public immutable minBetAmount; // e.g., 0.01 ether | |
AggregatorV3Interface public immutable priceFeed; | |
uint256 public snapshotPrice; | |
bool public snapshotTaken; | |
bool public creatorWithdrawn; | |
mapping(address => uint256) public bullBets; | |
mapping(address => uint256) public bearBets; | |
uint256 public totalBull; | |
uint256 public totalBear; | |
event Mint(address indexed user, Side side, uint256 amount); | |
event Burn(address indexed user, Side side, uint256 amount, uint256 fee); | |
event SnapshotTaken(uint256 price); | |
event RewardClaimed(address indexed user, uint256 amount); | |
event CreatorFeeWithdrawn(address indexed creator, uint256 amount); | |
constructor( | |
address _creator, // e.g., 0xCreator | |
string memory _tokenPair, // e.g., "ETH/USD" | |
uint256 _targetPrice, // e.g., 2900 | |
uint256 _expiry, // e.g., block.timestamp + 2 days | |
uint256 _creatorFee, // e.g., 100 = 1% | |
uint256 _minBetAmount, // e.g., 0.01 ether | |
address _priceFeed // e.g., Chainlink ETH/USD feed address | |
) { | |
require(_creator != address(0), "Invalid creator"); | |
require(_expiry > block.timestamp, "Expiry must be future"); | |
require(_creatorFee <= 1000, "Max 10% creator fee"); | |
require(_minBetAmount > 0, "Minimum bet must be > 0"); | |
creator = _creator; | |
tokenPair = _tokenPair; | |
targetPrice = _targetPrice; | |
expiry = _expiry; | |
creatorFee = _creatorFee; | |
minBetAmount = _minBetAmount; | |
priceFeed = AggregatorV3Interface(_priceFeed); | |
} | |
modifier onlyBeforeExpiry() { | |
require(block.timestamp < expiry, "Market expired"); | |
_; | |
} | |
modifier onlyAfterExpiry() { | |
require(block.timestamp >= expiry, "Market not expired"); | |
_; | |
} | |
function getLatestPrice() public view returns (uint256) { | |
(, int256 price,,,) = priceFeed.latestRoundData(); | |
require(price > 0, "Invalid price"); | |
uint8 decimals = priceFeed.decimals(); | |
return uint256(price) / (10 ** decimals); | |
} | |
function mintBull() external payable onlyBeforeExpiry { | |
require(msg.value >= minBetAmount, "Bet below minimum"); | |
bullBets[msg.sender] += msg.value; | |
totalBull += msg.value; | |
emit Mint(msg.sender, Side.BULL, msg.value); | |
} | |
function mintBear() external payable onlyBeforeExpiry { | |
require(msg.value >= minBetAmount, "Bet below minimum"); | |
bearBets[msg.sender] += msg.value; | |
totalBear += msg.value; | |
emit Mint(msg.sender, Side.BEAR, msg.value); | |
} | |
function burnBull(uint256 amount) external onlyBeforeExpiry { | |
require(bullBets[msg.sender] >= amount, "Insufficient BULL balance"); | |
uint256 fee = calculateBurnFee(); | |
uint256 refund = amount - ((amount * fee) / 10000); | |
bullBets[msg.sender] -= amount; | |
totalBull -= amount; | |
payable(msg.sender).transfer(refund); | |
emit Burn(msg.sender, Side.BULL, amount, fee); | |
} | |
function burnBear(uint256 amount) external onlyBeforeExpiry { | |
require(bearBets[msg.sender] >= amount, "Insufficient BEAR balance"); | |
uint256 fee = calculateBurnFee(); | |
uint256 refund = amount - ((amount * fee) / 10000); | |
bearBets[msg.sender] -= amount; | |
totalBear -= amount; | |
payable(msg.sender).transfer(refund); | |
emit Burn(msg.sender, Side.BEAR, amount, fee); | |
} | |
function takeSnapshot() external onlyAfterExpiry { | |
require(!snapshotTaken, "Snapshot already taken"); | |
snapshotPrice = getLatestPrice(); | |
snapshotTaken = true; | |
emit SnapshotTaken(snapshotPrice); | |
} | |
function claim() external onlyAfterExpiry { | |
require(snapshotTaken, "Snapshot not taken"); | |
bool bullWins = snapshotPrice > targetPrice; | |
uint256 userBet; | |
uint256 payout; | |
uint256 rewardPool = totalBull + totalBear; | |
uint256 totalWinning = bullWins ? totalBull : totalBear; | |
if (bullWins) { | |
userBet = bullBets[msg.sender]; | |
require(userBet > 0, "Not a winner"); | |
bullBets[msg.sender] = 0; | |
} else { | |
userBet = bearBets[msg.sender]; | |
require(userBet > 0, "Not a winner"); | |
bearBets[msg.sender] = 0; | |
} | |
uint256 creatorCut = (rewardPool * creatorFee) / 10000; | |
payout = (rewardPool - creatorCut) * userBet / totalWinning; | |
payable(msg.sender).transfer(payout); | |
emit RewardClaimed(msg.sender, payout); | |
} | |
function withdrawCreatorFee() external onlyAfterExpiry { | |
require(msg.sender == creator, "Only creator"); | |
require(!creatorWithdrawn, "Already withdrawn"); | |
uint256 rewardPool = totalBull + totalBear; | |
uint256 feeAmount = (rewardPool * creatorFee) / 10000; | |
creatorWithdrawn = true; | |
payable(creator).transfer(feeAmount); | |
emit CreatorFeeWithdrawn(creator, feeAmount); | |
} | |
function calculateBurnFee() public view returns (uint256) { | |
uint256 timeLeft = expiry > block.timestamp ? expiry - block.timestamp : 0; | |
uint256 maxFee = 300; // 3% | |
uint256 minFee = 50; // 0.5% | |
if (timeLeft > 1 days) return minFee; | |
if (timeLeft < 1 hours) return maxFee; | |
return minFee + ((maxFee - minFee) * (1 days - timeLeft)) / (1 days - 1 hours); | |
} | |
receive() external payable { | |
revert("Use mint functions"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment