Skip to content

Commit

Permalink
mock resolver & factory
Browse files Browse the repository at this point in the history
  • Loading branch information
hamdiallam committed Nov 8, 2024
1 parent 65e2808 commit 5bb5de6
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 30 deletions.
35 changes: 35 additions & 0 deletions contracts/script/predictionmarket/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {Script, console} from "forge-std/Script.sol";
import {PredictionMarket} from "../../src/predictionmarket/PredictionMarket.sol";

import {TicTacToe} from "../../src/tictactoe/TicTacToe.sol";
import {TicTacToePredictionMarketFactory} from "../../src/predictionmarket/factories/TicTacToePredictionMarketFactory.sol";
import {MockMarketFactory} from "../../src/predictionmarket/factories/MockMarketFactory.sol";
contract DeployScript is Script {
function setUp() public {}

function run() public {
// Only Prediction Market App Chain
require(block.chainid == 901);

// sanity check that this is deployed with an eth_call
TicTacToe tictactoe = TicTacToe(address(0xe405EE520988f6F4f508f64108436911B7816135));
console.log("Querying TicTacToe contract");
tictactoe.nextGameId();

vm.broadcast();

// Deploy Prediction Market
PredictionMarket market = new PredictionMarket{salt: "predictionmarket"}();

// Deploy Factories for the different kinds of markets
TicTacToePredictionMarketFactory factory = new TicTacToePredictionMarketFactory{salt: "tictactoefactory"}(tictactoe, market);
MockMarketFactory mockFactory = new MockMarketFactory{salt: "mockfactory"}(market);

console.log("PredictionMarket Deployed at: ", address(market));
console.log("TicTacToePredictionMarketFactory Deployed at: ", address(factory));
console.log("MockMarketFactory Deployed at: ", address(mockFactory));
}
}
10 changes: 5 additions & 5 deletions contracts/src/predictionmarket/PredictionMarket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,19 @@ contract PredictionMarket {
event NewMarket(IMarketResolver _resolver, address yesToken, address noToken, address lpToken);

// @notice emitted when a market has been resolved
event MarketResolved(IMarketResolver _resolver, MarketOutcome outcome);
event MarketResolved(IMarketResolver indexed _resolver, MarketOutcome outcome);

// @notice emitted when liquidity has been added to a market
event LiquidityAdded(IMarketResolver resolver, address provider, uint256 ethAmount);
event LiquidityAdded(IMarketResolver indexed resolver, address provider, uint256 ethAmount);

// @notice emitted when liquidity has been redeemed from a market
event LiquidityRedeemed(IMarketResolver resolver, address redeemer, uint256 yesAmount, uint256 noAmount);
event LiquidityRedeemed(IMarketResolver indexed resolver, address redeemer, uint256 yesAmount, uint256 noAmount);

// @notice emitted when a bet has been placed on a market
event BetPlaced(IMarketResolver resolver, address bettor, MarketOutcome outcome, uint256 amountIn, uint256 amountOut);
event BetPlaced(IMarketResolver indexed resolver, address bettor, MarketOutcome outcome, uint256 amountIn, uint256 amountOut);

// @notice emitted when an outcome token has been redeemed
event OutcomeRedeemed(IMarketResolver resolver, address redeemer, MarketOutcome outcome, uint256 amount);
event OutcomeRedeemed(IMarketResolver indexed resolver, address redeemer, MarketOutcome outcome, uint256 amount);

// @notice create and seed a new prediction market with liquidity
// @param _resolver contract identifying the outcome for an open market
Expand Down
19 changes: 19 additions & 0 deletions contracts/src/predictionmarket/factories/MockMarketFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {PredictionMarket} from "../PredictionMarket.sol";
import {MockResolver} from "../resolvers/MockResolver.sol";

contract MockMarketFactory {
// @notice PredictionMarket contract
PredictionMarket public predictionMarket;

constructor(PredictionMarket _predictionMarket) {
predictionMarket = _predictionMarket;
}

function newMarket() external {
MockResolver resolver = new MockResolver();
predictionMarket.newMarket(resolver);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ contract TicTacToePredictionMarketFactory {
// @notice Emitted when a new market for tictactoe is created
event TicTacToeMarketCreated(IMarketResolver resolver);

// @notice indiciator if a resolver originated from this factory
mapping(IMarketResolver => bool) public fromFactory;

// @notice create a new factory instantiating prediction markets based
// on the outcome of the TicTacToe games
// @param _gameAddress TicTacToe contract address
Expand Down Expand Up @@ -47,6 +50,8 @@ contract TicTacToePredictionMarketFactory {
// Create resolver for the game & market
IMarketResolver resolver = new TicTacToeGameResolver(game, chainId, gameId, opponent);
predictionMarket.newMarket(resolver);

fromFactory[resolver] = true;

emit TicTacToeMarketCreated(resolver);
}
Expand Down
42 changes: 42 additions & 0 deletions contracts/src/predictionmarket/resolvers/L1BlockResolver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {Predeploys} from "@contracts-bedrock/libraries/Predeploys.sol";
import {ICrossL2Inbox} from "@contracts-bedrock/L2/interfaces/ICrossL2Inbox.sol";

import { IMarketResolver, MarketOutcome } from "../MarketResolver.sol";

contract L1BlockResolver is IMarketResolver {
// @notice Chain ID of the L2 chain
uint256 public chainId;

// @notice block height of this bet
uint256 public blockNumber;

// @notice whether the block hash is odd or even
bool public isOdd;

// @notice current outcome of this bet
MarketOutcome public outcome;

constructor(uint256 _chainId, uint256 _blockNumber, bool _isOdd) {
outcome = MarketOutcome.UNDECIDED;

chainId = _chainId;
blockNumber = _blockNumber;
isOdd = _isOdd;
}

function resolve(ICrossL2Inbox.Identifier calldata _id, bytes calldata _data) external {
require(_id.origin == Predeploys.L1_BLOCK_ATTRIBUTES);
ICrossL2Inbox(Predeploys.CROSS_L2_INBOX).validateMessage(_id, keccak256(_data));

require(_id.chainId == chainId);

if (uint256(blockhash(blockNumber)) % 2 == 0 && isOdd) {
outcome = MarketOutcome.NO;
} else {
outcome = MarketOutcome.YES;
}
}
}
15 changes: 15 additions & 0 deletions contracts/src/predictionmarket/resolvers/MockResolver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {IMarketResolver, MarketOutcome} from "../MarketResolver.sol";

contract MockResolver is IMarketResolver {
MarketOutcome public outcome;

function setOutcome(MarketOutcome _outcome) public {
require(outcome == MarketOutcome.UNDECIDED);
require(_outcome != MarketOutcome.UNDECIDED);

outcome = _outcome;
}
}
2 changes: 1 addition & 1 deletion contracts/src/tictactoe/TicTacToe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ contract TicTacToe {
if (selector != AcceptedGame.selector) revert DataNotAcceptedGame();

(uint256 chainId, uint256 gameId, address player, address opponent) = // player, opponent swapped in local view
abi.decode(_acceptedGameData[32:], (uint256, uint256, address, address));
abi.decode(_acceptedGameData[32:], (uint256, uint256, address, address));

// The accepted game was started from this chain, from the sender
if (chainId != block.chainid) revert GameChainMismatch();
Expand Down
23 changes: 11 additions & 12 deletions contracts/test/predictionmarket/PredictionMarket.t.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import { Test } from "forge-std/Test.sol";
import {Test} from "forge-std/Test.sol";

import { MintableBurnableERC20 } from "../../src/predictionmarket/utils/MintableBurnableERC20.sol";
import { MarketOutcome } from "../../src/predictionmarket/MarketResolver.sol";
import {MintableBurnableERC20} from "../../src/predictionmarket/utils/MintableBurnableERC20.sol";
import {MarketOutcome} from "../../src/predictionmarket/MarketResolver.sol";
import {MockResolver} from "../../src/predictionmarket/resolvers/MockResolver.sol";
import {
Market,
MarketStatus,
Expand All @@ -13,8 +14,6 @@ import {
PredictionMarket
} from "../../src/predictionmarket/PredictionMarket.sol";

import { TestResolver } from "./TestResolver.sol";

contract PredictionMarketTest is Test {
PredictionMarket public predictionMarket;

Expand All @@ -23,7 +22,7 @@ contract PredictionMarketTest is Test {
}

function test_newMarket_succeeds() public {
TestResolver testResolver = new TestResolver();
MockResolver testResolver = new MockResolver();
predictionMarket.newMarket(testResolver);

(MarketStatus status, MarketOutcome outcome, , , , ) = predictionMarket.markets(testResolver);
Expand All @@ -32,7 +31,7 @@ contract PredictionMarketTest is Test {
}

function test_newMarket_addLiquidityWithValue_succeeds() public {
TestResolver testResolver = new TestResolver();
MockResolver testResolver = new MockResolver();
predictionMarket.newMarket{ value: 1 ether }(testResolver);

(, , MintableBurnableERC20 yesToken, MintableBurnableERC20 noToken, MintableBurnableERC20 lpToken, uint256 liquidity) =
Expand All @@ -48,7 +47,7 @@ contract PredictionMarketTest is Test {
}

function test_newMarket_decidedOutcome_reverts() public {
TestResolver testResolver = new TestResolver();
MockResolver testResolver = new MockResolver();
testResolver.setOutcome(MarketOutcome.YES);

vm.expectRevert(ResolverOutcomeDecided.selector);
Expand All @@ -57,7 +56,7 @@ contract PredictionMarketTest is Test {

function test_buyOutcome_succeeds() public {
// seed some liquidity
TestResolver testResolver = new TestResolver();
MockResolver testResolver = new MockResolver();
predictionMarket.newMarket{ value: 1 ether }(testResolver);

(, , MintableBurnableERC20 yesToken, , ,) = predictionMarket.markets(testResolver);
Expand All @@ -74,7 +73,7 @@ contract PredictionMarketTest is Test {
}

function test_addLiquidity_succeeds() public {
TestResolver testResolver = new TestResolver();
MockResolver testResolver = new MockResolver();
predictionMarket.newMarket{ value: 1 ether }(testResolver);

// double the liquidity
Expand All @@ -92,15 +91,15 @@ contract PredictionMarketTest is Test {
}

function test_addLiquidity_noValue_reverts() public {
TestResolver testResolver = new TestResolver();
MockResolver testResolver = new MockResolver();
predictionMarket.newMarket(testResolver);

vm.expectRevert(NoValue.selector);
predictionMarket.addLiquidity(testResolver);
}

function test_addLiquidity_atFairOdds_succeeds() public {
TestResolver testResolver = new TestResolver();
MockResolver testResolver = new MockResolver();
predictionMarket.newMarket{ value: 1 ether }(testResolver);

(, , MintableBurnableERC20 yesToken, MintableBurnableERC20 noToken, MintableBurnableERC20 lpToken, ) =
Expand Down
12 changes: 0 additions & 12 deletions contracts/test/predictionmarket/TestResolver.sol

This file was deleted.

0 comments on commit 5bb5de6

Please sign in to comment.