编译器
0.8.24+commit.e11b9ed9
文件 1 的 8:AccessControl.sol
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
文件 2 的 8:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 3 的 8:ERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 4 的 8:IAccessControl.sol
pragma solidity ^0.8.20;
interface IAccessControl {
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
error AccessControlBadConfirmation();
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address callerConfirmation) external;
}
文件 5 的 8:IDataStreamsVerifier.sol
pragma solidity ^0.8.24;
interface IDataStreamsVerifier {
function lastRetrievedPrice() external view returns (int192);
function getPrice() external view returns (int192);
function verifyReportWithTimestamp(
bytes memory unverifiedReport,
uint8 feedNumber
) external returns (int192, uint32);
function assetId(uint8 index) external view returns (bytes32);
}
文件 6 的 8:IERC165.sol
pragma solidity ^0.8.20;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 7 的 8:ITreasury.sol
pragma solidity ^0.8.24;
interface ITreasury {
struct PermitData {
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}
function DISTRIBUTOR_ROLE() external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function lockedRakeback(
bytes32 gameId,
address player,
uint256 depositId
) external returns (uint256);
function depositAndLock(
uint256 amount,
address from,
bytes32 gameId,
uint256 depositId
) external returns (uint256);
function depositAndLock(
uint256 amount,
address from,
bytes32 gameId,
bool isRakeback
) external returns (uint256 rakeback);
function depositAndLockWithPermit(
uint256 amount,
address from,
bytes32 gameId,
uint256 depositId,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 rakeback);
function depositAndLockWithPermit(
uint256 amount,
address from,
bytes32 gameId,
bool isRakeback,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 rakeback);
function lock(
uint256 amount,
address from,
uint256 depositId,
bytes32 gameId
) external returns (uint256 rakeback);
function lock(
uint256 amount,
address from,
bytes32 gameId,
bool isRakeback
) external returns (uint256 rakeback);
function upkeep() external view returns (address);
function bullseyeResetLockedAmount(bytes32 gameId) external;
function distributeBullseye(
uint256 rate,
uint256 lostTeamRakeback,
address to,
bytes32 gameId,
uint256 depositId
) external;
function approvedTokens(address token) external returns (bool);
function refund(uint256 amount, address to, bytes32 gameId) external;
function refund(
uint256 amount,
address to,
bytes32 gameId,
uint256 depositId
) external;
function refundWithFees(
uint256 amount,
address to,
uint256 refundFee,
bytes32 gameId
) external;
function refundWithFees(
uint256 amount,
address to,
uint256 refundFee,
bytes32 gameId,
uint256 depositId
) external;
function universalDistribute(
address to,
uint256 initialDeposit,
bytes32 gameId,
uint256 rate
) external;
function withdrawGameFee(
uint256 lostTeamDeposits,
uint256 gameFee,
bytes32 gameId
) external returns (uint256 withdrawnFees);
function calculateRate(
uint256 wonTeamTotal,
uint256 lostTeamRakeback,
bytes32 gameId
) external returns (uint256);
function withdrawInitiatorFee(
uint256 lostTeamDeposits,
uint256 wonTeamDeposits,
uint256 initiatorFee,
address initiator,
bytes32 gameId
) external returns (uint256 withdrawnFees);
function calculateRakebackAmount(
address target,
uint256 initialDeposit
) external;
function setGameFinished(bytes32 gameId) external;
function withdrawRakebackSetup(bytes32 gameId, address target) external;
function setGameToken(bytes32 gameId, address token) external;
function minDepositAmount(address token) external returns (uint256 amount);
}
文件 8 的 8:UpDown.sol
pragma solidity ^0.8.24;
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {ITreasury} from "./interfaces/ITreasury.sol";
import {IDataStreamsVerifier} from "./interfaces/IDataStreamsVerifier.sol";
contract UpDown is AccessControl {
event NewMaxPlayersAmount(uint256 newMax);
event NewFee(uint256 newFee);
event NewTreasury(address newTreasury);
event UpDownCreated(
uint256 startTime,
uint32 stopPredictAt,
uint32 endTime,
uint8 feedNumber,
bytes32 gameId,
address token
);
event UpDownNewPlayer(
address player,
bool isLong,
uint256 depositAmount,
bytes32 gameId,
uint256 rakeback
);
event UpDownStarted(int192 startingPrice, bytes32 gameId);
event UpDownFinalized(int192 finalPrice, bool isLong, bytes32 gameId);
event UpDownCancelled(bytes32 gameId);
struct GameInfo {
uint256 startTime;
uint256 endTime;
uint256 stopPredictAt;
uint8 feedNumber;
}
uint256 constant timeGap = 30 seconds;
uint256 packedData;
bytes32 public constant GAME_MASTER_ROLE = keccak256("GAME_MASTER_ROLE");
address[] public UpPlayers;
address[] public DownPlayers;
mapping(address => bool) public isParticipating;
mapping(address => uint256) public depositAmounts;
bytes32 public currentGameId;
address public treasury;
uint256 public minDepositAmount;
uint256 public startingPrice;
uint256 public totalDepositsUp;
uint256 public totalDepositsDown;
uint256 public totalRakebackUp;
uint256 public totalRakebackDown;
uint256 public maxPlayers = 100;
uint256 public fee = 1500;
constructor() {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function startGame(
uint32 endTime,
uint32 stopPredictAt,
uint256 depositAmount,
address token,
uint8 feedNumber
) public onlyRole(GAME_MASTER_ROLE) {
require(packedData == 0, "Finish previous game first");
require(stopPredictAt - block.timestamp >= timeGap, "Wrong stop time");
require(
endTime - stopPredictAt >= timeGap,
"Timeframe gap must be higher"
);
require(
depositAmount >= ITreasury(treasury).minDepositAmount(token),
"Wrong min deposit amount"
);
require(
IDataStreamsVerifier(ITreasury(treasury).upkeep()).assetId(
feedNumber
) != bytes32(0),
"Wrong feed number"
);
packedData = (block.timestamp |
(uint256(stopPredictAt) << 32) |
(uint256(endTime) << 64) |
(uint256(feedNumber) << 96));
currentGameId = keccak256(
abi.encodePacked(endTime, block.timestamp, address(this))
);
ITreasury(treasury).setGameToken(currentGameId, token);
minDepositAmount = depositAmount;
emit UpDownCreated(
block.timestamp,
stopPredictAt,
endTime,
feedNumber,
currentGameId,
token
);
}
function play(bool isLong, uint256 depositAmount) public {
require(depositAmount >= minDepositAmount, "Wrong deposit amount");
require(!isParticipating[msg.sender], "Already participating");
require(
DownPlayers.length + UpPlayers.length + 1 <= maxPlayers,
"Max player amount reached"
);
GameInfo memory game = decodeData();
require(
game.stopPredictAt > block.timestamp,
"Game is closed for new players"
);
depositAmounts[msg.sender] = depositAmount;
isParticipating[msg.sender] = true;
uint256 rakeback = ITreasury(treasury).depositAndLock(
depositAmount,
msg.sender,
currentGameId,
true
);
if (isLong) {
totalRakebackUp += rakeback;
totalDepositsUp += depositAmount;
UpPlayers.push(msg.sender);
} else {
totalRakebackDown += rakeback;
totalDepositsDown += depositAmount;
DownPlayers.push(msg.sender);
}
emit UpDownNewPlayer(
msg.sender,
isLong,
depositAmount,
currentGameId,
rakeback
);
}
function playWithDeposit(bool isLong, uint256 depositAmount) public {
require(depositAmount >= minDepositAmount, "Wrong deposit amount");
require(!isParticipating[msg.sender], "Already participating");
require(
DownPlayers.length + UpPlayers.length + 1 <= maxPlayers,
"Max player amount reached"
);
GameInfo memory game = decodeData();
require(
game.stopPredictAt > block.timestamp,
"Game is closed for new players"
);
depositAmounts[msg.sender] = depositAmount;
uint256 rakeback = ITreasury(treasury).lock(
depositAmount,
msg.sender,
currentGameId,
true
);
if (isLong) {
totalRakebackUp += rakeback;
totalDepositsUp += depositAmount;
UpPlayers.push(msg.sender);
} else {
totalRakebackDown += rakeback;
totalDepositsDown += depositAmount;
DownPlayers.push(msg.sender);
}
isParticipating[msg.sender] = true;
emit UpDownNewPlayer(
msg.sender,
isLong,
depositAmount,
currentGameId,
rakeback
);
}
function playWithPermit(
bool isLong,
uint256 depositAmount,
ITreasury.PermitData calldata permitData
) public {
require(depositAmount >= minDepositAmount, "Wrong deposit amount");
require(!isParticipating[msg.sender], "Already participating");
require(
DownPlayers.length + UpPlayers.length + 1 <= maxPlayers,
"Max player amount reached"
);
GameInfo memory game = decodeData();
require(
game.stopPredictAt > block.timestamp,
"Game is closed for new players"
);
depositAmounts[msg.sender] = depositAmount;
isParticipating[msg.sender] = true;
uint256 rakeback = ITreasury(treasury).depositAndLockWithPermit(
depositAmount,
msg.sender,
currentGameId,
true,
permitData.deadline,
permitData.v,
permitData.r,
permitData.s
);
if (isLong) {
totalRakebackUp += rakeback;
totalDepositsUp += depositAmount;
UpPlayers.push(msg.sender);
} else {
totalRakebackDown += rakeback;
totalDepositsDown += depositAmount;
DownPlayers.push(msg.sender);
}
emit UpDownNewPlayer(
msg.sender,
isLong,
depositAmount,
currentGameId,
rakeback
);
}
function setStartingPrice(
bytes memory unverifiedReport
) public onlyRole(GAME_MASTER_ROLE) {
GameInfo memory game = decodeData();
require(startingPrice == 0, "Starting price already set");
require(block.timestamp >= game.stopPredictAt, "Too early");
require(
UpPlayers.length != 0 || DownPlayers.length != 0,
"Not enough players"
);
address upkeep = ITreasury(treasury).upkeep();
(int192 priceData, uint32 priceTimestamp) = IDataStreamsVerifier(upkeep)
.verifyReportWithTimestamp(unverifiedReport, game.feedNumber);
require(
priceTimestamp - game.stopPredictAt <= 1 minutes,
"Old chainlink report"
);
startingPrice = uint192(priceData);
emit UpDownStarted(priceData, currentGameId);
}
function finalizeGame(
bytes memory unverifiedReport
) public onlyRole(GAME_MASTER_ROLE) {
GameInfo memory game = decodeData();
require(packedData != 0, "Start the game first");
require(block.timestamp >= game.endTime, "Too early to finish");
if (UpPlayers.length == 0 || DownPlayers.length == 0) {
if (UpPlayers.length > 0) {
for (uint i; i < UpPlayers.length; i++) {
ITreasury(treasury).refund(
depositAmounts[UpPlayers[i]],
UpPlayers[i],
currentGameId
);
isParticipating[UpPlayers[i]] = false;
depositAmounts[UpPlayers[i]] = 0;
}
delete UpPlayers;
} else if (DownPlayers.length > 0) {
for (uint i; i < DownPlayers.length; i++) {
ITreasury(treasury).refund(
depositAmounts[DownPlayers[i]],
DownPlayers[i],
currentGameId
);
isParticipating[DownPlayers[i]] = false;
depositAmounts[DownPlayers[i]] = 0;
}
delete DownPlayers;
}
emit UpDownCancelled(currentGameId);
packedData = 0;
totalDepositsUp = 0;
totalDepositsDown = 0;
totalRakebackUp = 0;
totalRakebackDown = 0;
startingPrice = 0;
currentGameId = bytes32(0);
return;
}
require(startingPrice != 0, "Starting price must be set");
address upkeep = ITreasury(treasury).upkeep();
(int192 finalPrice, uint32 priceTimestamp) = IDataStreamsVerifier(
upkeep
).verifyReportWithTimestamp(unverifiedReport, game.feedNumber);
require(
priceTimestamp - game.endTime <= 1 minutes,
"Old chainlink report"
);
if (uint192(finalPrice) > startingPrice) {
ITreasury(treasury).withdrawGameFee(
totalDepositsDown,
fee,
currentGameId
);
uint256 finalRate = ITreasury(treasury).calculateRate(
totalDepositsUp,
totalRakebackDown,
currentGameId
);
for (uint i = 0; i < UpPlayers.length; i++) {
ITreasury(treasury).universalDistribute(
UpPlayers[i],
depositAmounts[UpPlayers[i]],
currentGameId,
finalRate
);
}
emit UpDownFinalized(finalPrice, true, currentGameId);
} else if (uint192(finalPrice) < startingPrice) {
ITreasury(treasury).withdrawGameFee(
totalDepositsUp,
fee,
currentGameId
);
uint256 finalRate = ITreasury(treasury).calculateRate(
totalDepositsDown,
totalRakebackUp,
currentGameId
);
for (uint i = 0; i < DownPlayers.length; i++) {
ITreasury(treasury).universalDistribute(
DownPlayers[i],
depositAmounts[DownPlayers[i]],
currentGameId,
finalRate
);
}
emit UpDownFinalized(finalPrice, false, currentGameId);
} else if (uint192(finalPrice) == startingPrice) {
for (uint i; i < UpPlayers.length; i++) {
ITreasury(treasury).refund(
depositAmounts[UpPlayers[i]],
UpPlayers[i],
currentGameId
);
isParticipating[UpPlayers[i]] = false;
}
delete UpPlayers;
for (uint i; i < DownPlayers.length; i++) {
ITreasury(treasury).refund(
depositAmounts[DownPlayers[i]],
DownPlayers[i],
currentGameId
);
isParticipating[DownPlayers[i]] = false;
}
delete DownPlayers;
emit UpDownCancelled(currentGameId);
totalDepositsUp = 0;
totalDepositsDown = 0;
totalRakebackUp = 0;
totalRakebackDown = 0;
startingPrice = 0;
packedData = 0;
totalRakebackUp = 0;
totalRakebackDown = 0;
currentGameId = bytes32(0);
return;
}
for (uint i = 0; i < UpPlayers.length; i++) {
depositAmounts[UpPlayers[i]] = 0;
isParticipating[UpPlayers[i]] = false;
}
for (uint i = 0; i < DownPlayers.length; i++) {
depositAmounts[DownPlayers[i]] = 0;
isParticipating[DownPlayers[i]] = false;
}
delete DownPlayers;
delete UpPlayers;
ITreasury(treasury).setGameFinished(currentGameId);
currentGameId = bytes32(0);
packedData = 0;
totalDepositsUp = 0;
totalDepositsDown = 0;
totalRakebackUp = 0;
totalRakebackDown = 0;
startingPrice = 0;
}
function closeGame() public onlyRole(GAME_MASTER_ROLE) {
require(currentGameId != bytes32(0), "Game not started");
for (uint i; i < UpPlayers.length; i++) {
ITreasury(treasury).refund(
depositAmounts[UpPlayers[i]],
UpPlayers[i],
currentGameId
);
isParticipating[UpPlayers[i]] = false;
depositAmounts[UpPlayers[i]] = 0;
}
delete UpPlayers;
for (uint i; i < DownPlayers.length; i++) {
ITreasury(treasury).refund(
depositAmounts[DownPlayers[i]],
DownPlayers[i],
currentGameId
);
isParticipating[DownPlayers[i]] = false;
depositAmounts[DownPlayers[i]] = 0;
}
delete DownPlayers;
emit UpDownCancelled(currentGameId);
currentGameId = bytes32(0);
packedData = 0;
totalDepositsUp = 0;
totalDepositsDown = 0;
totalRakebackUp = 0;
totalRakebackDown = 0;
startingPrice = 0;
}
function decodeData() public view returns (GameInfo memory data) {
data.startTime = uint256(uint32(packedData));
data.stopPredictAt = uint256(uint32(packedData >> 32));
data.endTime = uint256(uint32(packedData >> 64));
data.feedNumber = uint8(packedData >> 96);
}
function getTotalPlayers() public view returns (uint256, uint256) {
return (UpPlayers.length, DownPlayers.length);
}
function setMaxPlayers(uint256 newMax) public onlyRole(DEFAULT_ADMIN_ROLE) {
maxPlayers = newMax;
emit NewMaxPlayersAmount(newMax);
}
function setTreasury(
address newTreasury
) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(newTreasury != address(0), "Zero address");
treasury = newTreasury;
emit NewTreasury(newTreasury);
}
function setFee(uint256 newFee) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(newFee <= 3000, "Fee exceeds the cap");
fee = newFee;
emit NewFee(newFee);
}
}
{
"compilationTarget": {
"contracts/UpDown.sol": "UpDown"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"NewFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMax","type":"uint256"}],"name":"NewMaxPlayersAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newTreasury","type":"address"}],"name":"NewTreasury","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"gameId","type":"bytes32"}],"name":"UpDownCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"stopPredictAt","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"endTime","type":"uint32"},{"indexed":false,"internalType":"uint8","name":"feedNumber","type":"uint8"},{"indexed":false,"internalType":"bytes32","name":"gameId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"UpDownCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int192","name":"finalPrice","type":"int192"},{"indexed":false,"internalType":"bool","name":"isLong","type":"bool"},{"indexed":false,"internalType":"bytes32","name":"gameId","type":"bytes32"}],"name":"UpDownFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"bool","name":"isLong","type":"bool"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"gameId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"rakeback","type":"uint256"}],"name":"UpDownNewPlayer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int192","name":"startingPrice","type":"int192"},{"indexed":false,"internalType":"bytes32","name":"gameId","type":"bytes32"}],"name":"UpDownStarted","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"DownPlayers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GAME_MASTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"UpPlayers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"closeGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentGameId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decodeData","outputs":[{"components":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"stopPredictAt","type":"uint256"},{"internalType":"uint8","name":"feedNumber","type":"uint8"}],"internalType":"struct UpDown.GameInfo","name":"data","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"depositAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"unverifiedReport","type":"bytes"}],"name":"finalizeGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalPlayers","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isParticipating","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPlayers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDepositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"uint256","name":"depositAmount","type":"uint256"}],"name":"play","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"uint256","name":"depositAmount","type":"uint256"}],"name":"playWithDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ITreasury.PermitData","name":"permitData","type":"tuple"}],"name":"playWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMax","type":"uint256"}],"name":"setMaxPlayers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"unverifiedReport","type":"bytes"}],"name":"setStartingPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"stopPredictAt","type":"uint32"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"feedNumber","type":"uint8"}],"name":"startGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startingPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDepositsDown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDepositsUp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRakebackDown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRakebackUp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]