Last active
February 23, 2025 14:52
-
-
Save k26dr/26f9b8a6c6f1c138d3e2460ee18173ad to your computer and use it in GitHub Desktop.
PeerBet
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.26; | |
| contract PeerBet { | |
| enum Side { PUSH, OVER, UNDER } | |
| struct Bet { | |
| uint counterStart; | |
| uint counterEnd; | |
| Side side; | |
| } | |
| struct Line { | |
| uint bettingEnds; | |
| uint payoutBegins; | |
| address resolver; | |
| bool cancelled; | |
| Side winner; | |
| mapping(Side => uint) counters; // Sum of bets on each side | |
| mapping(address => Bet) bets; | |
| } | |
| mapping(string => Line) lines; | |
| function register(string calldata id, uint bettingEnds, address resolver) public { | |
| require(lines[id].bettingEnds == 0, "Line is already registered"); | |
| lines[id].bettingEnds = bettingEnds; | |
| lines[id].payoutBegins = bettingEnds + 3*86400; // If oracle dies or something, winner defaults to PUSH, and refunds can begin 3 days after betting ends | |
| lines[id].resolver = resolver; | |
| } | |
| function bet(string calldata id, Side side) public payable { | |
| require(block.timestamp < lines[id].bettingEnds, "Betting period is over"); | |
| require(!lines[id].cancelled, "Line is cancelled"); | |
| require(msg.value > 0, "No value included in bet"); | |
| require(lines[id].bets[msg.sender].counterEnd == 0, "Cannot bet twice on a line with same address. Use a new address."); | |
| require(side == Side.OVER || side == Side.UNDER, "Cannot bet push"); | |
| lines[id].bets[msg.sender] = Bet( | |
| lines[id].counters[side], | |
| lines[id].counters[side] + msg.value, | |
| side | |
| ); | |
| lines[id].counters[side] += msg.value; | |
| } | |
| function setCanceled(string calldata id, bool cancelled) public { | |
| require(lines[id].resolver == msg.sender, "Only resolver can cancel line"); | |
| lines[id].cancelled = cancelled; | |
| if (cancelled) { | |
| lines[id].payoutBegins = block.timestamp + 86400; | |
| } else { | |
| lines[id].payoutBegins = lines[id].bettingEnds + 3*86400; | |
| } | |
| } | |
| function resolveLine(string calldata id, Side side) public { | |
| require(lines[id].resolver == msg.sender, "Only resolver can resolve line"); | |
| require(block.timestamp > lines[id].bettingEnds, "Betting has not ended"); | |
| lines[id].winner = side; | |
| lines[id].payoutBegins = block.timestamp + 86400; | |
| } | |
| function collectPayout(string calldata id) public { | |
| Bet memory myBet = lines[id].bets[msg.sender]; | |
| require(block.timestamp > lines[id].payoutBegins, "Payout period has not begun"); | |
| require(myBet.counterEnd > 0, "Bet does not exist. Did you already claim?"); | |
| require(lines[id].cancelled || lines[id].winner == myBet.side || lines[id].winner == Side.PUSH, "Your side lost"); | |
| Side otherSide = (myBet.side == Side.UNDER) ? Side.OVER : Side.UNDER; | |
| uint payoutAmount = 0; | |
| if (lines[id].winner == Side.PUSH || | |
| lines[id].cancelled || | |
| lines[id].counters[otherSide] > myBet.counterStart) // Bet did not activate | |
| { | |
| payoutAmount = myBet.counterEnd - myBet.counterStart; | |
| } | |
| else if (lines[id].winner == myBet.side) { | |
| payoutAmount = myBet.counterEnd > lines[id].counters[otherSide] ? | |
| 2 * (lines[id].counters[otherSide] - myBet.counterStart) : | |
| 2 * (myBet.counterEnd - myBet.counterStart); | |
| } | |
| delete lines[id].bets[msg.sender]; | |
| (bool success, ) = msg.sender.call{ value: payoutAmount }(""); | |
| require(success, "Transfer failed."); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment