编译器
0.8.14+commit.80d49f37
文件 1 的 16:BoostSlots.sol
pragma solidity 0.8.14;
import "../GameMasterclass/GameMasterclass.sol";
import "../ClaimManager/IClaimManager.sol";
import "../House/IHouse.sol";
contract Slots is GameMasterclass {
uint8[] public reel1;
uint8[] public reel2;
uint8[] public reel3;
mapping ( uint8 => uint8 ) public numToCoinReel1;
mapping ( uint8 => uint8 ) public numToCoinReel2;
mapping ( uint8 => uint8 ) public numToCoinReel3;
struct Game {
address player;
uint256 betAmount;
address token;
uint256 amountForHouse;
uint8 numSpins;
uint8 whichBoost;
uint8[] num0;
uint8[] num1;
uint8[] num2;
uint256 payout;
bool hasEnded;
}
struct Boost {
uint8 boostOdds;
uint16 payoutReduction;
}
mapping ( uint8 => Boost ) public boosts;
mapping ( uint256 => Game ) public games;
mapping ( uint256 => uint256 ) private requestToGame;
uint256 public platformFee = 100;
uint256 public boostFee = 100;
uint8 public boostGasMultiplier = 180;
uint256 private constant FEE_DENOM = 10_000;
mapping ( uint8 => mapping ( uint8 => mapping ( uint8 => uint256 ) ) ) public payout;
uint256 public constant PAYOUT_DENOM = 10_000;
uint32 public base_spin_gas = 640_000;
uint32 public gas_per_spin = 60_000;
uint256 public minBuyInGas;
uint256 public buyInGasPerSpin;
uint8 public boostMultiplier;
uint256 public MIN_SPINS = 1;
uint256 public MAX_SPINS = 30;
bool public oddsLocked;
event SetPlatformFee(uint256 newFee);
event RandomnessRequested(uint256 gameId);
event GameStarted(address indexed user, uint256 gameId);
event GameEnded(
address indexed user,
uint256 gameId,
uint256 buyIn,
uint256 payout
);
event FulfilRandomFailed(uint256 requestId, uint256 gameId, uint256[] randomWords);
event OddsLocked();
constructor(
uint256 GAME_ID_,
address history_,
uint8[] memory reel1_,
uint8[] memory reel2_,
uint8[] memory reel3_,
uint256 minBuyInGas_,
uint256 buyInGasPerSpin_,
uint8[] memory boostOdds,
uint16[] memory payoutReductions
) GameMasterclass(GAME_ID_, history_) {
reel1 = reel1_;
reel2 = reel2_;
reel3 = reel3_;
require(
reel1_.length == reel2_.length &&
reel2_.length == reel3_.length,
'Invalid Reel Length'
);
minBuyInGas = minBuyInGas_;
buyInGasPerSpin = buyInGasPerSpin_;
for (uint8 i = 0; i < boostOdds.length;) {
boosts[i + 1] = Boost(boostOdds[i], payoutReductions[i]);
unchecked { ++i; }
}
}
function setMinSpins(uint256 newMin) external onlyOwner {
MIN_SPINS = newMin;
}
function setMaxSpins(uint256 newMax) external onlyOwner {
MAX_SPINS = newMax;
}
function setBoostGasMultiplier(uint8 newMultiplier) external onlyOwner {
boostGasMultiplier = newMultiplier;
}
function setBoost(uint8 boostId, uint8 boostOdds, uint16 payoutReduction) external onlyOwner {
require(boostId > 0, 'Invalid Boost ID');
boosts[boostId] = Boost(boostOdds, payoutReduction);
}
function setBuyInGasInfo(uint256 newMin, uint256 newGasPerSpin) external onlyOwner {
minBuyInGas = newMin;
buyInGasPerSpin = newGasPerSpin;
}
function setVRFGasInfo(uint32 newBase, uint32 newGasPerSpin) external onlyOwner {
base_spin_gas = newBase;
gas_per_spin = newGasPerSpin;
}
function setPlatformFee(uint256 newPlatform) external onlyOwner {
require(
newPlatform <= FEE_DENOM / 10,
'Cannot Exceed 10%'
);
platformFee = newPlatform;
emit SetPlatformFee(newPlatform);
}
function setBoostFee(uint256 newBoost) external onlyOwner {
require(
newBoost <= FEE_DENOM / 10,
'Cannot Exceed 10%'
);
boostFee = newBoost;
}
function lockOdds() external onlyOwner {
oddsLocked = true;
emit OddsLocked();
}
function setReels(
uint8[] calldata reel1_,
uint8[] calldata reel2_,
uint8[] calldata reel3_,
bool[] calldata enforce
) external onlyOwner {
require(
oddsLocked == false,
'Odds Are Locked'
);
require(
reel1_.length == reel2_.length &&
reel2_.length == reel3_.length,
'Invalid Reel Length'
);
reel1 = reel1_;
reel2 = reel2_;
reel3 = reel3_;
if (enforce[0]) {
enforceReel1();
}
if (enforce[1]) {
enforceReel2();
}
if (enforce[2]) {
enforceReel3();
}
}
function enforceReel1() public onlyOwner {
uint8 coin1 = 0;
uint8 len = reel1[reel1.length - 1];
for (uint8 i = 0; i < len;) {
numToCoinReel1[i] = coin1;
unchecked { ++i; }
if (i == reel1[coin1]) {
unchecked { ++coin1; }
}
}
}
function enforceReel2() public onlyOwner {
uint8 coin2 = 0;
uint8 len = reel2[reel2.length - 1];
for (uint8 i = 0; i < len;) {
numToCoinReel2[i] = coin2;
unchecked { ++i; }
if (i == reel2[coin2]) {
unchecked { ++coin2; }
}
}
}
function enforceReel3() public onlyOwner {
uint8 coin3 = 0;
uint8 len = reel3[reel3.length - 1];
for (uint8 i = 0; i < len;) {
numToCoinReel3[i] = coin3;
unchecked { ++i; }
if (i == reel3[coin3]) {
unchecked { ++coin3; }
}
}
}
function batchSetPayouts(
uint8[] calldata coins0,
uint8[] calldata coins1,
uint8[] calldata coins2,
uint256[] calldata payoutMultiplier
) external onlyOwner {
require(
oddsLocked == false,
'Odds are locked'
);
uint len = coins0.length;
require(
len == coins1.length,
'Invalid Length 0-1'
);
require(
len == coins2.length,
'Invalid Length 0-2'
);
require(
len == payoutMultiplier.length,
'Invalid Length 0-payout'
);
for (uint i = 0; i < len;) {
payout[coins0[i]][coins1[i]][coins2[i]] = payoutMultiplier[i];
unchecked { ++i; }
}
}
function _playGame(address player, address token, uint256 amount, bytes calldata gameData) internal override {
(
uint8 numSpins,
uint8 whichBoost,
uint256 gameId,
uint256 partnerId,
address ref
) = abi.decode(gameData, (uint8, uint8, uint256, uint256, address));
address _token = token;
require(
numSpins >= MIN_SPINS && numSpins <= MAX_SPINS,
'Invalid Spin Count'
);
require(
isValidGameId(gameId),
'Game ID Already Used'
);
uint256 gasRequired = getMinBuyInGas(numSpins, whichBoost > 0);
require(
msg.value >= gasRequired,
'Invalid Ether Sent For BuyIn Gas'
);
uint256 totalBetAmount = _token == address(0) ? msg.value - gasRequired : amount;
uint256 betAmountPerSpin = totalBetAmount / numSpins;
if (whichBoost > 0) {
require(
boosts[whichBoost].payoutReduction > 0,
'Invalid Boost'
);
}
TransferHelper.safeTransferETH(manager.chainlinkFeeReceiver(), gasRequired);
uint256 platformFeeAmount = whichBoost == 0 ?
( totalBetAmount * platformFee ) / FEE_DENOM :
( totalBetAmount * ( platformFee + boostFee ) ) / FEE_DENOM;
_processFee(_token, platformFeeAmount, partnerId, ref);
games[gameId].player = player;
games[gameId].betAmount = betAmountPerSpin;
games[gameId].token = _token;
games[gameId].amountForHouse = totalBetAmount - platformFeeAmount;
games[gameId].numSpins = numSpins;
games[gameId].whichBoost = whichBoost;
games[gameId].num0 = new uint8[](numSpins);
games[gameId].num1 = new uint8[](numSpins);
games[gameId].num2 = new uint8[](numSpins);
_registerBet(player, totalBetAmount, _token, partnerId);
_requestRandom(gameId, numSpins, 2_000_000);
_registerGameId(player, gameId);
emit GameStarted(player, gameId);
}
function _requestRandom(uint256 gameId, uint8 numSpins, uint32 gas) internal {
uint256 requestId = IRNG(manager.RNG()).requestRandom(
gas,
uint32(numSpins * uint8(3))
);
require(
requestToGame[requestId] == 0,
'RequestId In Use'
);
requestToGame[requestId] = gameId;
IHouse(getHouse(games[gameId].token)).randomRequested();
emit RandomnessRequested(gameId);
}
function fulfillRandomWords(
uint256 requestId,
uint256[] calldata randomWords
) external override onlyRNG {
uint256 gameId = requestToGame[requestId];
if (
gameId == 0 ||
games[gameId].player == address(0) ||
games[gameId].hasEnded == true
) {
emit FulfilRandomFailed(requestId, gameId, randomWords);
return;
}
games[gameId].hasEnded = true;
delete requestToGame[requestId];
IHouse(getHouse(games[gameId].token)).randomRequestResolved();
uint8 boostNo = games[gameId].whichBoost;
uint8 boostOdds = boosts[boostNo].boostOdds;
uint256 betAmountPerSpin = boostNo > 0 ?
( games[gameId].betAmount * boosts[boostNo].payoutReduction ) / 1_000 :
games[gameId].betAmount;
uint256 totalToPayout = 0;
uint8 numSpins = games[gameId].numSpins;
for (uint i = 0; i < numSpins;) {
uint256 rand1 = randomWords[i * 3];
uint256 rand2 = randomWords[(i * 3) + 1];
uint256 rand3 = randomWords[(i * 3) + 2];
uint8 index1 = numToCoinReel1[uint8(rand1 % numOptionsReel1())];
uint8 index2 = numToCoinReel2[uint8(rand2 % numOptionsReel2())];
uint8 index3 = numToCoinReel3[uint8(rand3 % numOptionsReel3())];
if (boostNo > 0) {
if (index1 > 0 && ( (uint256(keccak256(abi.encodePacked(rand1))) % 100) < boostOdds )) {
unchecked { --index1; }
}
if (index2 > 0 && ( (uint256(keccak256(abi.encodePacked(rand2))) % 100) < boostOdds )) {
unchecked { --index2; }
}
if (index3 > 0 && ( (uint256(keccak256(abi.encodePacked(rand3))) % 100) < boostOdds )) {
unchecked { --index3; }
}
}
games[gameId].num0[i] = index1;
games[gameId].num1[i] = index2;
games[gameId].num2[i] = index3;
if (payout[index1][index2][index3] > 0) {
unchecked {
totalToPayout += ( payout[index1][index2][index3] * betAmountPerSpin ) / PAYOUT_DENOM;
}
}
unchecked { ++i; }
}
games[gameId].payout = totalToPayout;
_handlePayout(games[gameId].token, games[gameId].player, totalToPayout, games[gameId].amountForHouse);
emit GameEnded(games[gameId].player, gameId, games[gameId].betAmount * numSpins, totalToPayout);
}
function optionsReel1() external view returns (uint8[] memory) {
return reel1;
}
function optionsReel2() external view returns (uint8[] memory) {
return reel2;
}
function optionsReel3() external view returns (uint8[] memory) {
return reel3;
}
function getMinIndexReel1(uint256 random) public view returns (uint8) {
uint8 len = uint8(reel1.length);
uint8 index = len;
for (uint8 i = 0; i < len;) {
if (random < reel1[i]) {
index = i;
break;
}
unchecked { ++i; }
}
return index;
}
function getMinIndexReel2(uint256 random) public view returns (uint8) {
uint8 len = uint8(reel2.length);
uint8 index = len;
for (uint8 i = 0; i < len;) {
if (random < reel2[i]) {
index = i;
break;
}
unchecked { ++i; }
}
return index;
}
function getMinIndexReel3(uint256 random) public view returns (uint8) {
uint8 len = uint8(reel3.length);
uint8 index = len;
for (uint8 i = 0; i < len;) {
if (random < reel3[i]) {
index = i;
break;
}
unchecked { ++i; }
}
return index;
}
function numOptionsReel1() public view returns (uint8) {
return reel1[reel1.length - 1];
}
function numOptionsReel2() public view returns (uint8) {
return reel2[reel2.length - 1];
}
function numOptionsReel3() public view returns (uint8) {
return reel3[reel3.length - 1];
}
function getPayout(uint8 coin1, uint8 coin2, uint8 coin3) public view returns (uint256) {
return payout[coin1][coin2][coin3];
}
function getMinBuyInGas(uint8 numSpins, bool withBoost) public view returns (uint256) {
uint256 baseGas = minBuyInGas + ( numSpins * buyInGasPerSpin );
return withBoost ? ( baseGas * boostGasMultiplier ) / 100 : baseGas;
}
function quoteValue(uint256 buyIn, uint8 numSpins, bool withBoost) external view returns (uint256) {
return ( buyIn * numSpins ) + getMinBuyInGas(numSpins, withBoost);
}
function getGameInfo(uint256 gameId) external view returns (
address player,
uint256 betAmount,
uint8 numSpins,
uint8[] memory num0,
uint8[] memory num1,
uint8[] memory num2,
uint256 totalPayout,
address token,
bool hasEnded
) {
player = games[gameId].player;
betAmount = games[gameId].betAmount;
numSpins = games[gameId].numSpins;
num0 = games[gameId].num0;
num1 = games[gameId].num1;
num2 = games[gameId].num2;
totalPayout = games[gameId].payout;
token = games[gameId].token;
hasEnded = games[gameId].hasEnded;
}
}
文件 2 的 16:GameMasterclass.sol
pragma solidity 0.8.14;
import "../lib/TransferHelper.sol";
import "../GovernanceManager/PVPOwnable.sol";
import "./IGame.sol";
import "../UserTracker/IUserInfoTracker.sol";
import "../House/IHouseManager.sol";
import "../House/IHouse.sol";
import "../House/ITokenHouse.sol";
import "../lib/IERC20.sol";
import "../ClaimManager/IClaimManager.sol";
import "../History/IHistoryManager.sol";
contract GameMasterclass is PVPOwnable, IGame {
uint256 public immutable GAME_ID;
IHistoryManager public immutable history;
bool public paused = false;
uint256[] public usedGameIds;
mapping ( uint256 => bool ) public isUsedGameId;
constructor(
uint256 GAME_ID_,
address history_
) {
GAME_ID = GAME_ID_;
history = IHistoryManager(history_);
}
function pause() external onlyOwner {
paused = true;
}
function resume() external onlyOwner {
paused = false;
}
function withdrawETH(address to, uint256 amount) external onlyOwner {
(bool s,) = payable(to).call{value: amount}("");
require(s);
}
function withdrawToken(address token, uint amount) external onlyOwner {
TransferHelper.safeTransfer(token, msg.sender, amount);
}
function _registerBet(address user, uint256 amount, address token, uint256 partnerId) internal {
IUserInfoTracker(manager.userInfoTracker()).wagered(user, amount, GAME_ID, token, partnerId);
}
function _processFee(address token, uint256 feeAmount, uint256 partnerId, address ref) internal {
if (token == address(0)) {
IFeeRecipient(manager.feeReceiver()).takeFee{value: feeAmount}(
token, 0, partnerId, ref
);
} else {
TransferHelper.safeTransfer(token, manager.feeReceiver(), feeAmount);
IFeeRecipient(manager.feeReceiver()).takeFee{value: 0}(
token, feeAmount, partnerId, ref
);
}
}
function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) external virtual {}
function play(address player, address token, uint256 amount, bytes calldata gameData) external payable override validGameToken(token) validatePlayer(player) {
require(
!paused,
'Paused'
);
if (token != address(0)) {
uint256 before = IERC20(token).balanceOf(address(this));
TransferHelper.safeTransferFrom(token, msg.sender, address(this), amount);
uint256 After = IERC20(token).balanceOf(address(this));
require(
After > before,
'Invalid Transfer'
);
uint256 received = After - before;
_playGame(player, token, received, gameData);
} else {
_playGame(player, token, msg.value, gameData);
}
}
function _playGame(address player, address token, uint256 amount, bytes calldata gameData) internal virtual {}
function _handlePayout(address token, address player, uint256 totalToPayout, uint256 amountForHouse) internal {
if (totalToPayout > 0) {
if (totalToPayout >= amountForHouse) {
if (token == address(0)) {
IClaimManager(manager.claimManager()).credit{value: amountForHouse}(
GAME_ID,
player
);
uint256 remaining = totalToPayout - amountForHouse;
if (remaining > 0) {
IHouse(manager.house()).payout(GAME_ID, player, remaining);
}
} else {
TransferHelper.safeTransfer(token, player, amountForHouse);
IClaimManager(manager.claimManager()).creditToken(
player,
token,
GAME_ID,
amountForHouse
);
uint256 remaining = totalToPayout - amountForHouse;
if (remaining > 0) {
address _house = getHouse(token);
ITokenHouse(_house).payout(GAME_ID, player, remaining);
}
}
} else {
if (token == address(0)) {
IClaimManager(manager.claimManager()).credit{value: totalToPayout}(
GAME_ID,
player
);
uint256 remaining = amountForHouse - totalToPayout;
IHouse(manager.house()).houseProfit{value: remaining }(GAME_ID);
} else {
TransferHelper.safeTransfer(token, player, totalToPayout);
IClaimManager(manager.claimManager()).creditToken(
player,
token,
GAME_ID,
totalToPayout
);
uint256 remaining = amountForHouse - totalToPayout;
address _house = getHouse(token);
TransferHelper.safeTransfer(token, _house, remaining);
ITokenHouse(_house).houseProfit(GAME_ID, remaining);
}
}
} else {
if (token == address(0)) {
IHouse(manager.house()).houseProfit{value: amountForHouse }(GAME_ID);
} else {
address _house = getHouse(token);
TransferHelper.safeTransfer(token, _house, amountForHouse);
ITokenHouse(_house).houseProfit(GAME_ID, amountForHouse);
}
}
}
function _registerGameId(address player, uint256 gameId) internal {
history.addData(player, GAME_ID, gameId);
usedGameIds.push(gameId);
isUsedGameId[gameId] = true;
}
function getHouse(address token) public view returns (address) {
if (token == address(0)) {
return manager.house();
}
return IHouseManager(IProjectTokensManager(manager.projectTokens()).houseManager()).houseFor(token);
}
function isValidGameId(uint256 gameId) public view returns (bool) {
return isUsedGameId[gameId] == false && gameId > 0;
}
function batchCallIsUsedGameId(uint256[] calldata gameIds) external view returns (bool[] memory isUsed) {
uint len = gameIds.length;
isUsed = new bool[](len);
for (uint i = 0; i < len;) {
isUsed[i] = isUsedGameId[gameIds[i]];
unchecked { ++i; }
}
}
function paginateUsedGameIDs(uint256 start, uint256 end) external view returns (uint256[] memory) {
uint count = 0;
uint256[] memory ids = new uint256[](end - start);
for (uint i = start; i < end;) {
ids[count] = usedGameIds[i];
unchecked { ++i; ++count; }
}
return ids;
}
function numUsedGameIDs() external view returns (uint256) {
return usedGameIds.length;
}
}
文件 3 的 16:IClaimManager.sol
pragma solidity 0.8.14;
interface IClaimManager {
function credit(
uint256 GAME_ID,
address user
) external payable;
function creditToken(
address user,
address token,
uint256 GAME_ID,
uint256 amount
) external;
}
文件 4 的 16:IERC20.sol
pragma solidity 0.8.14;
interface IERC20 {
function totalSupply() external view returns (uint256);
function symbol() external view returns(string memory);
function name() external view returns(string memory);
function balanceOf(address account) external view returns (uint256);
function decimals() external view returns (uint8);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 5 的 16:IFeeRecipient.sol
pragma solidity 0.8.14;
interface IFeeRecipient {
function takeFee(address token, uint256 amount, uint256 partner, address ref) external payable;
}
文件 6 的 16:IGame.sol
pragma solidity 0.8.14;
interface IGame {
function fulfillRandomWords(
uint256 requestId,
uint256[] calldata randomWords
) external;
function play(address user, address token, uint256 amount, bytes calldata gameData) external payable;
}
文件 7 的 16:IGovernanceManager.sol
pragma solidity 0.8.14;
interface IGovernanceManager {
function RNG() external view returns (address);
function owner() external view returns (address);
function chainlinkFeeReceiver() external view returns (address);
function chainlinkSubscriptionOwner() external view returns (address);
function referralManager() external view returns (address);
function projectTokens() external view returns (address);
function feeReceiver() external view returns (address);
function claimManager() external view returns (address);
function house() external view returns (address);
function isGame(address game) external view returns (bool);
function userInfoTracker() external view returns (address);
}
文件 8 的 16:IHistoryManager.sol
pragma solidity 0.8.14;
interface IHistoryManager {
function addData(address user, uint256 GAME_ID, uint256 gameId) external;
}
文件 9 的 16:IHouse.sol
pragma solidity 0.8.14;
interface IHouse {
function houseProfit(uint256 GAME_ID) external payable;
function payout(uint256 GAME_ID, address user, uint256 value) external;
function maxPayout() external view returns (uint256);
function randomRequested() external;
function randomRequestResolved() external;
}
文件 10 的 16:IHouseManager.sol
pragma solidity 0.8.14;
interface IHouseManager {
function isHouse(address house) external view returns (bool);
function houseFor(address token) external view returns (address);
function createHouse(address token) external returns (address house);
}
文件 11 的 16:IProjectTokensManager.sol
pragma solidity 0.8.14;
interface IProjectTokensManager {
function isValidPartner(uint256 partnerNonce) external view returns (bool);
function getFundReceiver(uint256 partner) external view returns (address);
function isListedToken(address token) external view returns (bool);
function getWrapper(address token) external view returns (address);
function getHouse(address token) external view returns (address);
function getViewer(address token) external view returns (address);
function isWrappedAsset(address wrapper) external view returns (bool);
function canPlayForOthers(address addr) external view returns (bool);
function wrappedAssetManager() external view returns (address);
function houseManager() external view returns (address);
}
文件 12 的 16:IRNG.sol
pragma solidity 0.8.14;
interface IRNG {
function requestRandom(uint32 gas, uint32 numResults) external returns (uint256 requestId);
}
文件 13 的 16:ITokenHouse.sol
pragma solidity 0.8.14;
interface ITokenHouse {
function __init__(address _token) external;
function deposit(address to, uint256 amount) external;
function houseProfit(uint256 GAME_ID, uint256 amount) external;
function payout(uint256 GAME_ID, address user, uint256 value) external;
function maxPayout() external view returns (uint256);
function randomRequested() external;
function randomRequestResolved() external;
}
文件 14 的 16:IUserInfoTracker.sol
pragma solidity 0.8.14;
interface IUserInfoTracker {
function wagered(address user, uint256 amount, uint256 GAME_ID, address token, uint256 partnerId) external;
function createViewer(address token) external returns (address viewer);
function listAllUsers() external view returns (address[] memory);
function totalWageredForPartner(uint256 partnerId) external view returns (uint256);
}
文件 15 的 16:PVPOwnable.sol
pragma solidity 0.8.14;
import "./IFeeRecipient.sol";
import "./IGovernanceManager.sol";
import "../ProjectTokens/IProjectTokensManager.sol";
import "../RNGTracker/IRNG.sol";
contract PVPOwnable {
IGovernanceManager public constant manager = IGovernanceManager(0x22164a57446aD5dE1DBE831784D8029773941678);
modifier onlyOwner() {
require(
msg.sender == manager.owner(),
'Only Owner'
);
_;
}
modifier onlyGame() {
require(
manager.isGame(msg.sender),
'UnAuthorized'
);
_;
}
modifier onlyRNG() {
require(
msg.sender == manager.RNG(),
'Only RNG Contract'
);
_;
}
modifier onlyValidToken(address token_) {
require(
IProjectTokensManager(manager.projectTokens()).isWrappedAsset(token_),
'Invalid Token'
);
_;
}
modifier validGameToken(address token_) {
require(
token_ == address(0) || IProjectTokensManager(manager.projectTokens()).isWrappedAsset(token_),
'Invalid Token'
);
_;
}
modifier validatePlayer(address player) {
if (player != msg.sender) {
require(
IProjectTokensManager(manager.projectTokens()).canPlayForOthers(msg.sender),
'UnAuthorized To Play For Others'
);
}
_;
}
}
文件 16 的 16:TransferHelper.sol
pragma solidity 0.8.14;
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}
{
"compilationTarget": {
"contracts/Slots/BoostSlots.sol": "Slots"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"uint256","name":"GAME_ID_","type":"uint256"},{"internalType":"address","name":"history_","type":"address"},{"internalType":"uint8[]","name":"reel1_","type":"uint8[]"},{"internalType":"uint8[]","name":"reel2_","type":"uint8[]"},{"internalType":"uint8[]","name":"reel3_","type":"uint8[]"},{"internalType":"uint256","name":"minBuyInGas_","type":"uint256"},{"internalType":"uint256","name":"buyInGasPerSpin_","type":"uint256"},{"internalType":"uint8[]","name":"boostOdds","type":"uint8[]"},{"internalType":"uint16[]","name":"payoutReductions","type":"uint16[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gameId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"randomWords","type":"uint256[]"}],"name":"FulfilRandomFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"gameId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"buyIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"payout","type":"uint256"}],"name":"GameEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"gameId","type":"uint256"}],"name":"GameStarted","type":"event"},{"anonymous":false,"inputs":[],"name":"OddsLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gameId","type":"uint256"}],"name":"RandomnessRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"SetPlatformFee","type":"event"},{"inputs":[],"name":"GAME_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SPINS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_SPINS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAYOUT_DENOM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"base_spin_gas","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"gameIds","type":"uint256[]"}],"name":"batchCallIsUsedGameId","outputs":[{"internalType":"bool[]","name":"isUsed","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"coins0","type":"uint8[]"},{"internalType":"uint8[]","name":"coins1","type":"uint8[]"},{"internalType":"uint8[]","name":"coins2","type":"uint8[]"},{"internalType":"uint256[]","name":"payoutMultiplier","type":"uint256[]"}],"name":"batchSetPayouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"boostFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"boostGasMultiplier","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"boostMultiplier","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"boosts","outputs":[{"internalType":"uint8","name":"boostOdds","type":"uint8"},{"internalType":"uint16","name":"payoutReduction","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"buyInGasPerSpin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enforceReel1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enforceReel2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enforceReel3","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256[]","name":"randomWords","type":"uint256[]"}],"name":"fulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"games","outputs":[{"internalType":"address","name":"player","type":"address"},{"internalType":"uint256","name":"betAmount","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountForHouse","type":"uint256"},{"internalType":"uint8","name":"numSpins","type":"uint8"},{"internalType":"uint8","name":"whichBoost","type":"uint8"},{"internalType":"uint256","name":"payout","type":"uint256"},{"internalType":"bool","name":"hasEnded","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gas_per_spin","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gameId","type":"uint256"}],"name":"getGameInfo","outputs":[{"internalType":"address","name":"player","type":"address"},{"internalType":"uint256","name":"betAmount","type":"uint256"},{"internalType":"uint8","name":"numSpins","type":"uint8"},{"internalType":"uint8[]","name":"num0","type":"uint8[]"},{"internalType":"uint8[]","name":"num1","type":"uint8[]"},{"internalType":"uint8[]","name":"num2","type":"uint8[]"},{"internalType":"uint256","name":"totalPayout","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"hasEnded","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getHouse","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"numSpins","type":"uint8"},{"internalType":"bool","name":"withBoost","type":"bool"}],"name":"getMinBuyInGas","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"random","type":"uint256"}],"name":"getMinIndexReel1","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"random","type":"uint256"}],"name":"getMinIndexReel2","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"random","type":"uint256"}],"name":"getMinIndexReel3","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"coin1","type":"uint8"},{"internalType":"uint8","name":"coin2","type":"uint8"},{"internalType":"uint8","name":"coin3","type":"uint8"}],"name":"getPayout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"history","outputs":[{"internalType":"contract IHistoryManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isUsedGameId","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gameId","type":"uint256"}],"name":"isValidGameId","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockOdds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"contract IGovernanceManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minBuyInGas","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numOptionsReel1","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numOptionsReel2","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numOptionsReel3","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"numToCoinReel1","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"numToCoinReel2","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"numToCoinReel3","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numUsedGameIDs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oddsLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optionsReel1","outputs":[{"internalType":"uint8[]","name":"","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optionsReel2","outputs":[{"internalType":"uint8[]","name":"","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optionsReel3","outputs":[{"internalType":"uint8[]","name":"","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"paginateUsedGameIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"uint8","name":"","type":"uint8"}],"name":"payout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"gameData","type":"bytes"}],"name":"play","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"buyIn","type":"uint256"},{"internalType":"uint8","name":"numSpins","type":"uint8"},{"internalType":"bool","name":"withBoost","type":"bool"}],"name":"quoteValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"reel1","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"reel2","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"reel3","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"resume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"boostId","type":"uint8"},{"internalType":"uint8","name":"boostOdds","type":"uint8"},{"internalType":"uint16","name":"payoutReduction","type":"uint16"}],"name":"setBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newBoost","type":"uint256"}],"name":"setBoostFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"newMultiplier","type":"uint8"}],"name":"setBoostGasMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMin","type":"uint256"},{"internalType":"uint256","name":"newGasPerSpin","type":"uint256"}],"name":"setBuyInGasInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMax","type":"uint256"}],"name":"setMaxSpins","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMin","type":"uint256"}],"name":"setMinSpins","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPlatform","type":"uint256"}],"name":"setPlatformFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"reel1_","type":"uint8[]"},{"internalType":"uint8[]","name":"reel2_","type":"uint8[]"},{"internalType":"uint8[]","name":"reel3_","type":"uint8[]"},{"internalType":"bool[]","name":"enforce","type":"bool[]"}],"name":"setReels","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"newBase","type":"uint32"},{"internalType":"uint32","name":"newGasPerSpin","type":"uint32"}],"name":"setVRFGasInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"usedGameIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]