Created
March 14, 2022 22:10
-
-
Save 0xfoobar/c7f620e62339b0e7d201cb64f5042eef to your computer and use it in GitHub Desktop.
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.12; | |
import {IERC20} from "../interfaces/IERC20.sol"; | |
contract BetEscrow { | |
event BetOffered(uint betId); | |
enum Status { | |
Offered, | |
Accepted, | |
Settled | |
} | |
enum Outcome { | |
A, | |
B, | |
Neutral | |
} | |
struct Bet { | |
uint id; | |
address playerA; | |
address playerB; | |
address adjucator; | |
IERC20 token; | |
uint amount; | |
Status status; | |
} | |
mapping(uint => Bet) public bets; | |
uint public nextBetId = 0; | |
bool internal locked; | |
modifier noReentrant() { | |
require(!locked, "No re-entrancy"); | |
locked = true; | |
_; | |
locked = false; | |
} | |
function offerBet(address _playerB, address _adjucator, IERC20 token, uint amount) external { | |
IERC20(token).transferFrom(msg.sender, address(this), amount); | |
Bet memory bet = Bet({ | |
id: nextBetId, | |
playerA: msg.sender, | |
playerB: _playerB, | |
adjucator: _adjucator, | |
token: token, | |
amount: amount, | |
status: Status.Offered | |
}); | |
bets[nextBetId] = bet; | |
emit BetOffered(nextBetId); | |
nextBetId += 1; | |
} | |
function withdrawOffer(uint betId) external noReentrant { | |
Bet memory bet = bets[betId]; | |
require(msg.sender == bet.playerA, "Not the offer creator"); | |
require(bet.status == Status.Offered, "Not offered"); | |
// Cache values before deleting | |
IERC20 _token = bet.token; | |
uint _amount = bet.amount; | |
// Delete bet before refunding to prevent reentrancy | |
delete bets[betId]; | |
// Refund | |
_token.transfer(msg.sender, _amount); | |
} | |
function acceptBet(uint betId) external { | |
Bet memory bet = bets[betId]; | |
require(msg.sender == bet.playerB, "Not the offer recipient"); | |
require(bet.status == Status.Offered, "Not offered"); | |
bet.token.transferFrom(msg.sender, address(this), bet.amount); | |
bets[betId].status = Status.Accepted; | |
} | |
function settleBet(uint betId, Outcome outcome) external noReentrant { | |
Bet memory bet = bets[betId]; | |
require(msg.sender == bet.adjucator, "Not the adjucator"); | |
require(bet.status == Status.Accepted, "Not accepted"); | |
if (outcome == Outcome.A) { | |
bet.token.transfer(bet.playerA, 2 * bet.amount); | |
} else if (outcome == Outcome.B) { | |
bet.token.transfer(bet.playerB, 2 * bet.amount); | |
} else if (outcome == Outcome.Neutral) { | |
bet.token.transfer(bet.playerA, bet.amount); | |
bet.token.transfer(bet.playerB, bet.amount); | |
} | |
bets[betId].status = Status.Settled; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment