Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
OptimizedBTB
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "./interfaces/IBlast.sol";
import "./interfaces/IBlastPoints.sol";
import "./base/BlastTheBalloonBase.sol";
import "./BTBStorage.sol";
import "./interfaces/IBTBConfig.sol";
import {OptimizedBTBLogicLib} from "contracts/libraries/OptimizedBTBLogicLib.sol";
contract OptimizedBTB is BlastTheBalloonBase, BTBStorage {
// ================================= INITIALIZE =================================
/**
* @notice Initialize Blast The Balloon Contract
* @dev Called only once
* @param _entropy Address of entropy
* @param _provider Address of entropy provider
*/
function initialize(
address _entropy,
address _provider,
address _ballTreasury,
address _pointsOperator,
address _BlastPointsAddress,
address _config
) external initializer {
entropy = IEntropy(_entropy);
provider = _provider;
config = IBTBConfig(_config);
ballTreasury = payable(_ballTreasury);
adminAddr = payable(_msgSender());
BlastPointsAddress = _BlastPointsAddress;
pointsOperator = _pointsOperator;
IBlastPoints(BlastPointsAddress).configurePointsOperator(_pointsOperator);
IBlast(0x4300000000000000000000000000000000000002).configureClaimableGas();
IBlast(0x4300000000000000000000000000000000000002).configureClaimableYield();
_initVariables_();
_initEmptyRound_();
__Base_init(_msgSender());
}
// ============================== PRIVATE FUNCTION ==============================
/**
* @dev Create first empty round
*/
function _initEmptyRound_() private {
Round storage roundInfo = rounds[nonce];
roundInfo.startTime = uint32(block.timestamp);
roundInfo.roundId = nonce;
roundInfo.totalWinningBlastMaster = maxBlastMasterWinners;
}
/**
* @dev Init Variables
*/
function _initVariables_() private {
// Fee to spin
spinFee = 4000000000000000;
// Fee to ante
anteFee = 4000000000000000;
// Number of blast winners
maxBlastMasterWinners = 10;
failSpinLimit = 1 minutes;
// Duration of a round
roundDuration = 420;
// Max time can increase
roundMaxTime = 420;
// prize portion
ballTreasuryPortion = 2000; // 2000 / 100_000 = 0.02 <=> 2%
majorJackpotNextRoundPortion = 0; // 0%
majorJackpotPortion = 83000; // 83%
minorJackpotPortion = 15000; // 15%
// jackpot chance to win prize
kingBlasterChancePercentage = 1500; // 1.5%
blastMasterChancePercentage = 15000; // 15.0%
minorJackpotChancePercentage = 100; // 0.1%
// reward percentage of each type when user win
kingBlasterPrizePercentage = 35000; // 35%
blastMasterPrizePercentage = 65000; // 65%
minorJackpotPrizePercentage = 70000; // 70%
// adjust percentage of minor jackpot
minorJackpotAdjustPercentage = 5000;
maxMinorJackpotProbability =
PERCENTAGE_DENOMINATOR -
(kingBlasterChancePercentage + blastMasterChancePercentage);
seededBack = 5;
numOfSeed = 5;
guaranteeSlot = 3;
multipleProbability = 1000; // 1%
}
// ============================== EXTERNAL UPDATE FUNCTION ==============================
/**
* @dev Update Pyth address
* @param _entropy new entropy
* @param _provider new provider
* @param _newTreasury new treasury
* @param _newAdmin new admin
*/
function updateSystemAddress(
address _entropy,
address _provider,
address _newTreasury,
address _newAdmin
) external onlyAdmin {
require(_entropy != address(0), BlastTheBalloonErrors.NOT_ALLOWED_ZERO_ADDRESS);
require(_provider != address(0), BlastTheBalloonErrors.NOT_ALLOWED_ZERO_ADDRESS);
require(_newTreasury != address(0), BlastTheBalloonErrors.NOT_ALLOWED_ZERO_ADDRESS);
require(_newAdmin != address(0), BlastTheBalloonErrors.NOT_ALLOWED_ZERO_ADDRESS);
entropy = IEntropy(_entropy);
provider = _provider;
ballTreasury = payable(_newTreasury);
adminAddr = payable(_newAdmin);
// emit UpdatePyth(_entropy, _provider);
}
/**
* @dev update number of seed
* @param _newSeed new duration
* @param _seedBack seed back
* @param _newGuaranteeSeat new guarantee seat
*/
function updateSeed(uint32 _newSeed, uint _seedBack, uint _newGuaranteeSeat) external onlyAdmin {
Round storage roundInfo = rounds[nonce];
require(
block.timestamp > roundInfo.startTime + roundInfo.duration || block.timestamp < roundInfo.startTime,
BlastTheBalloonErrors.ROUND_STILL_OPEN
);
require(_newSeed > 0, BlastTheBalloonErrors.CANT_BE_ZERO);
require(_newGuaranteeSeat > 0, BlastTheBalloonErrors.CANT_BE_ZERO);
numOfSeed = _newSeed;
seededBack = _seedBack;
guaranteeSlot = _newGuaranteeSeat;
// emit UpdateRoundDuration(_newDuration);
}
/**
* @dev update Round Config
* @param _newMaxBlastMasters new max blast masters
* @param _newSpinFee new spin fee
* @param _newDuration new duration
* @param _newMaxTime new max time
* @param _anteFee new ante fee
* @param _multipleProbability new multiple probability
*/
function updateRoundConfig(
uint _newMaxBlastMasters,
uint _newSpinFee,
uint _anteFee,
uint32 _newDuration,
uint32 _newMaxTime,
uint24 _multipleProbability
) external onlyAdmin {
Round storage roundInfo = rounds[nonce];
require(
block.timestamp > roundInfo.startTime + roundInfo.duration || block.timestamp < roundInfo.startTime,
BlastTheBalloonErrors.ROUND_STILL_OPEN
);
require(_newDuration <= _newMaxTime, BlastTheBalloonErrors.INVALID_TIME);
require(_newMaxBlastMasters > 0, BlastTheBalloonErrors.CANT_BE_ZERO);
spinFee = _newSpinFee;
anteFee = _anteFee;
roundDuration = _newDuration;
roundMaxTime = _newMaxTime;
maxBlastMasterWinners = _newMaxBlastMasters;
multipleProbability = _multipleProbability;
}
/**
* @dev update jackpot prize distribution
* @param portions Array of prize portion includes:
* 0. % goes to minor
* 1. % goes to major,
* 2. % goes to next round major,
* 3. % goes to treasury,
*/
function updatePrizePortion(uint24[4] calldata portions) external onlyAdmin {
uint total = portions[0] + portions[1] + portions[2] + portions[3];
require(total == PERCENTAGE_DENOMINATOR, BlastTheBalloonErrors.INVALID_PERCENTAGE);
minorJackpotPortion = portions[0];
majorJackpotPortion = portions[1];
majorJackpotNextRoundPortion = portions[2];
ballTreasuryPortion = portions[3];
// emit UpdatePrizePortion(portions);
}
/**
* @dev update jackpot chances
* @param jackpotChances Array of jackpot chance includes:
* 0. kingBlasterChancePercentage
* 1. blastMasterChancePercentage
* 2. minorJackpotChancePercentage
*/
function updateJackpotChance(uint24[3] calldata jackpotChances) external onlyAdmin {
require(
jackpotChances[0] + jackpotChances[1] + jackpotChances[2] <= PERCENTAGE_DENOMINATOR,
BlastTheBalloonErrors.INVALID_PERCENTAGE
);
kingBlasterChancePercentage = jackpotChances[0];
blastMasterChancePercentage = jackpotChances[1];
minorJackpotChancePercentage = jackpotChances[2];
maxMinorJackpotProbability =
PERCENTAGE_DENOMINATOR -
(kingBlasterChancePercentage + blastMasterChancePercentage);
// emit UpdateJackpotChance(jackpotChances);
}
/**
* @dev update reward percentage of jackpot
* @param rewardPercentages Array of jackpot chance includes:
* 0. kingBlasterPrizePercentage
* 1. blastMasterPrizePercentage
* 2. minorJackpotPrizePercentage
*/
function updateRewardPercentage(uint24[3] calldata rewardPercentages) external onlyAdmin {
uint total = rewardPercentages[0] + rewardPercentages[1];
require(total <= PERCENTAGE_DENOMINATOR, BlastTheBalloonErrors.INVALID_PERCENTAGE);
require(rewardPercentages[2] <= PERCENTAGE_DENOMINATOR, BlastTheBalloonErrors.INVALID_PERCENTAGE);
kingBlasterPrizePercentage = rewardPercentages[0];
blastMasterPrizePercentage = rewardPercentages[1];
minorJackpotPrizePercentage = rewardPercentages[2];
// emit UpdateRewardPercentage(rewardPercentages);
}
/**
* @dev update jackpot adjust percentage
* @param newAdjustPercentage new adjust percentage
*/
function updateJackpotAdjustPercentage(uint newAdjustPercentage) external onlyAdmin {
require(newAdjustPercentage <= PERCENTAGE_DENOMINATOR, BlastTheBalloonErrors.INVALID_PERCENTAGE);
minorJackpotAdjustPercentage = newAdjustPercentage;
// emit UpdateJackpotAdjustPercentage(newAdjustPercentage);
}
/**
* @dev update spin fail time limit
* @param _newDuration new duration
*/
function updateFailSpinLimit(uint32 _newDuration) external onlyAdmin {
require(_newDuration > 5 seconds, BlastTheBalloonErrors.INVALID_FAIL_SPIN_LIMIT);
failSpinLimit = _newDuration;
}
// ============================== EXTERNAL FUNCTION ==============================
// Function to receive native token msg.data is empty
receive() external payable {}
// Fallback function is called when msg.data is not empty
fallback() external payable {}
/**
* @dev Create a new round and only admin can do it
*/
function createNewRound(uint _startRound) external payable onlyAdmin {
Round storage previousRoundInfo = rounds[nonce];
OptimizedBTBLogicLib.newRoundCondition(_startRound, roundDuration, previousRoundInfo);
(uint previousPrizeLeft, uint seedPrize) = OptimizedBTBLogicLib.getRemainingPrize(
nonce,
numOfSeed,
spinFee,
majorJackpotPortion,
previousRoundInfo,
kingBlasters
);
// update number of spin using seed, back to 0 if someone win jackpot
seedCount = seedPrize != 0 ? 0 : seedCount;
nonce += 1;
guaranteeSlotCount = 0;
Round storage roundInfo = rounds[nonce];
IBTBConfig.Point memory levelPoints = config.getLevelPoint();
IBTBConfig.TimeImpact memory timeImpacts = config.getTimeImpact();
uint[40] memory params = [
nonce,
roundDuration,
roundMaxTime,
maxBlastMasterWinners,
timeImpacts.firstGameTimerChancePercentage,
timeImpacts.secondGameTimerChancePercentage,
timeImpacts.thirdGameTimerChancePercentage,
timeImpacts.firstGameTimerImpact,
timeImpacts.secondGameTimerImpact,
timeImpacts.thirdGameTimerImpact,
kingBlasterChancePercentage,
blastMasterChancePercentage,
minorJackpotChancePercentage,
kingBlasterPrizePercentage,
blastMasterPrizePercentage,
minorJackpotPrizePercentage,
minorJackpotAdjustPercentage,
maxMinorJackpotProbability,
levelPoints.firstLevelPointP,
levelPoints.secondLevelPointP,
levelPoints.thirdLevelPointP,
levelPoints.fourthLevelPointP,
levelPoints.fifthLevelPointP,
levelPoints.sixthLevelPointP,
levelPoints.firstLevelPointA,
levelPoints.secondLevelPointA,
levelPoints.thirdLevelPointA,
levelPoints.fourthLevelPointA,
levelPoints.fifthLevelPointA,
levelPoints.sixthLevelPointA,
levelPoints.firstBonusTime,
levelPoints.secondBonusTime,
levelPoints.thirdBonusTime,
levelPoints.firstBonusMultiplier,
levelPoints.secondBonusMultiplier,
levelPoints.thirdBonusMultiplier,
ballTreasuryPortion,
majorJackpotNextRoundPortion,
majorJackpotPortion,
minorJackpotPortion
];
OptimizedBTBLogicLib.updateRoundInfo(
roundInfo,
previousRoundInfo,
previousPrizeLeft,
seedPrize,
uint32(_startRound),
params
);
emit CreateNewRound(_msgSender(), nonce, roundInfo.startTime, roundInfo.duration);
}
function addAnte(address player) external payable nonReentrant {
OptimizedBTBLogicLib.addAnte(nonce, anteFee, player, ballTreasury, rounds, ante);
}
/**
* @notice Request to get a random number. The caller should generate a random number prior to calling this method, then
* submit the hash of that number as userCommitment.
* @param userRandomNumber user generate random number to get random number from pyth
*/
function buySpin(address player, bytes32 userRandomNumber) external payable nonReentrant {
Round storage roundInfo = rounds[nonce];
Spin storage spinInfo = lastSpins[nonce][player];
_refundSpin(player);
OptimizedBTBLogicLib.buySpinCondition(roundInfo, spinInfo);
_calculateLastPrize(player);
require(ante[nonce][player], BlastTheBalloonErrors.INVALID_ANTE);
uint64 sequenceNumber = OptimizedBTBLogicLib.buySpin(
nonce,
msg.value,
spinFee,
player,
provider,
spinInfo,
entropy,
requestedRandomNumber,
userRandomNumber
);
emit BuySpin(player, nonce, sequenceNumber);
}
/**
* @notice Execute Spin
* @param sequenceNumber Sequence Number
* @param _providerAddress Created Random by Pyth. This can be retrieved from them in a provider-dependent manner.
* @param randomNumber Generated random number by Pyth. Used to calculate prize
*/
function entropyCallback(
uint64 sequenceNumber,
// If your app uses multiple providers, you can use this argument
// to distinguish which one is calling the app back. This app only
// uses one provider so this argument is not used.
address _providerAddress,
bytes32 randomNumber
) internal override {
require(_msgSender() == address(entropy), BlastTheBalloonErrors.CALLER_NOT_ENTROPY);
Round storage roundInfo = rounds[nonce];
uint guaranteedSeatBitMask = guaranteedSeatBitMaskByRound[nonce];
// get player address
address playerAddress = requestedRandomNumber[sequenceNumber];
Spin storage spinInfo = lastSpins[nonce][playerAddress];
OptimizedBTBLogicLib.executeSpinCondition(roundInfo, spinInfo, failSpinLimit);
_updatePrizePool(roundInfo, spinInfo);
uint userRandom = uint(spinInfo.userCommitment);
// Calculate exact jackpot percentage
(
uint jackpotWinningPosition,
uint24 minorProbability,
uint24 kingProbability,
uint24 blastProbability
) = _calculateProbabilityOfWinning(uint(randomNumber));
// Calculate time impact for current round duration
string memory gameTimeImpact = _gameTimeImpact(uint(randomNumber), userRandom);
MajorJackWinnerReturn memory majorWinnerReturn = _majorJackpotWinner(
jackpotWinningPosition,
kingProbability,
blastProbability,
uint(randomNumber),
guaranteedSeatBitMask,
playerAddress
);
{
uint prizeAmount = majorWinnerReturn.prize;
WinType jackpotType = majorWinnerReturn.wintype;
// Choose minor winner if none then choose major
if (jackpotType == WinType.NONE) {
(prizeAmount, jackpotType) = _minorJackpotWinner(
jackpotWinningPosition,
minorProbability,
playerAddress
);
}
// set executed status
spinInfo.status = SpinStatus.EXECUTED;
guaranteedSeatBitMaskByRound[nonce] = majorWinnerReturn.guaranteedSeatBitMask;
// Emit execute Spin event
// emit ExecuteSpin(playerAddress, uint256(randomNumber), nonce, prizeAmount, gameTimeImpact, jackpotType);
emitEvent(playerAddress, uint256(randomNumber), nonce, prizeAmount, gameTimeImpact, jackpotType);
}
}
function emitEvent(
address playerAddress,
uint randomUmber,
uint nonce,
uint prizeAmount,
string memory gameTimeImpact,
WinType jackpotType
) internal {
emit ExecuteSpin(playerAddress, randomUmber, nonce, prizeAmount, gameTimeImpact, jackpotType);
}
/**
* @dev Withdraw winning prize of the last round
*/
function claimPrize() external nonReentrant {
Round storage roundInfo = rounds[nonce];
_refundSpin(_msgSender());
_calculateLastPrize(_msgSender());
uint pendingAmount;
if (block.timestamp > roundInfo.startTime + roundInfo.duration && !pendingClaimed[nonce][_msgSender()]) {
pendingAmount = getCurrentClaimableAmounts(_msgSender());
pendingClaimed[nonce][_msgSender()] = true;
}
uint allPrize = claimableAmounts[_msgSender()] + pendingAmount;
require(address(this).balance >= allPrize, BlastTheBalloonErrors.NOT_ENOUGH_TOKEN);
claimableAmounts[_msgSender()] = 0;
(bool success, ) = payable(_msgSender()).call{value: allPrize}("");
require(success, "Failed to send Ether to blast winner");
emit ClaimPrize(_msgSender(), allPrize);
}
/**
* @dev Emergency Withdraw
*/
function emergencyWithdraw(uint _amount) external nonReentrant onlyAdmin {
require(emergencyStatus, BlastTheBalloonErrors.NOT_EMERGENCY);
require(address(this).balance >= _amount, BlastTheBalloonErrors.INVALID_AMOUNT);
(bool success, ) = payable(_msgSender()).call{value: _amount}("");
require(success, "Failed to send Ether to blast winner");
}
/**
* @dev Set Emergency status
*/
function setEmergencyStatus(bool _status) external onlyAdmin {
emergencyStatus = _status;
}
/**
* @dev Refund fail spin
*/
function refundSpin() external nonReentrant {
_refundSpin(_msgSender());
require(refundClaimable[_msgSender()] > 0, BlastTheBalloonErrors.INVALID_AMOUNT);
uint refundAmount = refundClaimable[_msgSender()];
refundClaimable[_msgSender()] = 0;
require(address(this).balance >= refundAmount, BlastTheBalloonErrors.INVALID_AMOUNT);
(bool success, ) = payable(_msgSender()).call{value: refundAmount}("");
require(success, "Failed to send Ether to blast winner");
}
/**
* @dev Claim Contract Gas
*/
function claimAllGas(address _recipient) external onlyAdmin {
IBlast(0x4300000000000000000000000000000000000002).claimAllGas(address(this), _recipient);
}
/**
* @dev Claim Contract Max Gas
*/
function claimMaxGas(address _recipient) external onlyAdmin {
IBlast(0x4300000000000000000000000000000000000002).claimMaxGas(address(this), _recipient);
}
/**
* @dev Claim Contract Yield
*/
function claimAllYield(address _recipient) external onlyAdmin {
IBlast(0x4300000000000000000000000000000000000002).claimAllYield(address(this), _recipient);
}
// ============================== INTERNAL FUNCTION ==============================
/**
* @dev Refund last fail spin
*/
function _refundSpin(address player) internal {
OptimizedBTBLogicLib.refundSpin(players, lastSpins, refundClaimable, failSpinLimit, player);
}
/**
* @dev calculates the user's previous awards
*/
function _calculateLastPrize(address player) internal {
Player storage playerInfo = players[player];
if (playerInfo.lastPlayRound >= nonce) {
return;
}
if (!pendingClaimed[playerInfo.lastPlayRound][player]) {
claimableAmounts[player] = getActualClaimableAmounts(player);
pendingClaimed[playerInfo.lastPlayRound][player] = true;
}
playerInfo.lastPlayRound = nonce;
}
/**
* @dev update Prize Information of the round
*/
function _updatePrizePool(Round storage roundInfo, Spin storage spinInfo) internal {
uint majorPortion = roundInfo.prizePortion.majorJackpotPortion;
// send eth to treasury
// uint ballTreasuryAmount = (spinInfo.spinFee * ballTreasuryPortion) / PERCENTAGE_DENOMINATOR;
uint ballTreasuryAmount = (spinInfo.spinFee * roundInfo.prizePortion.ballTreasuryPortion) / PERCENTAGE_DENOMINATOR;
(bool success, ) = ballTreasury.call{value: ballTreasuryAmount}("");
require(success, "Failed to send Ether to treasury");
if (seedCount < seededBack) {
seedCount += 1;
// send seed eth to treasury
uint seedRefund = (spinInfo.spinFee * majorPortion) / PERCENTAGE_DENOMINATOR;
(success, ) = adminAddr.call{value: seedRefund}("");
require(success, "Failed to send Seed Ether to prize pool wallet");
majorPortion = 0;
}
OptimizedBTBLogicLib.updatePrizePool(
roundInfo,
spinInfo,
majorPortion,
roundInfo.prizePortion.minorJackpotPortion,
roundInfo.prizePortion.majorJackpotNextRoundPortion
);
}
/**
* @dev Calculate timing affects the game
* @param randomNumber random number
*/
function _gameTimeImpact(uint randomNumber, uint userRandom) internal returns (string memory) {
Round storage roundInfo = rounds[nonce];
return OptimizedBTBLogicLib.gameTimeImpact(randomNumber, userRandom, roundInfo);
}
/**
* @dev Calculate jackpot probability
*/
function _calculateProbabilityOfWinning(uint randomNumber) internal view returns (uint, uint24, uint24, uint24) {
Round storage roundInfo = rounds[nonce];
/// Calculate probability of king and blast
uint kingBlasterWinningPercentage = roundInfo.jackpot.kingBlasterChancePercentage;
uint blastMasterWinningPercentage = kingBlasterWinningPercentage +
roundInfo.jackpot.blastMasterChancePercentage;
// Calculate winning probability for minor
uint currentProbability = (roundInfo.jackpot.minorJackpotChancePercentage +
((minorJackpotEntryCount * PERCENTAGE_DENOMINATOR) / roundInfo.jackpot.minorJackpotAdjustPercentage));
uint minorJackpotWinningPercentage = currentProbability < roundInfo.jackpot.maxMinorJackpotProbability
? currentProbability
: roundInfo.jackpot.maxMinorJackpotProbability;
minorJackpotWinningPercentage += blastMasterWinningPercentage;
/// Calculate winning position to choose winner
uint winningPosition = randomNumber % PERCENTAGE_DENOMINATOR;
return (
winningPosition,
uint24(minorJackpotWinningPercentage),
uint24(kingBlasterWinningPercentage),
uint24(blastMasterWinningPercentage)
);
}
/**
* @dev Check to see if won a major, king or blast
* @param winningPosition winning probability to check if won king or blast or nothing
* @param kingProbability percentage to win king
* @param blastProbability percentage to win blast
* @param randomNumber used to calculate position if won blast
*/
function _majorJackpotWinner(
uint winningPosition,
uint kingProbability,
uint blastProbability,
uint randomNumber,
uint currentGuaranteedSeatBitMask,
address player
) internal returns (MajorJackWinnerReturn memory) {
uint[7] memory positionUints = [
nonce,
randomNumber,
guaranteeSlot,
guaranteeSlotCount,
winningPosition,
kingProbability,
blastProbability
];
(uint blastMasterWinningPosition, uint guaranteedSeatBitMask) = OptimizedBTBLogicLib.calculateWinningPosition(
positionUints,
player,
rounds[nonce],
currentGuaranteedSeatBitMask,
guaranteedSeat
);
uint[6] memory uints = [
nonce,
winningPosition,
kingProbability,
blastProbability,
blastMasterWinningPosition,
multipleProbability
];
uint prize;
WinType winType;
uint winPos;
(prize, winType, winPos) = OptimizedBTBLogicLib.kingWinner(uints, player, rounds, kingBlasters);
if (winType == WinType.KING_BLASTER) {
minorJackpotEntryCount += 1;
emit MajorWinner(player, nonce, true, 0);
// return (prize, winType, guaranteedSeatBitMask);
return MajorJackWinnerReturn(prize, winType, guaranteedSeatBitMask);
}
(prize, winType, winPos) = OptimizedBTBLogicLib.blastWinner(
uints,
player,
rounds,
blastMasters,
blastMasterPositions,
numberOfBlasts
);
if (winType == WinType.BLAST_MASTER) {
minorJackpotEntryCount += 1;
guaranteeSlotCount = guaranteeSlotCount < guaranteeSlot ? guaranteeSlotCount + 1 : guaranteeSlotCount;
emit MajorWinner(player, nonce, false, winPos);
}
return MajorJackWinnerReturn(prize, winType, guaranteedSeatBitMask);
}
/**
* @dev Check to see if won a minor jackpot
* @param winningPosition winning position to check if won or not
* @param minorProbability minor winning probability
*/
function _minorJackpotWinner(
uint winningPosition,
uint24 minorProbability,
address player
) internal returns (uint, WinType) {
if (winningPosition < minorProbability) {
uint entries;
uint minorPrize;
(entries, minorPrize) = OptimizedBTBLogicLib.minorWinner(
nonce,
minorJackpotEntryCount,
player,
rounds,
claimableAmounts
);
minorJackpotEntryCount = 0;
emit MinorWinner(player, nonce, minorPrize, entries);
return (minorPrize, WinType.MINOR_JACKPOT);
}
minorJackpotEntryCount += 1;
return (0, WinType.NONE);
}
// ============================== VIEW FUNCTION ==============================
// This method is required by the IEntropyConsumer interface
function getEntropy() internal view override returns (address) {
return address(entropy);
}
// Get the fee to spin . See the comment above about fees.
function getFee() public view returns (uint256 fee) {
fee = entropy.getFee(provider);
}
// This method is used to get current claimable amount
function getCurrentClaimableAmounts(address player) public view returns (uint) {
Round storage roundInfo = rounds[nonce];
uint totalClaimableAmount;
if (pendingClaimed[nonce][player]) {
return totalClaimableAmount;
}
uint totalBlasts = numberOfBlasts[nonce][player];
uint kingPrize = ((roundInfo.jackpot.kingBlasterPrizePercentage * roundInfo.majorJackpot) /
PERCENTAGE_DENOMINATOR);
uint blastPrize = roundInfo.totalWinningBlastMaster == 0
? 0
: (roundInfo.majorJackpot - kingPrize) / roundInfo.totalWinningBlastMaster;
if (kingBlasters[nonce] == player) {
if (roundInfo.totalWinningBlastMaster == 0) {
totalClaimableAmount += (roundInfo.majorJackpot - kingPrize);
}
totalClaimableAmount += kingPrize;
}
if (totalBlasts > 0) {
if (kingBlasters[nonce] == address(0)) {
totalClaimableAmount += ((kingPrize / roundInfo.totalWinningBlastMaster) * totalBlasts);
}
totalClaimableAmount += blastPrize * totalBlasts;
}
return totalClaimableAmount;
}
// This method is used to get actual claimable amount
function getActualClaimableAmounts(address player) public view returns (uint) {
Player storage playerInfo = players[player];
Round storage roundInfo = rounds[playerInfo.lastPlayRound];
if (playerInfo.lastPlayRound >= nonce || pendingClaimed[playerInfo.lastPlayRound][player]) {
return claimableAmounts[player];
}
uint totalClaimableAmount = claimableAmounts[player];
uint totalBlasts = numberOfBlasts[playerInfo.lastPlayRound][player];
uint kingPrize = ((roundInfo.jackpot.kingBlasterPrizePercentage * roundInfo.majorJackpot) /
PERCENTAGE_DENOMINATOR);
uint blastPrize = roundInfo.totalWinningBlastMaster == 0
? 0
: (roundInfo.majorJackpot - kingPrize) / roundInfo.totalWinningBlastMaster;
if (kingBlasters[playerInfo.lastPlayRound] == player) {
if (roundInfo.totalWinningBlastMaster == 0) {
totalClaimableAmount += (roundInfo.majorJackpot - kingPrize);
}
totalClaimableAmount += kingPrize;
}
if (totalBlasts > 0) {
if (kingBlasters[playerInfo.lastPlayRound] == address(0)) {
totalClaimableAmount += ((kingPrize / roundInfo.totalWinningBlastMaster) * totalBlasts);
}
totalClaimableAmount += blastPrize * totalBlasts;
}
return totalClaimableAmount;
}
function getClaimableAmount(address player) public view returns (uint) {
Round storage roundInfo = rounds[nonce];
uint currentAmount;
uint previousAmount = getActualClaimableAmounts(player);
if (block.timestamp > roundInfo.startTime + roundInfo.duration) {
currentAmount = getCurrentClaimableAmounts(player);
}
return previousAmount + currentAmount;
}
// This method is used to get current probability of minor
function getMinorProbability(uint _nonce) public view returns (uint) {
Round storage roundInfo = rounds[_nonce];
if (_nonce > nonce) {
return 0;
}
// Calculate winning probability for minor
uint currentProbability = (roundInfo.jackpot.minorJackpotChancePercentage +
((minorJackpotEntryCount * PERCENTAGE_DENOMINATOR) / roundInfo.jackpot.minorJackpotAdjustPercentage));
uint minorJackpotWinningPercentage = currentProbability < roundInfo.jackpot.maxMinorJackpotProbability
? currentProbability
: roundInfo.jackpot.maxMinorJackpotProbability;
return minorJackpotWinningPercentage;
}
// This method is used to get blast winners
function getBlastWinners(uint _nonce) public view returns (address[] memory) {
Round storage roundInfo = rounds[_nonce];
if (_nonce > nonce) {
return new address[](1);
}
address[] memory blastWinners = new address[](roundInfo.maxBlastMasterWinners);
if (roundInfo.totalWinningBlastMaster == 0) {
return blastWinners;
}
for (uint i = 0; i < roundInfo.maxBlastMasterWinners; i++) {
blastWinners[i] = blastMasters[_nonce][i];
}
return blastWinners;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
StringsUpgradeable.toHexString(account),
" is missing role ",
StringsUpgradeable.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
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;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMathUpgradeable {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
import "./math/SignedMathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = MathUpgradeable.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, MathUpgradeable.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./EntropyStructs.sol";
interface EntropyEvents {
event Registered(EntropyStructs.ProviderInfo provider);
event Requested(EntropyStructs.Request request);
event RequestedWithCallback(
address indexed provider,
address indexed requestor,
uint64 indexed sequenceNumber,
bytes32 userRandomNumber,
EntropyStructs.Request request
);
event Revealed(
EntropyStructs.Request request,
bytes32 userRevelation,
bytes32 providerRevelation,
bytes32 blockHash,
bytes32 randomNumber
);
event RevealedWithCallback(
EntropyStructs.Request request,
bytes32 userRandomNumber,
bytes32 providerRevelation,
bytes32 randomNumber
);
event ProviderFeeUpdated(address provider, uint128 oldFee, uint128 newFee);
event ProviderUriUpdated(address provider, bytes oldUri, bytes newUri);
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
contract EntropyStructs {
struct ProviderInfo {
uint128 feeInWei;
uint128 accruedFeesInWei;
// The commitment that the provider posted to the blockchain, and the sequence number
// where they committed to this. This value is not advanced after the provider commits,
// and instead is stored to help providers track where they are in the hash chain.
bytes32 originalCommitment;
uint64 originalCommitmentSequenceNumber;
// Metadata for the current commitment. Providers may optionally use this field to to help
// manage rotations (i.e., to pick the sequence number from the correct hash chain).
bytes commitmentMetadata;
// Optional URI where clients can retrieve revelations for the provider.
// Client SDKs can use this field to automatically determine how to retrieve random values for each provider.
// TODO: specify the API that must be implemented at this URI
bytes uri;
// The first sequence number that is *not* included in the current commitment (i.e., an exclusive end index).
// The contract maintains the invariant that sequenceNumber <= endSequenceNumber.
// If sequenceNumber == endSequenceNumber, the provider must rotate their commitment to add additional random values.
uint64 endSequenceNumber;
// The sequence number that will be assigned to the next inbound user request.
uint64 sequenceNumber;
// The current commitment represents an index/value in the provider's hash chain.
// These values are used to verify requests for future sequence numbers. Note that
// currentCommitmentSequenceNumber < sequenceNumber.
//
// The currentCommitment advances forward through the provider's hash chain as values
// are revealed on-chain.
bytes32 currentCommitment;
uint64 currentCommitmentSequenceNumber;
}
struct Request {
// Storage slot 1 //
address provider;
uint64 sequenceNumber;
// The number of hashes required to verify the provider revelation.
uint32 numHashes;
// Storage slot 2 //
// The commitment is keccak256(userCommitment, providerCommitment). Storing the hash instead of both saves 20k gas by
// eliminating 1 store.
bytes32 commitment;
// Storage slot 3 //
// The number of the block where this request was created.
// Note that we're using a uint64 such that we have an additional space for an address and other fields in
// this storage slot. Although block.number returns a uint256, 64 bits should be plenty to index all of the
// blocks ever generated.
uint64 blockNumber;
// The address that requested this random number.
address requester;
// If true, incorporate the blockhash of blockNumber into the generated random value.
bool useBlockhash;
// If true, the requester will be called back with the generated random value.
bool isRequestWithCallback;
// There are 2 remaining bytes of free space in this slot.
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./EntropyEvents.sol";
interface IEntropy is EntropyEvents {
// Register msg.sender as a randomness provider. The arguments are the provider's configuration parameters
// and initial commitment. Re-registering the same provider rotates the provider's commitment (and updates
// the feeInWei).
//
// chainLength is the number of values in the hash chain *including* the commitment, that is, chainLength >= 1.
function register(
uint128 feeInWei,
bytes32 commitment,
bytes calldata commitmentMetadata,
uint64 chainLength,
bytes calldata uri
) external;
// Withdraw a portion of the accumulated fees for the provider msg.sender.
// Calling this function will transfer `amount` wei to the caller (provided that they have accrued a sufficient
// balance of fees in the contract).
function withdraw(uint128 amount) external;
// As a user, request a random number from `provider`. Prior to calling this method, the user should
// generate a random number x and keep it secret. The user should then compute hash(x) and pass that
// as the userCommitment argument. (You may call the constructUserCommitment method to compute the hash.)
//
// This method returns a sequence number. The user should pass this sequence number to
// their chosen provider (the exact method for doing so will depend on the provider) to retrieve the provider's
// number. The user should then call fulfillRequest to construct the final random number.
//
// This method will revert unless the caller provides a sufficient fee (at least getFee(provider)) as msg.value.
// Note that excess value is *not* refunded to the caller.
function request(
address provider,
bytes32 userCommitment,
bool useBlockHash
) external payable returns (uint64 assignedSequenceNumber);
// Request a random number. The method expects the provider address and a secret random number
// in the arguments. It returns a sequence number.
//
// The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
// The `entropyCallback` method on that interface will receive a callback with the generated random number.
//
// This method will revert unless the caller provides a sufficient fee (at least getFee(provider)) as msg.value.
// Note that excess value is *not* refunded to the caller.
function requestWithCallback(
address provider,
bytes32 userRandomNumber
) external payable returns (uint64 assignedSequenceNumber);
// Fulfill a request for a random number. This method validates the provided userRandomness and provider's proof
// against the corresponding commitments in the in-flight request. If both values are validated, this function returns
// the corresponding random number.
//
// Note that this function can only be called once per in-flight request. Calling this function deletes the stored
// request information (so that the contract doesn't use a linear amount of storage in the number of requests).
// If you need to use the returned random number more than once, you are responsible for storing it.
function reveal(
address provider,
uint64 sequenceNumber,
bytes32 userRevelation,
bytes32 providerRevelation
) external returns (bytes32 randomNumber);
// Fulfill a request for a random number. This method validates the provided userRandomness
// and provider's revelation against the corresponding commitment in the in-flight request. If both values are validated
// and the requestor address is a contract address, this function calls the requester's entropyCallback method with the
// sequence number, provider address and the random number as arguments. Else if the requestor is an EOA, it won't call it.
//
// Note that this function can only be called once per in-flight request. Calling this function deletes the stored
// request information (so that the contract doesn't use a linear amount of storage in the number of requests).
// If you need to use the returned random number more than once, you are responsible for storing it.
//
// Anyone can call this method to fulfill a request, but the callback will only be made to the original requester.
function revealWithCallback(
address provider,
uint64 sequenceNumber,
bytes32 userRandomNumber,
bytes32 providerRevelation
) external;
function getProviderInfo(
address provider
) external view returns (EntropyStructs.ProviderInfo memory info);
function getDefaultProvider() external view returns (address provider);
function getRequest(
address provider,
uint64 sequenceNumber
) external view returns (EntropyStructs.Request memory req);
function getFee(address provider) external view returns (uint128 feeAmount);
function getAccruedPythFees()
external
view
returns (uint128 accruedPythFeesInWei);
function setProviderFee(uint128 newFeeInWei) external;
function setProviderUri(bytes calldata newUri) external;
function constructUserCommitment(
bytes32 userRandomness
) external pure returns (bytes32 userCommitment);
function combineRandomValues(
bytes32 userRandomness,
bytes32 providerRandomness,
bytes32 blockHash
) external pure returns (bytes32 combinedRandomness);
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
abstract contract IEntropyConsumer {
// This method is called by Entropy to provide the random number to the consumer.
// It asserts that the msg.sender is the Entropy contract. It is not meant to be
// override by the consumer.
function _entropyCallback(
uint64 sequence,
address provider,
bytes32 randomNumber
) external {
address entropy = getEntropy();
require(entropy != address(0), "Entropy address not set");
require(msg.sender == entropy, "Only Entropy can call this function");
entropyCallback(sequence, provider, randomNumber);
}
// getEntropy returns Entropy contract address. The method is being used to check that the
// callback is indeed from Entropy contract. The consumer is expected to implement this method.
// Entropy address can be found here - https://docs.pyth.network/entropy/contract-addresses
function getEntropy() internal view virtual returns (address);
// This method is expected to be implemented by the consumer to handle the random number.
// It will be called by _entropyCallback after _entropyCallback ensures that the call is
// indeed from Entropy contract.
function entropyCallback(
uint64 sequence,
address provider,
bytes32 randomNumber
) internal virtual;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {BlastTheBalloonErrors} from "../libraries/BlastTheBalloonErrors.sol";
/**
* @title Blast The Balloon contract
* @notice This is our Base contract that most other contracts inherit from. It includes many standard
* useful abilities like upgradeability, pausability, access control, and re-entrancy guards.
* @author Blast The Balloon
*/
contract BlastTheBalloonBase is AccessControlUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable {
bytes32 public constant OWNER_ROLE = keccak256("OWNER_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
// Pre-reserving a few slots in the base contract in case we need to add things in the future.
// This does not actually take up gas cost or storage cost, but it does reserve the storage slots.
// See OpenZeppelin's use of this pattern here:
// https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/master/contracts/GSN/Context.sol#L37
uint256[50] private __gap1;
uint256[50] private __gap2;
uint256[50] private __gap3;
uint256[50] private __gap4;
constructor() {
_disableInitializers();
}
// solhint-disable-next-line func-name-mixedcase
function __Base_init(address owner) public onlyInitializing {
require(owner != address(0), "Owner cannot be the zero address");
__AccessControl_init();
__Pausable_init();
__ReentrancyGuard_init();
_setupRole(OWNER_ROLE, owner);
_setupRole(PAUSER_ROLE, owner);
_setRoleAdmin(PAUSER_ROLE, OWNER_ROLE);
_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);
}
function isAdmin() public view returns (bool) {
return hasRole(OWNER_ROLE, _msgSender());
}
function isPauser() public view returns (bool) {
return hasRole(PAUSER_ROLE, _msgSender());
}
modifier onlyAdmin() {
require(isAdmin(), "Must have admin role to perform this action");
_;
}
modifier onlyPauser() {
require(isPauser(), "Must have pauser role to perform this action");
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@pythnetwork/entropy-sdk-solidity/IEntropy.sol";
import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";
import "./interfaces/IBTBConfig.sol";
abstract contract BTBStorage is IEntropyConsumer {
enum WinType {
NONE,
MINOR_JACKPOT,
KING_BLASTER,
BLAST_MASTER
}
enum SpinStatus {
NONE,
WAITING_FOR_EXECUTE,
EXECUTED
}
/// @dev Spin Information
struct Spin {
uint roundId;
uint currentSpinId;
uint lastPlayTime;
uint spinFee; // the spin fee of user
bytes32 userCommitment; /// user commitment Of a Spin
uint64 sequenceNumber; /// sequence number Of a Spin
SpinStatus status; /// status of spin
}
struct TimeImpact {
uint24 firstGameTimerChancePercentage;
uint24 secondGameTimerChancePercentage;
uint24 thirdGameTimerChancePercentage;
uint32 firstGameTimerImpact;
uint32 secondGameTimerImpact;
uint32 thirdGameTimerImpact;
}
struct Jackpot {
uint24 kingBlasterChancePercentage;
uint24 blastMasterChancePercentage;
uint24 minorJackpotChancePercentage;
uint24 kingBlasterPrizePercentage;
uint24 blastMasterPrizePercentage;
uint24 minorJackpotPrizePercentage;
uint minorJackpotAdjustPercentage;
uint maxMinorJackpotProbability;
}
struct PrizePortion {
uint ballTreasuryPortion;
uint majorJackpotNextRoundPortion;
uint majorJackpotPortion;
uint minorJackpotPortion;
}
struct Point {
uint firstLevelPointP;
uint secondLevelPointP;
uint thirdLevelPointP;
uint fourthLevelPointP;
uint fifthLevelPointP;
uint sixthLevelPointP;
uint firstLevelPointA;
uint secondLevelPointA;
uint thirdLevelPointA;
uint fourthLevelPointA;
uint fifthLevelPointA;
uint sixthLevelPointA;
uint32 firstBonusTime;
uint32 secondBonusTime;
uint32 thirdBonusTime;
uint firstBonusMultiplier;
uint secondBonusMultiplier;
uint thirdBonusMultiplier;
}
/// @dev Round Information
struct Round {
uint roundId;
uint32 startTime;
uint32 duration;
uint32 maxTime;
uint majorJackpotNextRound; // total amount of eth for next round major jackpot
uint majorJackpot; // total amount of eth for major jackpot
uint minorJackpot; // total amount of eth for minor jackpot
uint totalSpins; // total spin used in a round
uint totalWinningBlastMaster; // total winning blast master
uint maxBlastMasterWinners; // total winning blast master
TimeImpact timeImpact;
Jackpot jackpot;
PrizePortion prizePortion;
Point point;
}
struct MajorJackWinnerReturn {
uint prize;
WinType wintype;
uint guaranteedSeatBitMask;
}
/// @dev Players Information
struct Player {
uint lastPlayRound;
}
// address public constant BLAST = 0x4300000000000000000000000000000000000002;
/// @dev Percentage denominator
uint32 public constant PERCENTAGE_DENOMINATOR = 100000;
uint32 public failSpinLimit;
/// @dev Emergency status
bool public emergencyStatus;
/// @dev Treasury Address take 1% of Spin fee
address payable public ballTreasury;
/// mainnet: 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800
/// testnet: 0x2fc95838c71e76ec69ff817983BFf17c710F34E0
/// @dev BlastPoints contract address. Use this address to calculate points and then distribute to users
address public BlastPointsAddress;
/// @dev Points Operator address
address public pointsOperator;
/// @notice Get HelixConfig contract's address
IBTBConfig public config;
/// @dev the nonce number, used to Identify round, this variable will +1 each new round
uint public nonce;
/// @dev the price of a spin
uint public spinFee;
/// @dev the percentage chance of winning king blaster
uint24 public kingBlasterChancePercentage;
/// @dev the percentage chance of winning blast master
uint24 public blastMasterChancePercentage;
/// @dev the percentage chance of winning Minor Jackpot
uint24 public minorJackpotChancePercentage;
/// @dev the denominator of [1%] + ([n / minorJackpotAdjustPercentage] * 100)%. where n is number of entries, eg: n = 1 then adjust = 1% + (1/100 * 100)% = 2%
uint public minorJackpotAdjustPercentage;
/// @dev the max probability of minor jackpot
uint public maxMinorJackpotProbability;
/// @dev the max number of winning king blaster
uint public maxKingBasterWinners;
/// @dev the max number of winning blast master
uint public maxBlastMasterWinners;
/// @dev king's prize percentage in the major jackpot
uint24 public kingBlasterPrizePercentage;
/// @dev blast's prize percentage in the major jackpot
uint24 public blastMasterPrizePercentage;
/// @dev minor prize percentage in the minor jackpot
uint24 public minorJackpotPrizePercentage;
/// @dev Number of entries since last win minor
uint public minorJackpotEntryCount;
/// @dev the duration of a round
uint32 public roundDuration;
/// @dev the max time can increase
uint32 public roundMaxTime;
/// @dev Percentage of treasury's ETH received when users buy spin
uint24 public ballTreasuryPortion;
/// @dev Percentage of majorJackpot's ETH received when users buy spin
uint24 public majorJackpotPortion;
/// @dev Percentage of minorJackpot's ETH received when users buy spin
uint24 public minorJackpotPortion;
/// @dev Percentage of next round majorJackpot's ETH received when users buy spin
uint24 public majorJackpotNextRoundPortion;
// /// @dev first Game timer chance percentage
// uint24 public firstGameTimerChancePercentage;
// /// @dev second Game timer chance percentage
// uint24 public secondGameTimerChancePercentage;
// /// @dev third Game timer chance percentage
// uint24 public thirdGameTimerChancePercentage;
// /// @dev first Game timer impact duration
// uint32 public firstGameTimerImpact;
// /// @dev second Game timer impact duration
// uint32 public secondGameTimerImpact;
// /// @dev second Game timer impact duration
// uint32 public thirdGameTimerImpact;
// /// @dev first level point probability
// uint public firstLevelPointP;
// /// @dev second level point probability
// uint public secondLevelPointP;
// /// @dev third level point probability
// uint public thirdLevelPointP;
// /// @dev fourth level point probability
// uint public fourthLevelPointP;
// /// @dev fifth level point probability
// uint public fifthLevelPointP;
// /// @dev sixth level point probability
// uint public sixthLevelPointP;
// /// @dev first level point amount
// uint public firstLevelPointA;
// /// @dev second level point amount
// uint public secondLevelPointA;
// /// @dev third level point amount
// uint public thirdLevelPointA;
// /// @dev fourth level point amount
// uint public fourthLevelPointA;
// /// @dev fifth level point amount
// uint public fifthLevelPointA;
// /// @dev sixth level point amount
// uint public sixthLevelPointA;
/// @dev level 1 bonus time
// uint32 public firstBonusTime;
// /// @dev level 2 bonus time
// uint32 public secondBonusTime;
// /// @dev level 3 bonus time
// uint32 public thirdBonusTime;
// /// @dev level 1 multiplier
// uint public firstBonusMultiplier;
// /// @dev level 2 multiplier
// uint public secondBonusMultiplier;
// /// @dev level 3 multiplier
// uint public thirdBonusMultiplier;
/// @dev guaranteed Slot
uint public guaranteeSlot;
/// @dev guaranteed Slot Count
uint public guaranteeSlotCount;
/// @dev the multiple probability
uint24 public multipleProbability;
/// @dev the number of seed back to treasury
uint public seededBack;
/// @dev seatposition left when new player win
uint[] public arrayPosLeft;
/// @dev the ante fee
uint public anteFee;
// uint public testVar;
/// @dev Mapping claimeable refund amounts. address --> claimed amounts
mapping(address => uint) public refundClaimable;
/// @dev Mapping claimed amounts. roundId (nonce) --> address --> claimed amounts
mapping(uint => mapping(address => uint)) public claimed;
/// @dev Mapping pending claimed amounts. roundId (nonce) --> address --> bool claimed
mapping(uint => mapping(address => bool)) public pendingClaimed;
/// @dev total winning prize from all round
mapping(address => uint) public claimableAmounts;
/// @dev Mapping winning kingBlaster. roundId (nonce) --> winned king address
mapping(uint => address) public kingBlasters;
/// @dev Mapping number of blast wins in 1 round. round nonce --> user address --> number of blast wins in 1 round
mapping(uint => mapping(address => uint)) public numberOfBlasts;
/// @dev Mapping winning blastMaster (default is 20 blast master). round nonce --> position id --> winner address
mapping(uint => mapping(uint => address)) public blastMasters;
/// @dev Mapping winning blastMaster with position (default is 10 blast master). round nonce --> winner address --> position
mapping(uint => mapping(address => uint)) public blastMasterPositions;
/// @dev Mapping Round Information
mapping(uint => Round) public rounds;
/// @dev Mapping Player Information
mapping(address => Player) public players;
/// @dev Mapping last spin information. round nonce --> player address --> lastSpin
mapping(uint => mapping(address => Spin)) public lastSpins;
/// @dev Mapping guaranteed address. round nonce --> seat number --> address
mapping(uint => mapping(uint => address)) public guaranteedSeat;
mapping(uint => uint) public guaranteedSeatBitMaskByRound;
/// @dev Mapping Ante
mapping(uint => mapping(address => bool)) public ante;
// ============================================ EVENT ============================================
// Event emitted when a buy spin is requested. The sequence number is required to reveal the result of the flip.
event BuySpin(address indexed player, uint roundId, uint64 sequenceNumber);
// Event emitted when executing a new spin
event ExecuteSpin(
address indexed player,
uint256 randomNumber,
uint nonce,
uint prizeAmount,
string timeImpact,
WinType indexed winType
);
// event ExecuteSpin(address indexed player, uint[3] uints, bool isIncrease, WinType indexed winType);
// Event emitted when creating a new round
event CreateNewRound(address indexed creator, uint nonce, uint startTime, uint roundDuration);
// Event emitted when claiming prize
event ClaimPrize(address indexed player, uint prize);
// Event emitted when someone wins a minor prize
event MinorWinner(address indexed player, uint roundId, uint prize, uint numberOfEntries);
// Event emitted when someone wins a king major prize
event MajorWinner(address indexed player, uint roundId, bool isKing, uint position);
// ================================= PYTH GENERATE RANDOM NUMBER =================================
// Contracts using Pyth Entropy should import the solidity SDK and then store both the Entropy contract
// and a specific entropy provider to use for requests. Each provider commits to a sequence of random numbers.
// Providers are then responsible for two things:
// 1. Operating an off-chain service that reveals their random numbers once they've been committed to on-chain
// 2. Maintaining the secrecy of the other random numbers
// Users should choose a reliable provider who they trust to uphold these commitments.
// (For the moment, the only available provider is 0x6CC14824Ea2918f5De5C2f75A9Da968ad4BD6344)
IEntropy public entropy;
address public provider;
// The contract is required to maintain a collection of in-flight requests. This mapping allows the contract
// to match the revealed random numbers against the original requests. The key of the map can be the
// sequence number provided by the Entropy protocol, and the value can be whatever information the protocol
// needs to resolve in-flight requests.
mapping(uint64 => address) public requestedRandomNumber;
// ================================= PYTH GENERATE RANDOM NUMBER =================================
/// @dev Number of seed prize when init new round
uint public numOfSeed;
/// @dev Number of time using seed prize when user buy spin
uint public seedCount;
/// @dev Admin Address take refund seed
address payable public adminAddr;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
enum GasMode {
VOID,
CLAIMABLE
}
interface IBlast{
// configure
function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;
function configure(YieldMode _yield, GasMode gasMode, address governor) external;
// base configuration options
function configureClaimableYield() external;
function configureClaimableYieldOnBehalf(address contractAddress) external;
function configureAutomaticYield() external;
function configureAutomaticYieldOnBehalf(address contractAddress) external;
function configureVoidYield() external;
function configureVoidYieldOnBehalf(address contractAddress) external;
function configureClaimableGas() external;
function configureClaimableGasOnBehalf(address contractAddress) external;
function configureVoidGas() external;
function configureVoidGasOnBehalf(address contractAddress) external;
function configureGovernor(address _governor) external;
function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;
// claim yield
function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256);
function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256);
// claim gas
function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256);
function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256);
// read functions
function readClaimableYield(address contractAddress) external view returns (uint256);
function readYieldConfiguration(address contractAddress) external view returns (uint8);
function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
interface IBlastPoints {
function configurePointsOperator(address operator) external;
function configurePointsOperatorOnBehalf(address contractAddress, address operator) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
interface IBTBConfig {
struct Point {
uint firstLevelPointP;
uint secondLevelPointP;
uint thirdLevelPointP;
uint fourthLevelPointP;
uint fifthLevelPointP;
uint sixthLevelPointP;
uint firstLevelPointA;
uint secondLevelPointA;
uint thirdLevelPointA;
uint fourthLevelPointA;
uint fifthLevelPointA;
uint sixthLevelPointA;
uint32 firstBonusTime;
uint32 secondBonusTime;
uint32 thirdBonusTime;
uint firstBonusMultiplier;
uint secondBonusMultiplier;
uint thirdBonusMultiplier;
}
struct TimeImpact {
uint24 firstGameTimerChancePercentage;
uint24 secondGameTimerChancePercentage;
uint24 thirdGameTimerChancePercentage;
uint32 firstGameTimerImpact;
uint32 secondGameTimerImpact;
uint32 thirdGameTimerImpact;
}
function getLevelPoint() external view returns(Point memory);
function getTimeImpact() external view returns(TimeImpact memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
library BlastTheBalloonErrors {
string public constant NOT_ALLOWED_ZERO_ADDRESS = '0';
string public constant CALLER_NOT_MANAGER = '1'; // 'The caller of the function is not a manager'
string public constant INVALID_SPIN = '2';
string public constant INVALID_ROUND_DURATION = '3';
string public constant ROUND_STILL_OPEN = '4';
string public constant ROUND_ENDED = '5';
string public constant ROUND_NOT_START = '6';
string public constant SPIN_IS_NOT_EXECUTED = '7';
string public constant INVALID_FEE = '8';
string public constant SPIN_IS_EXECUTED = '9';
string public constant CANT_BE_ZERO = '10';
string public constant INVALID_PERCENTAGE = '11';
string public constant CALLER_NOT_ENTROPY = '12';
string public constant NOT_ENOUGH_TOKEN = '13';
string public constant NOT_EMERGENCY = '14';
string public constant INVALID_TIMESTAMP = '15';
string public constant INVALID_TIME = '16';
string public constant CLAIMED = '17';
string public constant INVALID_AMOUNT = '18';
string public constant INVALID_FAIL_SPIN_LIMIT = '19';
string public constant INVALID_ANTE = '20';
string public constant ALREADY_ANTE = '21';
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "../BTBStorage.sol";
import "@pythnetwork/entropy-sdk-solidity/IEntropy.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import {BlastTheBalloonErrors} from "../libraries/BlastTheBalloonErrors.sol";
library OptimizedBTBLogicLib {
uint32 constant PERCENTAGE_DENOMINATOR = 100000;
/// @dev The longest possible time to start a new round
uint32 public constant LONGEST_START_DURATION = 7 days;
/// @dev Used to end a round a few seconds early
uint16 public constant DURATION_TOLERANCE = 3;
function newRoundCondition(
uint _startRound,
uint32 roundDuration,
BTBStorage.Round storage previousRoundInfo
) external view {
/// Check invalid round duration
require(roundDuration > 0, BlastTheBalloonErrors.INVALID_ROUND_DURATION);
/// Check if old round finished?
require(
block.timestamp > previousRoundInfo.startTime + previousRoundInfo.duration,
BlastTheBalloonErrors.ROUND_STILL_OPEN
);
/// Check start round timestamp
require(block.timestamp <= _startRound, BlastTheBalloonErrors.INVALID_TIMESTAMP);
/// Check if timestamp start new round longer than 7 days
require(_startRound <= block.timestamp + LONGEST_START_DURATION, BlastTheBalloonErrors.INVALID_TIMESTAMP);
}
function getRemainingPrize(
uint nonce,
uint numOfSeed,
uint spinFee,
uint majorJackpotPortion,
BTBStorage.Round storage previousRoundInfo,
mapping(uint => address) storage kingBlasters
) external view returns (uint, uint) {
/// Check to see if the previous round had a king winner and blast winner if none then add previous prize to current round
uint previousPrizeLeft = kingBlasters[nonce] == address(0) && previousRoundInfo.totalWinningBlastMaster == 0
? previousRoundInfo.majorJackpot
: 0;
uint seedPrize = kingBlasters[nonce] != address(0) || previousRoundInfo.totalWinningBlastMaster != 0
? (numOfSeed * spinFee * majorJackpotPortion) / PERCENTAGE_DENOMINATOR
: 0;
return (previousPrizeLeft, seedPrize);
}
/**
* @dev Refund last fail spin
*/
function refundSpin(
mapping(address => BTBStorage.Player) storage players,
mapping(uint => mapping(address => BTBStorage.Spin)) storage lastSpins,
mapping(address => uint) storage refundClaimable,
uint32 failSpinLimit,
address player
) external {
BTBStorage.Player storage playerInfo = players[player];
BTBStorage.Spin storage spinInfo = lastSpins[playerInfo.lastPlayRound][player];
if (
block.timestamp > spinInfo.lastPlayTime + failSpinLimit &&
spinInfo.status == BTBStorage.SpinStatus.WAITING_FOR_EXECUTE
) {
spinInfo.status = BTBStorage.SpinStatus.EXECUTED;
refundClaimable[player] += spinInfo.spinFee;
// emit RefundSpin(player, nonce, spinInfo.spinFee);
}
}
function addAnte(
uint _nonce,
uint anteFee,
address player,
address ballTreasury,
mapping(uint => BTBStorage.Round) storage rounds,
mapping(uint => mapping(address => bool)) storage ante
) external {
uint nonce = _nonce;
BTBStorage.Round storage roundInfo = rounds[nonce];
roundInfo.majorJackpotNextRound += ((msg.value * roundInfo.prizePortion.majorJackpotNextRoundPortion) /
PERCENTAGE_DENOMINATOR);
roundInfo.majorJackpot += ((msg.value * roundInfo.prizePortion.majorJackpotPortion) / PERCENTAGE_DENOMINATOR);
roundInfo.minorJackpot += ((msg.value * roundInfo.prizePortion.minorJackpotPortion) / PERCENTAGE_DENOMINATOR);
uint ballTreasuryAmount = (msg.value * roundInfo.prizePortion.ballTreasuryPortion) / PERCENTAGE_DENOMINATOR;
if (block.timestamp >= roundInfo.startTime) {
nonce = _nonce + 1;
roundInfo = rounds[nonce];
}
require(ante[nonce][player] != true, BlastTheBalloonErrors.ALREADY_ANTE);
require(msg.value >= anteFee, BlastTheBalloonErrors.INVALID_FEE);
(bool success, ) = ballTreasury.call{value: ballTreasuryAmount}("");
require(success, "Failed to send Ether to treasury");
ante[nonce][player] = true;
}
/**
* @dev check buy spin condition
*/
function buySpinCondition(BTBStorage.Round storage roundInfo, BTBStorage.Spin storage spinInfo) external view {
uint32 adjustedDuration = roundInfo.duration < DURATION_TOLERANCE ? 0 : roundInfo.duration - DURATION_TOLERANCE;
require(block.timestamp >= roundInfo.startTime, BlastTheBalloonErrors.ROUND_NOT_START);
require(block.timestamp <= roundInfo.startTime + adjustedDuration, BlastTheBalloonErrors.ROUND_ENDED);
require(
spinInfo.status == BTBStorage.SpinStatus.NONE || spinInfo.status == BTBStorage.SpinStatus.EXECUTED,
BlastTheBalloonErrors.SPIN_IS_NOT_EXECUTED
);
}
/**
* @dev check execute spin condition
*/
function executeSpinCondition(
BTBStorage.Round storage roundInfo,
BTBStorage.Spin storage spinInfo,
uint32 failSpinLimit
) external view {
require(block.timestamp >= roundInfo.startTime, BlastTheBalloonErrors.ROUND_NOT_START);
require(block.timestamp <= roundInfo.startTime + roundInfo.duration, BlastTheBalloonErrors.ROUND_ENDED);
require(spinInfo.status == BTBStorage.SpinStatus.WAITING_FOR_EXECUTE, BlastTheBalloonErrors.SPIN_IS_EXECUTED);
require(block.timestamp < spinInfo.lastPlayTime + failSpinLimit, BlastTheBalloonErrors.INVALID_SPIN);
}
/**
* @dev check buy spin condition
*/
function buySpin(
uint nonce,
uint totalValue,
uint spinFee,
address player,
address provider,
BTBStorage.Spin storage spinInfo,
IEntropy entropy,
mapping(uint64 => address) storage requestedRandomNumber,
bytes32 userRandomNumber
) external returns (uint64) {
// The entropy protocol requires the caller to pay a fee (in native gas tokens) per requested random number.
// This fee can either be paid by the contract itself or passed on to the end user.
// This implementation of the requestFlip method passes on the fee to the end user.
uint pythFee = entropy.getFee(provider);
uint totalFee = pythFee + spinFee;
require(totalValue >= totalFee, BlastTheBalloonErrors.INVALID_FEE);
uint acutalSpinFee = totalValue - pythFee;
// pay the fees and request a random number from entropy
uint64 sequenceNumber = entropy.requestWithCallback{value: pythFee}(provider, userRandomNumber);
requestedRandomNumber[sequenceNumber] = player;
spinInfo.roundId = nonce;
spinInfo.lastPlayTime = block.timestamp;
spinInfo.currentSpinId += 1;
spinInfo.spinFee = acutalSpinFee;
spinInfo.userCommitment = userRandomNumber;
spinInfo.sequenceNumber = sequenceNumber;
spinInfo.status = BTBStorage.SpinStatus.WAITING_FOR_EXECUTE;
return sequenceNumber;
}
function gameTimeImpact(
uint randomNumber,
uint userRandom,
BTBStorage.Round storage roundInfo
) external returns (string memory) {
// Round storage roundInfo = rounds[nonce];
uint winningPosition = randomNumber > userRandom
? (randomNumber % userRandom) % PERCENTAGE_DENOMINATOR
: (userRandom % randomNumber) % PERCENTAGE_DENOMINATOR;
uint24 firstLevelChance = roundInfo.timeImpact.firstGameTimerChancePercentage;
uint24 secondLevelChance = roundInfo.timeImpact.secondGameTimerChancePercentage;
uint24 thirdLevelChance = roundInfo.timeImpact.thirdGameTimerChancePercentage;
uint32 firstLevelImpact = roundInfo.timeImpact.firstGameTimerImpact;
uint32 secondLevelImpact = roundInfo.timeImpact.secondGameTimerImpact;
uint32 thirdLevelImpact = roundInfo.timeImpact.thirdGameTimerImpact;
if (winningPosition < firstLevelChance) {
roundInfo.duration = roundInfo.duration + firstLevelImpact >= roundInfo.maxTime
? roundInfo.maxTime
: roundInfo.duration + firstLevelImpact;
return string.concat("+", Strings.toString(firstLevelImpact));
} else if (winningPosition < firstLevelChance + secondLevelChance) {
roundInfo.duration = (secondLevelImpact >= roundInfo.duration) ? 0 : roundInfo.duration - secondLevelImpact;
return string.concat("-", Strings.toString(secondLevelImpact));
} else if (winningPosition < firstLevelChance + secondLevelChance + thirdLevelChance) {
roundInfo.duration = (thirdLevelImpact >= roundInfo.duration) ? 0 : roundInfo.duration - thirdLevelImpact;
return string.concat("-", Strings.toString(thirdLevelImpact));
}
}
/**
* @dev Minor Winner Logic
*/
function minorWinner(
uint nonce,
uint minorJackpotEntryCount,
address player,
mapping(uint => BTBStorage.Round) storage rounds,
mapping(address => uint) storage claimableAmounts
) external returns (uint, uint) {
BTBStorage.Round storage roundInfo = rounds[nonce];
uint entries = minorJackpotEntryCount;
uint minorPrize = (roundInfo.jackpot.minorJackpotPrizePercentage * roundInfo.minorJackpot) /
PERCENTAGE_DENOMINATOR;
roundInfo.minorJackpot = minorPrize < roundInfo.minorJackpot ? roundInfo.minorJackpot - minorPrize : 0;
claimableAmounts[player] += minorPrize;
return (entries, minorPrize);
}
/**
* @dev Check to see if won a major, king or blast
* @param uints an array contains:
* 0. nonce
* 1. winningPosition
* 2. kingProbability
* 3. blastProbability
* 4. blastMasterWinningPosition
* 5. multipleProbability
*/
function kingWinner(
uint[6] memory uints,
address player,
mapping(uint => BTBStorage.Round) storage rounds,
mapping(uint => address) storage kingBlasters
) external returns (uint, BTBStorage.WinType, uint) {
BTBStorage.Round storage roundInfo = rounds[uints[0]];
if (uints[1] < uints[2]) {
uint kingPrize = (roundInfo.majorJackpot * roundInfo.jackpot.kingBlasterPrizePercentage) /
PERCENTAGE_DENOMINATOR;
kingBlasters[uints[0]] = player;
return (kingPrize, BTBStorage.WinType.KING_BLASTER, 0);
}
return (0, BTBStorage.WinType.NONE, 0);
}
/**
* @param uints an array contains:
* 0. nonce
* 1. winningPosition
* 2. kingProbability
* 3. blastProbability
* 4. blastMasterWinningPosition
* 5. multipleProbability
*/
function replaceBlast(
address player,
uint[6] memory uints,
uint blastMasterWinningPosition,
BTBStorage.Round storage roundInfo,
mapping(uint => mapping(uint => address)) storage blastMasters,
mapping(uint => mapping(address => uint)) storage blastMasterPositions,
mapping(uint => mapping(address => uint)) storage numberOfBlasts
) internal returns (uint, BTBStorage.WinType, uint) {
if (uints[1] >= uints[3]) {
return (0, BTBStorage.WinType.NONE, 0);
}
address previousWinner = blastMasters[uints[0]][blastMasterWinningPosition];
roundInfo.jackpot.blastMasterChancePercentage = roundInfo.totalWinningBlastMaster <
roundInfo.maxBlastMasterWinners
? roundInfo.jackpot.blastMasterChancePercentage - uint24(uints[5])
: roundInfo.jackpot.blastMasterChancePercentage;
if (previousWinner == address(0)) {
roundInfo.totalWinningBlastMaster = (roundInfo.totalWinningBlastMaster < roundInfo.maxBlastMasterWinners)
? roundInfo.totalWinningBlastMaster + 1
: roundInfo.maxBlastMasterWinners;
} else {
blastMasterPositions[uints[0]][previousWinner] = roundInfo.maxBlastMasterWinners;
numberOfBlasts[uints[0]][previousWinner] = numberOfBlasts[uints[0]][previousWinner] == 0
? 0
: numberOfBlasts[uints[0]][previousWinner] - 1;
}
blastMasters[uints[0]][blastMasterWinningPosition] = player;
blastMasterPositions[uints[0]][player] = blastMasterWinningPosition;
numberOfBlasts[uints[0]][player] += 1;
uint blastPrize = ((roundInfo.majorJackpot * roundInfo.jackpot.blastMasterPrizePercentage) /
roundInfo.totalWinningBlastMaster) / PERCENTAGE_DENOMINATOR;
return (blastPrize, BTBStorage.WinType.BLAST_MASTER, blastMasterWinningPosition);
}
/**
* @dev Check to see if won a major, king or blast
* @param uints an array contains:
* 0. nonce
* 1. winningPosition
* 2. kingProbability
* 3. blastProbability
* 4. blastMasterWinningPosition
* 5. multipleProbability
*/
function blastWinner(
uint[6] memory uints,
address player,
mapping(uint => BTBStorage.Round) storage rounds,
mapping(uint => mapping(uint => address)) storage blastMasters,
mapping(uint => mapping(address => uint)) storage blastMasterPositions,
mapping(uint => mapping(address => uint)) storage numberOfBlasts
) external returns (uint, BTBStorage.WinType, uint) {
BTBStorage.Round storage roundInfo = rounds[uints[0]];
uint blastMasterWinningPosition = uints[4];
if (uints[1] < uints[3]) {
return
replaceBlast(
player,
uints,
blastMasterWinningPosition,
roundInfo,
blastMasters,
blastMasterPositions,
numberOfBlasts
);
}
return (0, BTBStorage.WinType.NONE, 0);
}
/**
* @dev Calculate Winning Position
* @param uints an array contains:
* 0. nonce
* 1. randomNumber
* 2. guaranteeSlot
* 3. guaranteeSlotCount
* 4. winningPosition
* 5. kingProbability
* 6. blastProbability
*/
function calculateWinningPosition(
uint[7] memory uints,
address player,
BTBStorage.Round memory roundInfo,
uint guaranteedSeatBitMask,
mapping(uint => mapping(uint => address)) storage guaranteedSeat
) external returns (uint, uint) {
uint index = 0;
uint maxBlastMasterWinners = roundInfo.maxBlastMasterWinners;
uint[] memory arrayPosLeft = new uint[](maxBlastMasterWinners);
for (uint i = 0; i < maxBlastMasterWinners; ) {
if ((guaranteedSeatBitMask & (1 << i)) == 0) {
arrayPosLeft[index] = i;
index += 1;
}
unchecked {
++i;
}
}
uint randomNumber = type(uint).max % uints[1];
uint blastMasterWinningPosition = arrayPosLeft[randomNumber % index];
if (uints[4] >= uints[5] && uints[4] < uints[6]) {
if (blastMasterWinningPosition < uints[2]) {
guaranteedSeat[uints[0]][blastMasterWinningPosition] = player;
guaranteedSeatBitMask ^= (1 << blastMasterWinningPosition);
}
}
return (blastMasterWinningPosition, guaranteedSeatBitMask);
}
/**
* @dev update Prize Information of the round
*/
function updatePrizePool(
BTBStorage.Round storage roundInfo,
BTBStorage.Spin storage spinInfo,
// uint ballTreasuryPortion,
uint majorJackpotPortion,
uint minorJackpotPortion,
uint majorJackpotNextRoundPortion // address ballTreasury
) external {
// update round info
roundInfo.totalSpins += 1;
roundInfo.majorJackpot += ((spinInfo.spinFee * majorJackpotPortion) / PERCENTAGE_DENOMINATOR);
roundInfo.minorJackpot += ((spinInfo.spinFee * minorJackpotPortion) / PERCENTAGE_DENOMINATOR);
roundInfo.majorJackpotNextRound += ((spinInfo.spinFee * majorJackpotNextRoundPortion) / PERCENTAGE_DENOMINATOR);
}
/**
* @dev update new round Information
*/
function updateRoundInfo(
BTBStorage.Round storage roundInfo,
BTBStorage.Round storage previousRoundInfo,
uint previousPrizeLeft,
uint seedPrize,
uint32 _startRound,
uint[40] memory params
) external {
roundInfo.startTime = _startRound;
roundInfo.roundId = params[0];
roundInfo.duration = uint32(params[1]);
roundInfo.maxTime = uint32(params[2]);
roundInfo.majorJackpot += (previousRoundInfo.majorJackpotNextRound + previousPrizeLeft + seedPrize);
roundInfo.minorJackpot = previousRoundInfo.minorJackpot;
roundInfo.maxBlastMasterWinners = params[3];
roundInfo.timeImpact.firstGameTimerChancePercentage = uint24(params[4]);
roundInfo.timeImpact.secondGameTimerChancePercentage = uint24(params[5]);
roundInfo.timeImpact.thirdGameTimerChancePercentage = uint24(params[6]);
roundInfo.timeImpact.firstGameTimerImpact = uint32(params[7]);
roundInfo.timeImpact.secondGameTimerImpact = uint32(params[8]);
roundInfo.timeImpact.thirdGameTimerImpact = uint32(params[9]);
roundInfo.jackpot.kingBlasterChancePercentage = uint24(params[10]);
roundInfo.jackpot.blastMasterChancePercentage = uint24(params[11]);
roundInfo.jackpot.minorJackpotChancePercentage = uint24(params[12]);
roundInfo.jackpot.kingBlasterPrizePercentage = uint24(params[13]);
roundInfo.jackpot.blastMasterPrizePercentage = uint24(params[14]);
roundInfo.jackpot.minorJackpotPrizePercentage = uint24(params[15]);
roundInfo.jackpot.minorJackpotAdjustPercentage = params[16];
roundInfo.jackpot.maxMinorJackpotProbability = params[17];
roundInfo.point.firstLevelPointP = params[18];
roundInfo.point.secondLevelPointP = params[19];
roundInfo.point.thirdLevelPointP = params[20];
roundInfo.point.fourthLevelPointP = params[21];
roundInfo.point.fifthLevelPointP = params[22];
roundInfo.point.sixthLevelPointP = params[23];
roundInfo.point.firstLevelPointA = params[24];
roundInfo.point.secondLevelPointA = params[25];
roundInfo.point.thirdLevelPointA = params[26];
roundInfo.point.fourthLevelPointA = params[27];
roundInfo.point.fifthLevelPointA = params[28];
roundInfo.point.sixthLevelPointA = params[29];
roundInfo.point.firstBonusTime = uint32(params[30]);
roundInfo.point.secondBonusTime = uint32(params[31]);
roundInfo.point.thirdBonusTime = uint32(params[32]);
roundInfo.point.firstBonusMultiplier = params[33];
roundInfo.point.secondBonusMultiplier = params[34];
roundInfo.point.thirdBonusMultiplier = params[35];
roundInfo.prizePortion.ballTreasuryPortion = params[36];
roundInfo.prizePortion.majorJackpotNextRoundPortion = params[37];
roundInfo.prizePortion.majorJackpotPortion = params[38];
roundInfo.prizePortion.minorJackpotPortion = params[39];
}
}{
"optimizer": {
"enabled": true,
"runs": 100
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {
"contracts/libraries/OptimizedBTBLogicLib.sol": {
"OptimizedBTBLogicLib": "0xd5cc46388c7046fb9770ae1191c14686eaec63c6"
}
}
}Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"BuySpin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"prize","type":"uint256"}],"name":"ClaimPrize","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"roundDuration","type":"uint256"}],"name":"CreateNewRound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"randomNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"indexed":false,"internalType":"string","name":"timeImpact","type":"string"},{"indexed":true,"internalType":"enum BTBStorage.WinType","name":"winType","type":"uint8"}],"name":"ExecuteSpin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isKing","type":"bool"},{"indexed":false,"internalType":"uint256","name":"position","type":"uint256"}],"name":"MajorWinner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numberOfEntries","type":"uint256"}],"name":"MinorWinner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","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":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"BlastPointsAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OWNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERCENTAGE_DENOMINATOR","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"__Base_init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"sequence","type":"uint64"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"bytes32","name":"randomNumber","type":"bytes32"}],"name":"_entropyCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"addAnte","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"adminAddr","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"ante","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"anteFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"arrayPosLeft","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ballTreasury","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ballTreasuryPortion","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blastMasterChancePercentage","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"blastMasterPositions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blastMasterPrizePercentage","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"blastMasters","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"},{"internalType":"bytes32","name":"userRandomNumber","type":"bytes32"}],"name":"buySpin","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimAllGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimAllYield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimMaxGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimPrize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimableAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"claimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"contract IBTBConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startRound","type":"uint256"}],"name":"createNewRound","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"emergencyStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"entropy","outputs":[{"internalType":"contract IEntropy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"failSpinLimit","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"getActualClaimableAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"getBlastWinners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"getClaimableAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"getCurrentClaimableAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"getMinorProbability","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"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":[],"name":"guaranteeSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guaranteeSlotCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"guaranteedSeat","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"guaranteedSeatBitMaskByRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"_entropy","type":"address"},{"internalType":"address","name":"_provider","type":"address"},{"internalType":"address","name":"_ballTreasury","type":"address"},{"internalType":"address","name":"_pointsOperator","type":"address"},{"internalType":"address","name":"_BlastPointsAddress","type":"address"},{"internalType":"address","name":"_config","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPauser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kingBlasterChancePercentage","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kingBlasterPrizePercentage","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"kingBlasters","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"lastSpins","outputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256","name":"currentSpinId","type":"uint256"},{"internalType":"uint256","name":"lastPlayTime","type":"uint256"},{"internalType":"uint256","name":"spinFee","type":"uint256"},{"internalType":"bytes32","name":"userCommitment","type":"bytes32"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"enum BTBStorage.SpinStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"majorJackpotNextRoundPortion","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"majorJackpotPortion","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBlastMasterWinners","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxKingBasterWinners","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMinorJackpotProbability","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minorJackpotAdjustPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minorJackpotChancePercentage","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minorJackpotEntryCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minorJackpotPortion","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minorJackpotPrizePercentage","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multipleProbability","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numOfSeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"numberOfBlasts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"pendingClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"players","outputs":[{"internalType":"uint256","name":"lastPlayRound","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pointsOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"provider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"refundClaimable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refundSpin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"requestedRandomNumber","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"roundDuration","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"roundMaxTime","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rounds","outputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint32","name":"maxTime","type":"uint32"},{"internalType":"uint256","name":"majorJackpotNextRound","type":"uint256"},{"internalType":"uint256","name":"majorJackpot","type":"uint256"},{"internalType":"uint256","name":"minorJackpot","type":"uint256"},{"internalType":"uint256","name":"totalSpins","type":"uint256"},{"internalType":"uint256","name":"totalWinningBlastMaster","type":"uint256"},{"internalType":"uint256","name":"maxBlastMasterWinners","type":"uint256"},{"components":[{"internalType":"uint24","name":"firstGameTimerChancePercentage","type":"uint24"},{"internalType":"uint24","name":"secondGameTimerChancePercentage","type":"uint24"},{"internalType":"uint24","name":"thirdGameTimerChancePercentage","type":"uint24"},{"internalType":"uint32","name":"firstGameTimerImpact","type":"uint32"},{"internalType":"uint32","name":"secondGameTimerImpact","type":"uint32"},{"internalType":"uint32","name":"thirdGameTimerImpact","type":"uint32"}],"internalType":"struct BTBStorage.TimeImpact","name":"timeImpact","type":"tuple"},{"components":[{"internalType":"uint24","name":"kingBlasterChancePercentage","type":"uint24"},{"internalType":"uint24","name":"blastMasterChancePercentage","type":"uint24"},{"internalType":"uint24","name":"minorJackpotChancePercentage","type":"uint24"},{"internalType":"uint24","name":"kingBlasterPrizePercentage","type":"uint24"},{"internalType":"uint24","name":"blastMasterPrizePercentage","type":"uint24"},{"internalType":"uint24","name":"minorJackpotPrizePercentage","type":"uint24"},{"internalType":"uint256","name":"minorJackpotAdjustPercentage","type":"uint256"},{"internalType":"uint256","name":"maxMinorJackpotProbability","type":"uint256"}],"internalType":"struct BTBStorage.Jackpot","name":"jackpot","type":"tuple"},{"components":[{"internalType":"uint256","name":"ballTreasuryPortion","type":"uint256"},{"internalType":"uint256","name":"majorJackpotNextRoundPortion","type":"uint256"},{"internalType":"uint256","name":"majorJackpotPortion","type":"uint256"},{"internalType":"uint256","name":"minorJackpotPortion","type":"uint256"}],"internalType":"struct BTBStorage.PrizePortion","name":"prizePortion","type":"tuple"},{"components":[{"internalType":"uint256","name":"firstLevelPointP","type":"uint256"},{"internalType":"uint256","name":"secondLevelPointP","type":"uint256"},{"internalType":"uint256","name":"thirdLevelPointP","type":"uint256"},{"internalType":"uint256","name":"fourthLevelPointP","type":"uint256"},{"internalType":"uint256","name":"fifthLevelPointP","type":"uint256"},{"internalType":"uint256","name":"sixthLevelPointP","type":"uint256"},{"internalType":"uint256","name":"firstLevelPointA","type":"uint256"},{"internalType":"uint256","name":"secondLevelPointA","type":"uint256"},{"internalType":"uint256","name":"thirdLevelPointA","type":"uint256"},{"internalType":"uint256","name":"fourthLevelPointA","type":"uint256"},{"internalType":"uint256","name":"fifthLevelPointA","type":"uint256"},{"internalType":"uint256","name":"sixthLevelPointA","type":"uint256"},{"internalType":"uint32","name":"firstBonusTime","type":"uint32"},{"internalType":"uint32","name":"secondBonusTime","type":"uint32"},{"internalType":"uint32","name":"thirdBonusTime","type":"uint32"},{"internalType":"uint256","name":"firstBonusMultiplier","type":"uint256"},{"internalType":"uint256","name":"secondBonusMultiplier","type":"uint256"},{"internalType":"uint256","name":"thirdBonusMultiplier","type":"uint256"}],"internalType":"struct BTBStorage.Point","name":"point","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seededBack","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_status","type":"bool"}],"name":"setEmergencyStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"spinFee","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":[{"internalType":"uint32","name":"_newDuration","type":"uint32"}],"name":"updateFailSpinLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newAdjustPercentage","type":"uint256"}],"name":"updateJackpotAdjustPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24[3]","name":"jackpotChances","type":"uint24[3]"}],"name":"updateJackpotChance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24[4]","name":"portions","type":"uint24[4]"}],"name":"updatePrizePortion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24[3]","name":"rewardPercentages","type":"uint24[3]"}],"name":"updateRewardPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMaxBlastMasters","type":"uint256"},{"internalType":"uint256","name":"_newSpinFee","type":"uint256"},{"internalType":"uint256","name":"_anteFee","type":"uint256"},{"internalType":"uint32","name":"_newDuration","type":"uint32"},{"internalType":"uint32","name":"_newMaxTime","type":"uint32"},{"internalType":"uint24","name":"_multipleProbability","type":"uint24"}],"name":"updateRoundConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_newSeed","type":"uint32"},{"internalType":"uint256","name":"_seedBack","type":"uint256"},{"internalType":"uint256","name":"_newGuaranteeSeat","type":"uint256"}],"name":"updateSeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_entropy","type":"address"},{"internalType":"address","name":"_provider","type":"address"},{"internalType":"address","name":"_newTreasury","type":"address"},{"internalType":"address","name":"_newAdmin","type":"address"}],"name":"updateSystemAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b615dfa80620000f36000396000f3fe6080604052600436106104c05760003560e01c80638bed5bd211610274578063bb0c48531161014e578063d731907a116100c6578063e58378bb11610082578063e58378bb1461145f578063e63ab1e914611481578063e7487eb5146114a3578063edcc8461146114df578063f7cb789a146114ff578063f9b3d1ad1461151d57005b8063d731907a14611328578063dce54178146113ac578063e12f3a61146113cc578063e2eb41ff146113ec578063e3ec42c61461141a578063e45ed31e1461143157005b8063cc2a9a5b11610115578063cc2a9a5b1461126f578063cd2002f51461128f578063ced72f87146112af578063d00c9179146112c4578063d0efe3c7146112e8578063d547741f1461130857005b8063bb0c4853146111c0578063c18e8ac8146111d5578063c2d94aec146111fa578063c91360061461121a578063cabb1ae41461125157005b8063a178a472116101ec578063a97223ed116101a8578063a97223ed14611100578063affed0e014611124578063b3cd42541461113b578063b6db75a014611167578063b7a52bfb1461117c578063b80163a9146111a057005b8063a178a47214611026578063a217fddf1461104a578063a2ee631b1461105f578063a420f7b21461108c578063a65d60af146110b0578063a86b11b8146110c757005b8063936c8a511161023b578063936c8a5114610f5a57806399221b2714610f9c5780639b6bb91d14610fbc5780639bbe239114610fdc5780639df6efd214610ff3578063a170dfc91461100657005b80638bed5bd214610ae35780638c65c81f14610afa578063906e3d9f14610ee75780639119ddc514610efe57806391d1485414610f3a57005b806344599e34116103a55780635c975abb1161031d57806370740ac9116102d957806370740ac914610a3157806375715ce714610a4657806379502c5514610a6657806380c2c89714610a875780638183059314610a9e57806387f9798914610abf57005b80635c975abb146109785780635ead5a321461099057806367cabd66146109c957806368e9f954146109e95780636919ed7214610a095780636a8a3b9614610a1c57005b80634dbb78b71161036c5780634dbb78b71461089b5780634f1d7f6e146108bf5780635237fa55146108d657806352a5f1f8146108f65780635312ea8e146109165780635508edf11461093657005b806344599e34146107fc57806346eacf1b1461081957806347ce07cc1461083957806347fb45531461085a5780634b750bd51461087b57005b806322bc2852116104385780632c4106bd116103ff5780632c4106bd146107405780632cc5d624146107575780632f2ff15d1461077757806330858ae21461079757806336568abe146107c55780633de3786a146107e557005b806322bc285214610694578063248a9ca3146106ab578063272b1323146106db5780632a3d5741146106fb5780632bc79c121461071257005b80630ecb3c89116104875780630ecb3c89146105b1578063120aa877146105c457806316cfaa16146105fd5780631aba27301461061e5780631b43987f146106555780631f0f01ef1461067757005b806301ffc9a7146104c9578063085d4883146104fe578063088803b41461052c5780630a1d562f146105645780630e9d0c321461058c57005b366104c757005b005b3480156104d557600080fd5b506104e96104e4366004614cb5565b61153a565b60405190151581526020015b60405180910390f35b34801561050a57600080fd5b506101e65461051f906001600160a01b031681565b6040516104f59190614cdf565b34801561053857600080fd5b506101ce5461055090600160301b900462ffffff1681565b60405162ffffff90911681526020016104f5565b34801561057057600080fd5b506101c35461051f90600160281b90046001600160a01b031681565b34801561059857600080fd5b506105a36101cc5481565b6040519081526020016104f5565b6104c76105bf366004614d0f565b611571565b3480156105d057600080fd5b506105a36105df366004614d39565b6101d860209081526000928352604080842090915290825290205481565b34801561060957600080fd5b506101c45461051f906001600160a01b031681565b34801561062a57600080fd5b5061051f610639366004614d7a565b6101e7602052600090815260409020546001600160a01b031681565b34801561066157600080fd5b506101c3546104e990600160201b900460ff1681565b34801561068357600080fd5b506101d3546105509062ffffff1681565b3480156106a057600080fd5b506105a36101cb5481565b3480156106b757600080fd5b506105a36106c6366004614d97565b60009081526065602052604090206001015490565b3480156106e757600080fd5b506104c76106f6366004614db0565b6117c1565b34801561070757600080fd5b506105a36101d15481565b34801561071e57600080fd5b506105a361072d366004614db0565b6101da6020526000908152604090205481565b34801561074c57600080fd5b506105a36101c85481565b34801561076357600080fd5b506105a3610772366004614d97565b611854565b34801561078357600080fd5b506104c7610792366004614d39565b611876565b3480156107a357600080fd5b506105a36107b2366004614d97565b6101e36020526000908152604090205481565b3480156107d157600080fd5b506104c76107e0366004614d39565b6118a0565b3480156107f157600080fd5b506105a36101cd5481565b34801561080857600080fd5b506101ce546105509062ffffff1681565b34801561082557600080fd5b506105a3610834366004614db0565b61191a565b34801561084557600080fd5b506101e55461051f906001600160a01b031681565b34801561086657600080fd5b506101c55461051f906001600160a01b031681565b34801561088757600080fd5b506104c7610896366004614d97565b611abb565b3480156108a757600080fd5b506101c954610550906301000000900462ffffff1681565b3480156108cb57600080fd5b506105a36101d45481565b3480156108e257600080fd5b506104c76108f1366004614dcb565b611b23565b34801561090257600080fd5b506104c7610911366004614df3565b611ca0565b34801561092257600080fd5b506104c7610931366004614d97565b611d7c565b34801561094257600080fd5b5061051f610951366004614e31565b6101dd6020908152600092835260408084209091529082529020546001600160a01b031681565b34801561098457600080fd5b5060975460ff166104e9565b34801561099c57600080fd5b506105a36109ab366004614d39565b6101dc60209081526000928352604080842090915290825290205481565b3480156109d557600080fd5b506104c76109e4366004614e53565b611ea2565b3480156109f557600080fd5b506104c7610a04366004614eb9565b61202c565b6104c7610a17366004614d97565b612163565b348015610a2857600080fd5b506104e96127b2565b348015610a3d57600080fd5b506104c76127d1565b348015610a5257600080fd5b506104c7610a61366004614db0565b6129a5565b348015610a7257600080fd5b506101c65461051f906001600160a01b031681565b348015610a9357600080fd5b506105a36101ca5481565b348015610aaa57600080fd5b506101ea5461051f906001600160a01b031681565b348015610acb57600080fd5b506101c95461055090600160301b900462ffffff1681565b348015610aef57600080fd5b506105a36101e95481565b348015610b0657600080fd5b50610ecd610b15366004614d97565b6101df6020528060005260406000206000915090508060000154908060010160009054906101000a900463ffffffff16908060010160049054906101000a900463ffffffff16908060010160089054906101000a900463ffffffff1690806002015490806003015490806004015490806005015490806006015490806007015490806008016040518060c00160405290816000820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160039054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160069054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160099054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600d9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160119054906101000a900463ffffffff1663ffffffff1663ffffffff16815250509080600901604051806101000160405290816000820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160039054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160069054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160099054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600c9054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600f9054906101000a900462ffffff1662ffffff1662ffffff168152602001600182015481526020016002820154815250509080600c0160405180608001604052908160008201548152602001600182015481526020016002820154815260200160038201548152505090806010016040518061024001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152602001600782015481526020016008820154815260200160098201548152602001600a8201548152602001600b8201548152602001600c820160009054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600c820160049054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600c820160089054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600d8201548152602001600e8201548152602001600f8201548152505090508e565b6040516104f59e9d9c9b9a99989796959493929190614fcc565b348015610ef357600080fd5b506105a36101cf5481565b348015610f0a57600080fd5b506104e9610f19366004614d39565b6101d960209081526000928352604080842090915290825290205460ff1681565b348015610f4657600080fd5b506104e9610f55366004614d39565b612aa8565b348015610f6657600080fd5b5061051f610f75366004614e31565b6101e26020908152600092835260408084209091529082529020546001600160a01b031681565b348015610fa857600080fd5b506104c7610fb736600461512d565b612ad3565b348015610fc857600080fd5b506104c7610fd7366004614dcb565b612b55565b348015610fe857600080fd5b506105a36101d65481565b6104c7611001366004614db0565b612cc7565b34801561101257600080fd5b506105a3611021366004614d97565b612d7f565b34801561103257600080fd5b506101d05461055090600160581b900462ffffff1681565b34801561105657600080fd5b506105a3600081565b34801561106b57600080fd5b5061107f61107a366004614d97565b612e09565b6040516104f5919061514a565b34801561109857600080fd5b506101d05461055090600160881b900462ffffff1681565b3480156110bc57600080fd5b506105a36101e85481565b3480156110d357600080fd5b506105a36110e2366004614d39565b6101de60209081526000928352604080842090915290825290205481565b34801561110c57600080fd5b506101d05461055090600160401b900462ffffff1681565b34801561113057600080fd5b506105a36101c75481565b34801561114757600080fd5b50611152620186a081565b60405163ffffffff90911681526020016104f5565b34801561117357600080fd5b506104e9612f1e565b34801561118857600080fd5b506101ce54610550906301000000900462ffffff1681565b3480156111ac57600080fd5b506104c76111bb366004615197565b612f38565b3480156111cc57600080fd5b506104c7612f7c565b3480156111e157600080fd5b506101d05461115290600160201b900463ffffffff1681565b34801561120657600080fd5b506104c7611215366004614db0565b6130a0565b34801561122657600080fd5b5061051f611235366004614d97565b6101db602052600090815260409020546001600160a01b031681565b34801561125d57600080fd5b506101c3546111529063ffffffff1681565b34801561127b57600080fd5b506104c761128a3660046151b9565b6130f0565b34801561129b57600080fd5b506104c76112aa366004614db0565b6133f9565b3480156112bb57600080fd5b506105a3613449565b3480156112d057600080fd5b506101d05461055090600160701b900462ffffff1681565b3480156112f457600080fd5b506104c761130336600461523e565b6134d2565b34801561131457600080fd5b506104c7611323366004614d39565b61365b565b34801561133457600080fd5b50611399611343366004614d39565b6101e160209081526000928352604080842090915290825290208054600182015460028301546003840154600485015460059095015493949293919290916001600160401b03811690600160401b900460ff1687565b6040516104f597969594939291906152bb565b3480156113b857600080fd5b506104c76113c736600461531d565b613680565b3480156113d857600080fd5b506105a36113e7366004614db0565b61381a565b3480156113f857600080fd5b506105a3611407366004614db0565b6101e06020526000908152604090205481565b34801561142657600080fd5b506105a36101d25481565b34801561143d57600080fd5b506105a361144c366004614db0565b6101d76020526000908152604090205481565b34801561146b57600080fd5b506105a3600080516020615d8583398151915281565b34801561148d57600080fd5b506105a3600080516020615da583398151915281565b3480156114af57600080fd5b506104e96114be366004614d39565b6101e460209081526000928352604080842090915290825290205460ff1681565b3480156114eb57600080fd5b506105a36114fa366004614db0565b61387c565b34801561150b57600080fd5b506101d0546111529063ffffffff1681565b34801561152957600080fd5b506101c9546105509062ffffff1681565b60006001600160e01b03198216637965db0b60e01b148061156b57506301ffc9a760e01b6001600160e01b03198316145b92915050565b611579613a6c565b6101c75460009081526101df602090815260408083206101e183528184206001600160a01b03871685529092529091206115b284613ac5565b604051638f4fa25160e01b8152600481018390526024810182905273d5cc46388c7046fb9770ae1191c14686eaec63c690638f4fa2519060440160006040518083038186803b15801561160457600080fd5b505af4158015611618573d6000803e3d6000fd5b5050505061162584613b5c565b6101c75460009081526101e4602090815260408083206001600160a01b03881684528252918290205482518084019093526002835261032360f41b9183019190915260ff166116905760405162461bcd60e51b8152600401611687919061538f565b60405180910390fd5b506101c7546101c8546101e6546101e554604051631295edbd60e21b8152600481019490945234602485015260448401929092526001600160a01b038088166064850152908116608484015260a483018490521660c48201526101e760e4820152610104810184905260009073d5cc46388c7046fb9770ae1191c14686eaec63c690634a57b6f49061012401602060405180830381865af4158015611739573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175d91906153a2565b6101c754604080519182526001600160401b03831660208301529192506001600160a01b038716917f5a0920da7c4df7f0e5da0ce23542a31a806ddda495b3f8da7ca95e92ad030dbc910160405180910390a25050506117bd600160c955565b5050565b6117c9612f1e565b6117e55760405162461bcd60e51b8152600401611687906153bf565b604051634aa7d2f760e11b81526002604360981b019063954fa5ee90611811903090859060040161540a565b6020604051808303816000875af1158015611830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117bd9190615424565b6101d5818154811061186557600080fd5b600091825260209091200154905081565b60008281526065602052604090206001015461189181613c0a565b61189b8383613c14565b505050565b6001600160a01b03811633146119105760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401611687565b6117bd8282613c9a565b6101c75460009081526101df602090815260408083206101d983528184206001600160a01b0386168552909252822054829060ff161561195b579392505050565b6101c75460009081526101dc602090815260408083206001600160a01b038816845290915281205460038401546009850154919291620186a0916119aa91600160481b900462ffffff16615453565b6119b49190615488565b9050600084600601546000146119e85784600601548286600301546119d9919061549c565b6119e39190615488565b6119eb565b60005b6101c75460009081526101db60205260409020549091506001600160a01b03808916911603611a4a578460060154600003611a3d57818560030154611a30919061549c565b611a3a90856154af565b93505b611a4782856154af565b93505b8215611ab0576101c75460009081526101db60205260409020546001600160a01b0316611a995782856006015483611a829190615488565b611a8c9190615453565b611a9690856154af565b93505b611aa38382615453565b611aad90856154af565b93505b509195945050505050565b611ac3612f1e565b611adf5760405162461bcd60e51b8152600401611687906153bf565b604080518082019091526002815261313160f01b6020820152620186a0821115611b1c5760405162461bcd60e51b8152600401611687919061538f565b506101ca55565b611b2b612f1e565b611b475760405162461bcd60e51b8152600401611687906153bf565b6000611b5960408301602084016154d8565b611b6660208401846154d8565b611b7091906154f5565b62ffffff169050620186a063ffffffff1681111560405180604001604052806002815260200161313160f01b81525090611bbd5760405162461bcd60e51b8152600401611687919061538f565b50620186a0611bd260608401604085016154d8565b62ffffff16111560405180604001604052806002815260200161313160f01b81525090611c125760405162461bcd60e51b8152600401611687919061538f565b50611c2060208301836154d8565b6101ce805462ffffff191662ffffff92909216919091179055611c4960408301602084016154d8565b6101ce805462ffffff9290921663010000000265ffffff00000019909216919091179055611c7d60608301604084016154d8565b6101ce60066101000a81548162ffffff021916908362ffffff1602179055505050565b6000611cb56101e5546001600160a01b031690565b90506001600160a01b038116611d075760405162461bcd60e51b8152602060048201526017602482015276115b9d1c9bdc1e481859191c995cdcc81b9bdd081cd95d604a1b6044820152606401611687565b336001600160a01b03821614611d6b5760405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920456e74726f70792063616e2063616c6c20746869732066756e637460448201526234b7b760e91b6064820152608401611687565b611d76848484613d01565b50505050565b611d84613a6c565b611d8c612f1e565b611da85760405162461bcd60e51b8152600401611687906153bf565b6101c3546040805180820190915260028152610c4d60f21b602082015290600160201b900460ff16611ded5760405162461bcd60e51b8152600401611687919061538f565b508047101560405180604001604052806002815260200161062760f31b81525090611e2b5760405162461bcd60e51b8152600401611687919061538f565b50604051600090339083908381818185875af1925050503d8060008114611e6e576040519150601f19603f3d011682016040523d82523d6000602084013e611e73565b606091505b5050905080611e945760405162461bcd60e51b815260040161168790615518565b50611e9f600160c955565b50565b611eaa612f1e565b611ec65760405162461bcd60e51b8152600401611687906153bf565b6040805180820190915260018152600360fc1b60208201526001600160a01b038516611f055760405162461bcd60e51b8152600401611687919061538f565b506040805180820190915260018152600360fc1b60208201526001600160a01b038416611f455760405162461bcd60e51b8152600401611687919061538f565b506040805180820190915260018152600360fc1b60208201526001600160a01b038316611f855760405162461bcd60e51b8152600401611687919061538f565b506040805180820190915260018152600360fc1b60208201526001600160a01b038216611fc55760405162461bcd60e51b8152600401611687919061538f565b506101e580546001600160a01b039586166001600160a01b0319918216179091556101e68054948616948216949094179093556101c38054928516600160281b02600160281b600160c81b0319909316929092179091556101ea8054919093169116179055565b612034612f1e565b6120505760405162461bcd60e51b8152600401611687906153bf565b6101c75460009081526101df6020526040902060018101546120819063ffffffff600160201b82048116911661555c565b63ffffffff1642118061209d5750600181015463ffffffff1642105b604051806040016040528060018152602001600d60fa1b815250906120d55760405162461bcd60e51b8152600401611687919061538f565b50604080518082019091526002815261031360f41b602082015263ffffffff85166121135760405162461bcd60e51b8152600401611687919061538f565b50604080518082019091526002815261031360f41b60208201528261214b5760405162461bcd60e51b8152600401611687919061538f565b505063ffffffff9092166101e8556101d4556101d155565b61216b612f1e565b6121875760405162461bcd60e51b8152600401611687906153bf565b6101c75460009081526101df6020526040908190206101d054915163063f43a360e41b81526004810184905263ffffffff9092166024830152604482018190529073d5cc46388c7046fb9770ae1191c14686eaec63c6906363f43a309060640160006040518083038186803b1580156121ff57600080fd5b505af4158015612213573d6000803e3d6000fd5b50506101c7546101e8546101c8546101d05460405163fce0536160e01b8152600481019490945260248401929092526044830152600160581b900462ffffff166064820152608481018490526101db60a48201526000925082915073d5cc46388c7046fb9770ae1191c14686eaec63c69063fce053619060c4016040805180830381865af41580156122a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122cd9190615579565b91509150806000036122e2576101e9546122e5565b60005b6101e98190555060016101c7600082825461230091906154af565b909155505060006101d28190556101c75481526101df60205260408082206101c65482516315cef56d60e11b815292519193926001600160a01b0390911691632b9deada91600480820192610240929091908290030181865afa15801561236b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238f91906155e7565b905060006101c660009054906101000a90046001600160a01b03166001600160a01b031663a8bcf2ab6040518163ffffffff1660e01b815260040160c060405180830381865afa1580156123e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061240b91906156dc565b905060006040518061050001604052806101c75481526020016101d060009054906101000a900463ffffffff1663ffffffff1681526020016101d060049054906101000a900463ffffffff1663ffffffff1681526020016101cd548152602001836000015162ffffff168152602001836020015162ffffff168152602001836040015162ffffff168152602001836060015163ffffffff168152602001836080015163ffffffff1681526020018360a0015163ffffffff1681526020016101c960009054906101000a900462ffffff1662ffffff1681526020016101c960039054906101000a900462ffffff1662ffffff1681526020016101c960069054906101000a900462ffffff1662ffffff1681526020016101ce60009054906101000a900462ffffff1662ffffff1681526020016101ce60039054906101000a900462ffffff1662ffffff1681526020016101ce60069054906101000a900462ffffff1662ffffff1681526020016101ca5481526020016101cb54815260200184600001518152602001846020015181526020018460400151815260200184606001518152602001846080015181526020018460a0015181526020018460c0015181526020018460e001518152602001846101000151815260200184610120015181526020018461014001518152602001846101600151815260200184610180015163ffffffff168152602001846101a0015163ffffffff168152602001846101c0015163ffffffff168152602001846101e001518152602001846102000151815260200184610220015181526020016101d060089054906101000a900462ffffff1662ffffff1681526020016101d060119054906101000a900462ffffff1662ffffff1681526020016101d0600b9054906101000a900462ffffff1662ffffff1681526020016101d0600e9054906101000a900462ffffff1662ffffff16815250905073d5cc46388c7046fb9770ae1191c14686eaec63c663353fd196858989898d876040518763ffffffff1660e01b815260040161270d96959493929190615786565b60006040518083038186803b15801561272557600080fd5b505af4158015612739573d6000803e3d6000fd5b505050506127443390565b6101c75460018601546040805192835263ffffffff8083166020850152600160201b90920490911682820152516001600160a01b0392909216917fd4f4eda7fb0fd42c44eceae5e61ca3734aa4c9843303a9bed659b38d6872b26a9181900360600190a25050505050505050565b60006127cc600080516020615da583398151915233612aa8565b905090565b6127d9613a6c565b6101c75460009081526101df602052604090206127f533613ac5565b6127fe33613b5c565b600181015460009061281f9063ffffffff600160201b82048116911661555c565b63ffffffff164211801561285257506101c75460009081526101d96020908152604080832033845290915290205460ff16155b1561288c576128603361191a565b6101c75460009081526101d9602090815260408083203384529091529020805460ff1916600117905590505b3360009081526101da60205260408120546128a89083906154af565b90508047101560405180604001604052806002815260200161313360f01b815250906128e75760405162461bcd60e51b8152600401611687919061538f565b503360008181526101da60205260408082208290555190919083908381818185875af1925050503d806000811461293a576040519150601f19603f3d011682016040523d82523d6000602084013e61293f565b606091505b50509050806129605760405162461bcd60e51b815260040161168790615518565b60405182815233907f0ba90eb685b3b0006a3c394dd506a37e5e136aa5340c16793a2d546bd6721b8f9060200160405180910390a2505050506129a3600160c955565b565b600054610100900460ff166129cc5760405162461bcd60e51b8152600401611687906157e5565b6001600160a01b038116612a225760405162461bcd60e51b815260206004820181905260248201527f4f776e65722063616e6e6f7420626520746865207a65726f20616464726573736044820152606401611687565b612a2a613f0c565b612a32613f33565b612a3a613f62565b612a52600080516020615d8583398151915282613f91565b612a6a600080516020615da583398151915282613f91565b612a90600080516020615da5833981519152600080516020615d85833981519152613f9b565b611e9f600080516020615d8583398151915280613f9b565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b612adb612f1e565b612af75760405162461bcd60e51b8152600401611687906153bf565b604080518082019091526002815261313960f01b6020820152600563ffffffff831611612b375760405162461bcd60e51b8152600401611687919061538f565b506101c3805463ffffffff191663ffffffff92909216919091179055565b612b5d612f1e565b612b795760405162461bcd60e51b8152600401611687906153bf565b620186a0612b8d60608301604084016154d8565b612b9d60408401602085016154d8565b612baa60208501856154d8565b612bb491906154f5565b612bbe91906154f5565b62ffffff16111560405180604001604052806002815260200161313160f01b81525090612bfe5760405162461bcd60e51b8152600401611687919061538f565b50612c0c60208201826154d8565b6101c9805462ffffff191662ffffff92909216919091179055612c3560408201602083016154d8565b6101c9805462ffffff9290921663010000000265ffffff00000019909216919091179055612c6960608201604083016154d8565b6101c9805462ffffff928316600160301b0268ffffff000000000000198216811792839055612ca89363010000009093048316929081169116176154f5565b612cba9062ffffff16620186a0615830565b63ffffffff166101cb5550565b612ccf613a6c565b6101c7546101d6546101c3546040516362d764b560e01b8152600481019390935260248301919091526001600160a01b038084166044840152600160281b9091041660648201526101df60848201526101e460a482015273d5cc46388c7046fb9770ae1191c14686eaec63c6906362d764b59060c40160006040518083038186803b158015612d5d57600080fd5b505af4158015612d71573d6000803e3d6000fd5b50505050611e9f600160c955565b60008181526101df602052604081206101c754831115612da25750600092915050565b600a8101546101cf5460009190612dbd90620186a090615453565b612dc79190615488565b6009830154612de29190600160301b900462ffffff166154af565b9050600082600901600201548210612dfe57600b830154612e00565b815b95945050505050565b60008181526101df602052604090206101c75460609190831115612e4d5760408051600180825281830190925290602080830190803683370190505b509392505050565b600081600701546001600160401b03811115612e6b57612e6b61559d565b604051908082528060200260200182016040528015612e94578160200160208202803683370190505b5090508160060154600003612eaa579392505050565b60005b8260070154811015612e455760008581526101dd6020908152604080832084845290915290205482516001600160a01b0390911690839083908110612ef457612ef46154c2565b6001600160a01b039092166020928302919091019091015280612f168161584d565b915050612ead565b60006127cc600080516020615d8583398151915233612aa8565b612f40612f1e565b612f5c5760405162461bcd60e51b8152600401611687906153bf565b6101c38054911515600160201b0264ff0000000019909216919091179055565b612f84613a6c565b612f8d33613ac5565b3360009081526101d760209081526040918290205482518084019093526002835261062760f31b91830191909152612fd85760405162461bcd60e51b8152600401611687919061538f565b503360009081526101d760209081526040808320805493905580518082019091526002815261062760f31b918101919091524782111561302b5760405162461bcd60e51b8152600401611687919061538f565b50604051600090339083908381818185875af1925050503d806000811461306e576040519150601f19603f3d011682016040523d82523d6000602084013e613073565b606091505b50509050806130945760405162461bcd60e51b815260040161168790615518565b50506129a3600160c955565b6130a8612f1e565b6130c45760405162461bcd60e51b8152600401611687906153bf565b60405163430021db60e11b81526002604360981b019063860043b690611811903090859060040161540a565b600054610100900460ff16158080156131105750600054600160ff909116105b8061312a5750303b15801561312a575060005460ff166001145b61318d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611687565b6000805460ff1916600117905580156131b0576000805461ff0019166101001790555b6101e580546001600160a01b03808a166001600160a01b0319928316179092556101e680548984169083161790556101c6805485841692169190911790556101c38054918716600160281b02600160281b600160c81b03199092169190911790556132183390565b6101ea80546001600160a01b03199081166001600160a01b03938416179091556101c4805482168684169081179091556101c580549092169287169290921790556040516336b91f2b60e01b81526336b91f2b9061327a908790600401614cdf565b600060405180830381600087803b15801561329457600080fd5b505af11580156132a8573d6000803e3d6000fd5b505050506002604360981b016001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156132ee57600080fd5b505af1158015613302573d6000803e3d6000fd5b505050506002604360981b016001600160a01b031663f098767a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561334857600080fd5b505af115801561335c573d6000803e3d6000fd5b50505050613368613fe6565b6101c7805460009081526101df6020526040902060018101805463ffffffff19164263ffffffff16179055905481556101cd546006909101556133aa336129a5565b80156133f0576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b613401612f1e565b61341d5760405162461bcd60e51b8152600401611687906153bf565b60405163662aa11d60e01b81526002604360981b019063662aa11d90611811903090859060040161540a565b6101e5546101e654604051631711922960e31b81526000926001600160a01b039081169263b88c9148926134839290911690600401614cdf565b602060405180830381865afa1580156134a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134c49190615866565b6001600160801b0316905090565b6134da612f1e565b6134f65760405162461bcd60e51b8152600401611687906153bf565b6101c75460009081526101df6020526040902060018101546135279063ffffffff600160201b82048116911661555c565b63ffffffff164211806135435750600181015463ffffffff1642105b604051806040016040528060018152602001600d60fa1b8152509061357b5760405162461bcd60e51b8152600401611687919061538f565b508263ffffffff168463ffffffff16111560405180604001604052806002815260200161189b60f11b815250906135c55760405162461bcd60e51b8152600401611687919061538f565b50604080518082019091526002815261031360f41b6020820152876135fd5760405162461bcd60e51b8152600401611687919061538f565b50506101c8949094556101d6929092556101d0805463ffffffff938416600160201b0267ffffffffffffffff1990911693909216929092171790556101cd919091556101d3805462ffffff90921662ffffff19909216919091179055565b60008281526065602052604090206001015461367681613c0a565b61189b8383613c9a565b613688612f1e565b6136a45760405162461bcd60e51b8152600401611687906153bf565b60006136b660808301606084016154d8565b6136c660608401604085016154d8565b6136d660408501602086016154d8565b6136e360208601866154d8565b6136ed91906154f5565b6136f791906154f5565b61370191906154f5565b62ffffff169050620186a063ffffffff16811460405180604001604052806002815260200161313160f01b8152509061374d5760405162461bcd60e51b8152600401611687919061538f565b5061375b60208301836154d8565b6101d0805462ffffff92909216600160701b0262ffffff60701b1990921691909117905561378f60408301602084016154d8565b6101d0805462ffffff92909216600160581b0262ffffff60581b199092169190911790556137c360608301604084016154d8565b6101d0805462ffffff92909216600160881b0262ffffff60881b199092169190911790556137f760808301606084016154d8565b6101d060086101000a81548162ffffff021916908362ffffff1602179055505050565b6101c75460009081526101df6020526040812081806138388561387c565b60018401549091506138599063ffffffff600160201b82048116911661555c565b63ffffffff164211156138725761386f8561191a565b91505b612e0082826154af565b6001600160a01b03811660009081526101e06020908152604080832080548085526101df9093529083206101c754919290911115806138e05750815460009081526101d9602090815260408083206001600160a01b038816845290915290205460ff165b15613904575050506001600160a01b031660009081526101da602052604090205490565b6001600160a01b03841660008181526101da6020908152604080832054865484526101dc83528184209484529390915281205460038401546009850154919291620186a09161395e91600160481b900462ffffff16615453565b6139689190615488565b90506000846006015460001461399c57846006015482866003015461398d919061549c565b6139979190615488565b61399f565b60005b865460009081526101db60205260409020549091506001600160a01b03808a169116036139fc5784600601546000036139ef578185600301546139e2919061549c565b6139ec90856154af565b93505b6139f982856154af565b93505b8215613a6057855460009081526101db60205260409020546001600160a01b0316613a495782856006015483613a329190615488565b613a3c9190615453565b613a4690856154af565b93505b613a538382615453565b613a5d90856154af565b93505b50919695505050505050565b600260c95403613abe5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611687565b600260c955565b6101c354604051632992684f60e01b81526101e060048201526101e160248201526101d7604482015263ffffffff90911660648201526001600160a01b038216608482015273d5cc46388c7046fb9770ae1191c14686eaec63c690632992684f9060a40160006040518083038186803b158015613b4157600080fd5b505af4158015613b55573d6000803e3d6000fd5b5050505050565b6001600160a01b03811660009081526101e0602052604090206101c754815410613b84575050565b805460009081526101d9602090815260408083206001600160a01b038616845290915290205460ff16613bfa57613bba8261387c565b6001600160a01b03831660008181526101da6020908152604080832094909455845482526101d981528382209282529190915220805460ff191660011790555b6101c754905550565b600160c955565b611e9f81336140ca565b613c1e8282612aa8565b6117bd5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff19166001179055613c563390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b613ca48282612aa8565b156117bd5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6101e5546001600160a01b0316336001600160a01b03161460405180604001604052806002815260200161189960f11b81525090613d525760405162461bcd60e51b8152600401611687919061538f565b506101c75460008181526101df602090815260408083206101e38352818420546001600160401b03891685526101e78452828520549585526101e184528285206001600160a01b0390961680865295909352928190206101c35491516310d481af60e11b8152600481018590526024810182905263ffffffff9092166044830152929391929073d5cc46388c7046fb9770ae1191c14686eaec63c6906321a9035e9060640160006040518083038186803b158015613e0f57600080fd5b505af4158015613e23573d6000803e3d6000fd5b50505050613e318482614123565b60048101546000808080613e448a61439c565b93509350935093506000613e5b8b60001c87614467565b90506000613e758662ffffff8087169086168f8e8e61450d565b80516020820151919250906000816003811115613e9457613e946152a5565b03613eaa57613ea488888d614901565b90925090505b60058a0180546002919060ff60401b1916600160401b83021790555082604001516101e360006101c754815260200190815260200160002081905550613efa8b8f60001c6101c754858886614a46565b50505050505050505050505050505050565b600054610100900460ff166129a35760405162461bcd60e51b8152600401611687906157e5565b600054610100900460ff16613f5a5760405162461bcd60e51b8152600401611687906157e5565b6129a3614aa7565b600054610100900460ff16613f895760405162461bcd60e51b8152600401611687906157e5565b6129a3614ada565b6117bd8282613c14565b600082815260656020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b660e35fa931a00006101c88190556101d655600a6101cd556101c38054603c63ffffffff199091161790556101d080546001600160a01b0319166f3a980144380007d0000001a4000001a41790556101c9805468ffffffffffffffffff199081166664003a980005dc17918290556101ce80549091166801117000fde80088b81790556113886101ca556140899062ffffff6301000000909104166105dc6154f5565b61409b9062ffffff16620186a0615830565b63ffffffff166101cb5560056101d48190556101e85560036101d1556101d3805462ffffff19166103e8179055565b6140d48282612aa8565b6117bd576140e181614b01565b6140ec836020614b13565b6040516020016140fd92919061588f565b60408051601f198184030181529082905262461bcd60e51b82526116879160040161538f565b600e820154600c8301546003830154600091620186a0916141449190615453565b61414e9190615488565b6101c354604051919250600091600160281b9091046001600160a01b03169083908381818185875af1925050503d80600081146141a7576040519150601f19603f3d011682016040523d82523d6000602084013e6141ac565b606091505b50509050806141fd5760405162461bcd60e51b815260206004820181905260248201527f4661696c656420746f2073656e6420457468657220746f2074726561737572796044820152606401611687565b6101d4546101e954101561430a5760016101e9600082825461421f91906154af565b90915550506003840154600090620186a09061423c908690615453565b6142469190615488565b6101ea546040519192506001600160a01b0316908290600081818185875af1925050503d8060008114614295576040519150601f19603f3d011682016040523d82523d6000602084013e61429a565b606091505b505080925050816143045760405162461bcd60e51b815260206004820152602e60248201527f4661696c656420746f2073656e64205365656420457468657220746f2070726960448201526d1e99481c1bdbdb081dd85b1b195d60921b6064820152608401611687565b60009350505b600f850154600d860154604051600162beb8ff60e01b031981526004810188905260248101879052604481018690526064810192909252608482015273d5cc46388c7046fb9770ae1191c14686eaec63c69063ff4147019060a40160006040518083038186803b15801561437d57600080fd5b505af4158015614391573d6000803e3d6000fd5b505050505050505050565b6101c75460009081526101df6020526040812060098101548291829182919062ffffff8082169184916143d7916301000000900416836154af565b600a8401546101cf549192506000916143f490620186a090615453565b6143fe9190615488565b60098501546144199190600160301b900462ffffff166154af565b905060008460090160020154821061443557600b850154614437565b815b905061444383826154af565b90506000614454620186a08c6158fe565b9b919a5093985091965090945050505050565b6101c75460009081526101df60205260409081902090516327dba2ff60e11b81526004810184905260248101839052604481018290526060919073d5cc46388c7046fb9770ae1191c14686eaec63c690634fb745fe90606401600060405180830381865af41580156144dd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526145059190810190615912565b949350505050565b60408051606081018252600080825260208201819052918101919091526040805160e0810182526101c75480825260208083018890526101d154838501526101d2546060840152608083018b905260a083018a905260c0830189905260009182526101df9052828120925163108c9e0360e11b815291929091829173d5cc46388c7046fb9770ae1191c14686eaec63c6916321193c06916145ba9187918a918c906101e290600401615b0c565b6040805180830381865af41580156145d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145fa9190615579565b6040805160c0810182526101c7548152602081018e90528082018d9052606081018c9052608081018490526101d35462ffffff1660a08201529051631585364760e31b8152929450909250906000908190819073d5cc46388c7046fb9770ae1191c14686eaec63c69063ac29b238906146819087908d906101df906101db90600401615c94565b606060405180830381865af415801561469e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146c29190615cc8565b9194509250905060028260038111156146dd576146dd6152a5565b036147855760016101cf60008282546146f691906154af565b90915550506101c75460408051918252600160208301526000908201526001600160a01b038a16907fe74013133fb67b03a3cba620837d933f19e9141c42fbf501232300c7f981fc639060600160405180910390a2604051806060016040528084815260200183600381111561476e5761476e6152a5565b8152602001868152509750505050505050506148f7565b60405163d984928f60e01b815273d5cc46388c7046fb9770ae1191c14686eaec63c69063d984928f906147ce9087908d906101df906101dd906101de906101dc90600401615d05565b606060405180830381865af41580156147eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061480f9190615cc8565b91945092509050600382600381111561482a5761482a6152a5565b036148c15760016101cf600082825461484391906154af565b90915550506101d1546101d2541061485e576101d25461486d565b6101d25461486d9060016154af565b6101d2556101c754604080519182526000602083015281018290526001600160a01b038a16907fe74013133fb67b03a3cba620837d933f19e9141c42fbf501232300c7f981fc639060600160405180910390a25b60405180606001604052808481526020018360038111156148e4576148e46152a5565b8152602001868152509750505050505050505b9695505050505050565b6000808362ffffff16851015614a1d576101c7546101cf54604051630633166360e01b8152600481019290925260248201526001600160a01b03841660448201526101df60648201526101da6084820152600090819073d5cc46388c7046fb9770ae1191c14686eaec63c69063063316639060a4016040805180830381865af4158015614992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149b69190615579565b60006101cf556101c7546040805191825260208201839052810183905291935091506001600160a01b038616907f3f88442eb3441ef91803cd74336f2222c81a2d7f987cb61024e76b1b02eeecfb9060600160405180910390a2925060019150614a3e9050565b60016101cf6000828254614a3191906154af565b9091555060009250829150505b935093915050565b806003811115614a5857614a586152a5565b866001600160a01b03167fc338cfe35c3d868fb81af4e8541c0468d009b25f0849de36101d3369ee3667ef87878787604051614a979493929190615d48565b60405180910390a3505050505050565b600054610100900460ff16614ace5760405162461bcd60e51b8152600401611687906157e5565b6097805460ff19169055565b600054610100900460ff16613c035760405162461bcd60e51b8152600401611687906157e5565b606061156b6001600160a01b03831660145b60606000614b22836002615453565b614b2d9060026154af565b6001600160401b03811115614b4457614b4461559d565b6040519080825280601f01601f191660200182016040528015614b6e576020820181803683370190505b509050600360fc1b81600081518110614b8957614b896154c2565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110614bb857614bb86154c2565b60200101906001600160f81b031916908160001a9053506000614bdc846002615453565b614be79060016154af565b90505b6001811115614c5f576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110614c1b57614c1b6154c2565b1a60f81b828281518110614c3157614c316154c2565b60200101906001600160f81b031916908160001a90535060049490941c93614c5881615d6d565b9050614bea565b508315614cae5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401611687565b9392505050565b600060208284031215614cc757600080fd5b81356001600160e01b031981168114614cae57600080fd5b6001600160a01b0391909116815260200190565b80356001600160a01b0381168114614d0a57600080fd5b919050565b60008060408385031215614d2257600080fd5b614d2b83614cf3565b946020939093013593505050565b60008060408385031215614d4c57600080fd5b82359150614d5c60208401614cf3565b90509250929050565b6001600160401b0381168114611e9f57600080fd5b600060208284031215614d8c57600080fd5b8135614cae81614d65565b600060208284031215614da957600080fd5b5035919050565b600060208284031215614dc257600080fd5b614cae82614cf3565b600060608284031215614ddd57600080fd5b82606083011115614ded57600080fd5b50919050565b600080600060608486031215614e0857600080fd5b8335614e1381614d65565b9250614e2160208501614cf3565b9150604084013590509250925092565b60008060408385031215614e4457600080fd5b50508035926020909101359150565b60008060008060808587031215614e6957600080fd5b614e7285614cf3565b9350614e8060208601614cf3565b9250614e8e60408601614cf3565b9150614e9c60608601614cf3565b905092959194509250565b63ffffffff81168114611e9f57600080fd5b600080600060608486031215614ece57600080fd5b8335614ed981614ea7565b95602085013595506040909401359392505050565b805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e083015261010080820151818401525061012080820151818401525061014080820151818401525061016080820151818401525061018080820151614f808285018263ffffffff169052565b50506101a08181015163ffffffff81168483015250506101c08181015163ffffffff81168483015250506101e08181015190830152610200808201519083015261022090810151910152565b60006105c0820190508f825263ffffffff8f16602083015263ffffffff8e16604083015263ffffffff8d1660608301528b60808301528a60a08301528960c08301528860e0830152876101008301528661012083015261507e61014083018762ffffff80825116835280602083015116602084015280604083015116604084015250606081015163ffffffff80821660608501528060808401511660808501528060a08401511660a085015250505050565b845162ffffff9081166102008401526020860151811661022084015260408601518116610240840152606086015181166102608401526080860151811661028084015260a0860151166102a083015260c08501516102c083015260e08501516102e0830152835161030083015260208401516103208301526040840151610340830152606084015161036083015261511a610380830184614eee565b9f9e505050505050505050505050505050565b60006020828403121561513f57600080fd5b8135614cae81614ea7565b6020808252825182820181905260009190848201906040850190845b8181101561518b5783516001600160a01b031683529284019291840191600101615166565b50909695505050505050565b6000602082840312156151a957600080fd5b81358015158114614cae57600080fd5b60008060008060008060c087890312156151d257600080fd5b6151db87614cf3565b95506151e960208801614cf3565b94506151f760408801614cf3565b935061520560608801614cf3565b925061521360808801614cf3565b915061522160a08801614cf3565b90509295509295509295565b62ffffff81168114611e9f57600080fd5b60008060008060008060c0878903121561525757600080fd5b863595506020870135945060408701359350606087013561527781614ea7565b9250608087013561528781614ea7565b915060a08701356152978161522d565b809150509295509295509295565b634e487b7160e01b600052602160045260246000fd5b600060e0820190508882528760208301528660408301528560608301528460808301526001600160401b03841660a08301526003831061530b57634e487b7160e01b600052602160045260246000fd5b8260c083015298975050505050505050565b60006080828403121561532f57600080fd5b82608083011115614ded57600080fd5b60005b8381101561535a578181015183820152602001615342565b50506000910152565b6000815180845261537b81602086016020860161533f565b601f01601f19169290920160200192915050565b602081526000614cae6020830184615363565b6000602082840312156153b457600080fd5b8151614cae81614d65565b6020808252602b908201527f4d75737420686176652061646d696e20726f6c6520746f20706572666f726d2060408201526a3a3434b99030b1ba34b7b760a91b606082015260800190565b6001600160a01b0392831681529116602082015260400190565b60006020828403121561543657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561546d5761546d61543d565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261549757615497615472565b500490565b8181038181111561156b5761156b61543d565b8082018082111561156b5761156b61543d565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156154ea57600080fd5b8135614cae8161522d565b62ffffff8181168382160190808211156155115761551161543d565b5092915050565b60208082526024908201527f4661696c656420746f2073656e6420457468657220746f20626c617374207769604082015263373732b960e11b606082015260800190565b63ffffffff8181168382160190808211156155115761551161543d565b6000806040838503121561558c57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052604160045260246000fd5b60405161024081016001600160401b03811182821017156155d6576155d661559d565b60405290565b8051614d0a81614ea7565b600061024082840312156155fa57600080fd5b6156026155b3565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e082015261010080840151818301525061012080840151818301525061014080840151818301525061016080840151818301525061018061568a8185016155dc565b908201526101a061569c8482016155dc565b908201526101c06156ae8482016155dc565b908201526101e083810151908201526102008084015190820152610220928301519281019290925250919050565b600060c082840312156156ee57600080fd5b60405160c081018181106001600160401b03821117156157105761571061559d565b604052825161571e8161522d565b8152602083015161572e8161522d565b602082015260408301516157418161522d565b6040820152606083015161575481614ea7565b6060820152608083015161576781614ea7565b608082015260a083015161577a81614ea7565b60a08201529392505050565b60006105a0820190508782526020878184015286604084015285606084015263ffffffff8516608084015260a083018460005b60288110156157d6578151835291830191908301906001016157b9565b50505050979650505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b63ffffffff8281168282160390808211156155115761551161543d565b60006001820161585f5761585f61543d565b5060010190565b60006020828403121561587857600080fd5b81516001600160801b0381168114614cae57600080fd5b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516158c181601785016020880161533f565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516158f281602884016020880161533f565b01602801949350505050565b60008261590d5761590d615472565b500690565b60006020828403121561592457600080fd5b81516001600160401b038082111561593b57600080fd5b818401915084601f83011261594f57600080fd5b8151818111156159615761596161559d565b604051601f8201601f19908116603f011681019083821181831017156159895761598961559d565b816040528281528760208487010111156159a257600080fd5b6159b383602083016020880161533f565b979650505050505050565b805462ffffff8082168452808260181c166020850152808260301c166040850152808260481c166060850152615a0060808501828460601c1662ffffff169052565b615a1660a08501828460781c1662ffffff169052565b5050600181015460c08301526002015460e090910152565b8054825260018101546020830152600281015460408301526003810154606083015260048101546080830152600581015460a0830152600681015460c0830152600781015460e083015260088101546101008301526009810154610120830152600a810154610140830152600b810154610160830152600c81015463ffffffff808216610180850152615acf6101a08501828460201c1663ffffffff169052565b615ae76101c08501828460401c1663ffffffff169052565b5050600d8101546101e0830152600e810154610200830152600f015461022090910152565b6107008101818760005b6007811015615b35578151835260209283019290910190600101615b16565b5050506001600160a01b03861660e08301528454610100830152600185015463ffffffff808216610120850152602082901c811661014085015260409190911c8116610160840152600286015461018084015260038601546101a084015260048601546101c084015260058601546101e084015260068601546102008401526007860154610220840152600886015462ffffff808216610240860152601882901c8116610260860152603082901c16610280850152604881901c82166102a0850152606881901c82166102c085015260881c166102e0830152615c1f6103008301600987016159be565b600c850154610400830152600d850154610420830152600e850154610440830152600f850154610460830152615c5c610480830160108701615a2e565b6106c08201939093526106e001529392505050565b8060005b6006811015611d76578151845260209384019390910190600101615c75565b6101208101615ca38287615c71565b6001600160a01b039490941660c082015260e081019290925261010090910152919050565b600080600060608486031215615cdd57600080fd5b83519250602084015160048110615cf357600080fd5b80925050604084015190509250925092565b6101608101615d148289615c71565b6001600160a01b039690961660c082015260e081019490945261010084019290925261012083015261014090910152919050565b8481528360208201528260408201526080606082015260006148f76080830184615363565b600081615d7c57615d7c61543d565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa2646970667358221220d8d037784a19318b8b19324601143d915adb1ac064c74a871d0b79a547729ef764736f6c63430008100033
Deployed Bytecode
0x6080604052600436106104c05760003560e01c80638bed5bd211610274578063bb0c48531161014e578063d731907a116100c6578063e58378bb11610082578063e58378bb1461145f578063e63ab1e914611481578063e7487eb5146114a3578063edcc8461146114df578063f7cb789a146114ff578063f9b3d1ad1461151d57005b8063d731907a14611328578063dce54178146113ac578063e12f3a61146113cc578063e2eb41ff146113ec578063e3ec42c61461141a578063e45ed31e1461143157005b8063cc2a9a5b11610115578063cc2a9a5b1461126f578063cd2002f51461128f578063ced72f87146112af578063d00c9179146112c4578063d0efe3c7146112e8578063d547741f1461130857005b8063bb0c4853146111c0578063c18e8ac8146111d5578063c2d94aec146111fa578063c91360061461121a578063cabb1ae41461125157005b8063a178a472116101ec578063a97223ed116101a8578063a97223ed14611100578063affed0e014611124578063b3cd42541461113b578063b6db75a014611167578063b7a52bfb1461117c578063b80163a9146111a057005b8063a178a47214611026578063a217fddf1461104a578063a2ee631b1461105f578063a420f7b21461108c578063a65d60af146110b0578063a86b11b8146110c757005b8063936c8a511161023b578063936c8a5114610f5a57806399221b2714610f9c5780639b6bb91d14610fbc5780639bbe239114610fdc5780639df6efd214610ff3578063a170dfc91461100657005b80638bed5bd214610ae35780638c65c81f14610afa578063906e3d9f14610ee75780639119ddc514610efe57806391d1485414610f3a57005b806344599e34116103a55780635c975abb1161031d57806370740ac9116102d957806370740ac914610a3157806375715ce714610a4657806379502c5514610a6657806380c2c89714610a875780638183059314610a9e57806387f9798914610abf57005b80635c975abb146109785780635ead5a321461099057806367cabd66146109c957806368e9f954146109e95780636919ed7214610a095780636a8a3b9614610a1c57005b80634dbb78b71161036c5780634dbb78b71461089b5780634f1d7f6e146108bf5780635237fa55146108d657806352a5f1f8146108f65780635312ea8e146109165780635508edf11461093657005b806344599e34146107fc57806346eacf1b1461081957806347ce07cc1461083957806347fb45531461085a5780634b750bd51461087b57005b806322bc2852116104385780632c4106bd116103ff5780632c4106bd146107405780632cc5d624146107575780632f2ff15d1461077757806330858ae21461079757806336568abe146107c55780633de3786a146107e557005b806322bc285214610694578063248a9ca3146106ab578063272b1323146106db5780632a3d5741146106fb5780632bc79c121461071257005b80630ecb3c89116104875780630ecb3c89146105b1578063120aa877146105c457806316cfaa16146105fd5780631aba27301461061e5780631b43987f146106555780631f0f01ef1461067757005b806301ffc9a7146104c9578063085d4883146104fe578063088803b41461052c5780630a1d562f146105645780630e9d0c321461058c57005b366104c757005b005b3480156104d557600080fd5b506104e96104e4366004614cb5565b61153a565b60405190151581526020015b60405180910390f35b34801561050a57600080fd5b506101e65461051f906001600160a01b031681565b6040516104f59190614cdf565b34801561053857600080fd5b506101ce5461055090600160301b900462ffffff1681565b60405162ffffff90911681526020016104f5565b34801561057057600080fd5b506101c35461051f90600160281b90046001600160a01b031681565b34801561059857600080fd5b506105a36101cc5481565b6040519081526020016104f5565b6104c76105bf366004614d0f565b611571565b3480156105d057600080fd5b506105a36105df366004614d39565b6101d860209081526000928352604080842090915290825290205481565b34801561060957600080fd5b506101c45461051f906001600160a01b031681565b34801561062a57600080fd5b5061051f610639366004614d7a565b6101e7602052600090815260409020546001600160a01b031681565b34801561066157600080fd5b506101c3546104e990600160201b900460ff1681565b34801561068357600080fd5b506101d3546105509062ffffff1681565b3480156106a057600080fd5b506105a36101cb5481565b3480156106b757600080fd5b506105a36106c6366004614d97565b60009081526065602052604090206001015490565b3480156106e757600080fd5b506104c76106f6366004614db0565b6117c1565b34801561070757600080fd5b506105a36101d15481565b34801561071e57600080fd5b506105a361072d366004614db0565b6101da6020526000908152604090205481565b34801561074c57600080fd5b506105a36101c85481565b34801561076357600080fd5b506105a3610772366004614d97565b611854565b34801561078357600080fd5b506104c7610792366004614d39565b611876565b3480156107a357600080fd5b506105a36107b2366004614d97565b6101e36020526000908152604090205481565b3480156107d157600080fd5b506104c76107e0366004614d39565b6118a0565b3480156107f157600080fd5b506105a36101cd5481565b34801561080857600080fd5b506101ce546105509062ffffff1681565b34801561082557600080fd5b506105a3610834366004614db0565b61191a565b34801561084557600080fd5b506101e55461051f906001600160a01b031681565b34801561086657600080fd5b506101c55461051f906001600160a01b031681565b34801561088757600080fd5b506104c7610896366004614d97565b611abb565b3480156108a757600080fd5b506101c954610550906301000000900462ffffff1681565b3480156108cb57600080fd5b506105a36101d45481565b3480156108e257600080fd5b506104c76108f1366004614dcb565b611b23565b34801561090257600080fd5b506104c7610911366004614df3565b611ca0565b34801561092257600080fd5b506104c7610931366004614d97565b611d7c565b34801561094257600080fd5b5061051f610951366004614e31565b6101dd6020908152600092835260408084209091529082529020546001600160a01b031681565b34801561098457600080fd5b5060975460ff166104e9565b34801561099c57600080fd5b506105a36109ab366004614d39565b6101dc60209081526000928352604080842090915290825290205481565b3480156109d557600080fd5b506104c76109e4366004614e53565b611ea2565b3480156109f557600080fd5b506104c7610a04366004614eb9565b61202c565b6104c7610a17366004614d97565b612163565b348015610a2857600080fd5b506104e96127b2565b348015610a3d57600080fd5b506104c76127d1565b348015610a5257600080fd5b506104c7610a61366004614db0565b6129a5565b348015610a7257600080fd5b506101c65461051f906001600160a01b031681565b348015610a9357600080fd5b506105a36101ca5481565b348015610aaa57600080fd5b506101ea5461051f906001600160a01b031681565b348015610acb57600080fd5b506101c95461055090600160301b900462ffffff1681565b348015610aef57600080fd5b506105a36101e95481565b348015610b0657600080fd5b50610ecd610b15366004614d97565b6101df6020528060005260406000206000915090508060000154908060010160009054906101000a900463ffffffff16908060010160049054906101000a900463ffffffff16908060010160089054906101000a900463ffffffff1690806002015490806003015490806004015490806005015490806006015490806007015490806008016040518060c00160405290816000820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160039054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160069054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160099054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600d9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160119054906101000a900463ffffffff1663ffffffff1663ffffffff16815250509080600901604051806101000160405290816000820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160039054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160069054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160099054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600c9054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600f9054906101000a900462ffffff1662ffffff1662ffffff168152602001600182015481526020016002820154815250509080600c0160405180608001604052908160008201548152602001600182015481526020016002820154815260200160038201548152505090806010016040518061024001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152602001600782015481526020016008820154815260200160098201548152602001600a8201548152602001600b8201548152602001600c820160009054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600c820160049054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600c820160089054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600d8201548152602001600e8201548152602001600f8201548152505090508e565b6040516104f59e9d9c9b9a99989796959493929190614fcc565b348015610ef357600080fd5b506105a36101cf5481565b348015610f0a57600080fd5b506104e9610f19366004614d39565b6101d960209081526000928352604080842090915290825290205460ff1681565b348015610f4657600080fd5b506104e9610f55366004614d39565b612aa8565b348015610f6657600080fd5b5061051f610f75366004614e31565b6101e26020908152600092835260408084209091529082529020546001600160a01b031681565b348015610fa857600080fd5b506104c7610fb736600461512d565b612ad3565b348015610fc857600080fd5b506104c7610fd7366004614dcb565b612b55565b348015610fe857600080fd5b506105a36101d65481565b6104c7611001366004614db0565b612cc7565b34801561101257600080fd5b506105a3611021366004614d97565b612d7f565b34801561103257600080fd5b506101d05461055090600160581b900462ffffff1681565b34801561105657600080fd5b506105a3600081565b34801561106b57600080fd5b5061107f61107a366004614d97565b612e09565b6040516104f5919061514a565b34801561109857600080fd5b506101d05461055090600160881b900462ffffff1681565b3480156110bc57600080fd5b506105a36101e85481565b3480156110d357600080fd5b506105a36110e2366004614d39565b6101de60209081526000928352604080842090915290825290205481565b34801561110c57600080fd5b506101d05461055090600160401b900462ffffff1681565b34801561113057600080fd5b506105a36101c75481565b34801561114757600080fd5b50611152620186a081565b60405163ffffffff90911681526020016104f5565b34801561117357600080fd5b506104e9612f1e565b34801561118857600080fd5b506101ce54610550906301000000900462ffffff1681565b3480156111ac57600080fd5b506104c76111bb366004615197565b612f38565b3480156111cc57600080fd5b506104c7612f7c565b3480156111e157600080fd5b506101d05461115290600160201b900463ffffffff1681565b34801561120657600080fd5b506104c7611215366004614db0565b6130a0565b34801561122657600080fd5b5061051f611235366004614d97565b6101db602052600090815260409020546001600160a01b031681565b34801561125d57600080fd5b506101c3546111529063ffffffff1681565b34801561127b57600080fd5b506104c761128a3660046151b9565b6130f0565b34801561129b57600080fd5b506104c76112aa366004614db0565b6133f9565b3480156112bb57600080fd5b506105a3613449565b3480156112d057600080fd5b506101d05461055090600160701b900462ffffff1681565b3480156112f457600080fd5b506104c761130336600461523e565b6134d2565b34801561131457600080fd5b506104c7611323366004614d39565b61365b565b34801561133457600080fd5b50611399611343366004614d39565b6101e160209081526000928352604080842090915290825290208054600182015460028301546003840154600485015460059095015493949293919290916001600160401b03811690600160401b900460ff1687565b6040516104f597969594939291906152bb565b3480156113b857600080fd5b506104c76113c736600461531d565b613680565b3480156113d857600080fd5b506105a36113e7366004614db0565b61381a565b3480156113f857600080fd5b506105a3611407366004614db0565b6101e06020526000908152604090205481565b34801561142657600080fd5b506105a36101d25481565b34801561143d57600080fd5b506105a361144c366004614db0565b6101d76020526000908152604090205481565b34801561146b57600080fd5b506105a3600080516020615d8583398151915281565b34801561148d57600080fd5b506105a3600080516020615da583398151915281565b3480156114af57600080fd5b506104e96114be366004614d39565b6101e460209081526000928352604080842090915290825290205460ff1681565b3480156114eb57600080fd5b506105a36114fa366004614db0565b61387c565b34801561150b57600080fd5b506101d0546111529063ffffffff1681565b34801561152957600080fd5b506101c9546105509062ffffff1681565b60006001600160e01b03198216637965db0b60e01b148061156b57506301ffc9a760e01b6001600160e01b03198316145b92915050565b611579613a6c565b6101c75460009081526101df602090815260408083206101e183528184206001600160a01b03871685529092529091206115b284613ac5565b604051638f4fa25160e01b8152600481018390526024810182905273d5cc46388c7046fb9770ae1191c14686eaec63c690638f4fa2519060440160006040518083038186803b15801561160457600080fd5b505af4158015611618573d6000803e3d6000fd5b5050505061162584613b5c565b6101c75460009081526101e4602090815260408083206001600160a01b03881684528252918290205482518084019093526002835261032360f41b9183019190915260ff166116905760405162461bcd60e51b8152600401611687919061538f565b60405180910390fd5b506101c7546101c8546101e6546101e554604051631295edbd60e21b8152600481019490945234602485015260448401929092526001600160a01b038088166064850152908116608484015260a483018490521660c48201526101e760e4820152610104810184905260009073d5cc46388c7046fb9770ae1191c14686eaec63c690634a57b6f49061012401602060405180830381865af4158015611739573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175d91906153a2565b6101c754604080519182526001600160401b03831660208301529192506001600160a01b038716917f5a0920da7c4df7f0e5da0ce23542a31a806ddda495b3f8da7ca95e92ad030dbc910160405180910390a25050506117bd600160c955565b5050565b6117c9612f1e565b6117e55760405162461bcd60e51b8152600401611687906153bf565b604051634aa7d2f760e11b81526002604360981b019063954fa5ee90611811903090859060040161540a565b6020604051808303816000875af1158015611830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117bd9190615424565b6101d5818154811061186557600080fd5b600091825260209091200154905081565b60008281526065602052604090206001015461189181613c0a565b61189b8383613c14565b505050565b6001600160a01b03811633146119105760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401611687565b6117bd8282613c9a565b6101c75460009081526101df602090815260408083206101d983528184206001600160a01b0386168552909252822054829060ff161561195b579392505050565b6101c75460009081526101dc602090815260408083206001600160a01b038816845290915281205460038401546009850154919291620186a0916119aa91600160481b900462ffffff16615453565b6119b49190615488565b9050600084600601546000146119e85784600601548286600301546119d9919061549c565b6119e39190615488565b6119eb565b60005b6101c75460009081526101db60205260409020549091506001600160a01b03808916911603611a4a578460060154600003611a3d57818560030154611a30919061549c565b611a3a90856154af565b93505b611a4782856154af565b93505b8215611ab0576101c75460009081526101db60205260409020546001600160a01b0316611a995782856006015483611a829190615488565b611a8c9190615453565b611a9690856154af565b93505b611aa38382615453565b611aad90856154af565b93505b509195945050505050565b611ac3612f1e565b611adf5760405162461bcd60e51b8152600401611687906153bf565b604080518082019091526002815261313160f01b6020820152620186a0821115611b1c5760405162461bcd60e51b8152600401611687919061538f565b506101ca55565b611b2b612f1e565b611b475760405162461bcd60e51b8152600401611687906153bf565b6000611b5960408301602084016154d8565b611b6660208401846154d8565b611b7091906154f5565b62ffffff169050620186a063ffffffff1681111560405180604001604052806002815260200161313160f01b81525090611bbd5760405162461bcd60e51b8152600401611687919061538f565b50620186a0611bd260608401604085016154d8565b62ffffff16111560405180604001604052806002815260200161313160f01b81525090611c125760405162461bcd60e51b8152600401611687919061538f565b50611c2060208301836154d8565b6101ce805462ffffff191662ffffff92909216919091179055611c4960408301602084016154d8565b6101ce805462ffffff9290921663010000000265ffffff00000019909216919091179055611c7d60608301604084016154d8565b6101ce60066101000a81548162ffffff021916908362ffffff1602179055505050565b6000611cb56101e5546001600160a01b031690565b90506001600160a01b038116611d075760405162461bcd60e51b8152602060048201526017602482015276115b9d1c9bdc1e481859191c995cdcc81b9bdd081cd95d604a1b6044820152606401611687565b336001600160a01b03821614611d6b5760405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920456e74726f70792063616e2063616c6c20746869732066756e637460448201526234b7b760e91b6064820152608401611687565b611d76848484613d01565b50505050565b611d84613a6c565b611d8c612f1e565b611da85760405162461bcd60e51b8152600401611687906153bf565b6101c3546040805180820190915260028152610c4d60f21b602082015290600160201b900460ff16611ded5760405162461bcd60e51b8152600401611687919061538f565b508047101560405180604001604052806002815260200161062760f31b81525090611e2b5760405162461bcd60e51b8152600401611687919061538f565b50604051600090339083908381818185875af1925050503d8060008114611e6e576040519150601f19603f3d011682016040523d82523d6000602084013e611e73565b606091505b5050905080611e945760405162461bcd60e51b815260040161168790615518565b50611e9f600160c955565b50565b611eaa612f1e565b611ec65760405162461bcd60e51b8152600401611687906153bf565b6040805180820190915260018152600360fc1b60208201526001600160a01b038516611f055760405162461bcd60e51b8152600401611687919061538f565b506040805180820190915260018152600360fc1b60208201526001600160a01b038416611f455760405162461bcd60e51b8152600401611687919061538f565b506040805180820190915260018152600360fc1b60208201526001600160a01b038316611f855760405162461bcd60e51b8152600401611687919061538f565b506040805180820190915260018152600360fc1b60208201526001600160a01b038216611fc55760405162461bcd60e51b8152600401611687919061538f565b506101e580546001600160a01b039586166001600160a01b0319918216179091556101e68054948616948216949094179093556101c38054928516600160281b02600160281b600160c81b0319909316929092179091556101ea8054919093169116179055565b612034612f1e565b6120505760405162461bcd60e51b8152600401611687906153bf565b6101c75460009081526101df6020526040902060018101546120819063ffffffff600160201b82048116911661555c565b63ffffffff1642118061209d5750600181015463ffffffff1642105b604051806040016040528060018152602001600d60fa1b815250906120d55760405162461bcd60e51b8152600401611687919061538f565b50604080518082019091526002815261031360f41b602082015263ffffffff85166121135760405162461bcd60e51b8152600401611687919061538f565b50604080518082019091526002815261031360f41b60208201528261214b5760405162461bcd60e51b8152600401611687919061538f565b505063ffffffff9092166101e8556101d4556101d155565b61216b612f1e565b6121875760405162461bcd60e51b8152600401611687906153bf565b6101c75460009081526101df6020526040908190206101d054915163063f43a360e41b81526004810184905263ffffffff9092166024830152604482018190529073d5cc46388c7046fb9770ae1191c14686eaec63c6906363f43a309060640160006040518083038186803b1580156121ff57600080fd5b505af4158015612213573d6000803e3d6000fd5b50506101c7546101e8546101c8546101d05460405163fce0536160e01b8152600481019490945260248401929092526044830152600160581b900462ffffff166064820152608481018490526101db60a48201526000925082915073d5cc46388c7046fb9770ae1191c14686eaec63c69063fce053619060c4016040805180830381865af41580156122a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122cd9190615579565b91509150806000036122e2576101e9546122e5565b60005b6101e98190555060016101c7600082825461230091906154af565b909155505060006101d28190556101c75481526101df60205260408082206101c65482516315cef56d60e11b815292519193926001600160a01b0390911691632b9deada91600480820192610240929091908290030181865afa15801561236b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238f91906155e7565b905060006101c660009054906101000a90046001600160a01b03166001600160a01b031663a8bcf2ab6040518163ffffffff1660e01b815260040160c060405180830381865afa1580156123e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061240b91906156dc565b905060006040518061050001604052806101c75481526020016101d060009054906101000a900463ffffffff1663ffffffff1681526020016101d060049054906101000a900463ffffffff1663ffffffff1681526020016101cd548152602001836000015162ffffff168152602001836020015162ffffff168152602001836040015162ffffff168152602001836060015163ffffffff168152602001836080015163ffffffff1681526020018360a0015163ffffffff1681526020016101c960009054906101000a900462ffffff1662ffffff1681526020016101c960039054906101000a900462ffffff1662ffffff1681526020016101c960069054906101000a900462ffffff1662ffffff1681526020016101ce60009054906101000a900462ffffff1662ffffff1681526020016101ce60039054906101000a900462ffffff1662ffffff1681526020016101ce60069054906101000a900462ffffff1662ffffff1681526020016101ca5481526020016101cb54815260200184600001518152602001846020015181526020018460400151815260200184606001518152602001846080015181526020018460a0015181526020018460c0015181526020018460e001518152602001846101000151815260200184610120015181526020018461014001518152602001846101600151815260200184610180015163ffffffff168152602001846101a0015163ffffffff168152602001846101c0015163ffffffff168152602001846101e001518152602001846102000151815260200184610220015181526020016101d060089054906101000a900462ffffff1662ffffff1681526020016101d060119054906101000a900462ffffff1662ffffff1681526020016101d0600b9054906101000a900462ffffff1662ffffff1681526020016101d0600e9054906101000a900462ffffff1662ffffff16815250905073d5cc46388c7046fb9770ae1191c14686eaec63c663353fd196858989898d876040518763ffffffff1660e01b815260040161270d96959493929190615786565b60006040518083038186803b15801561272557600080fd5b505af4158015612739573d6000803e3d6000fd5b505050506127443390565b6101c75460018601546040805192835263ffffffff8083166020850152600160201b90920490911682820152516001600160a01b0392909216917fd4f4eda7fb0fd42c44eceae5e61ca3734aa4c9843303a9bed659b38d6872b26a9181900360600190a25050505050505050565b60006127cc600080516020615da583398151915233612aa8565b905090565b6127d9613a6c565b6101c75460009081526101df602052604090206127f533613ac5565b6127fe33613b5c565b600181015460009061281f9063ffffffff600160201b82048116911661555c565b63ffffffff164211801561285257506101c75460009081526101d96020908152604080832033845290915290205460ff16155b1561288c576128603361191a565b6101c75460009081526101d9602090815260408083203384529091529020805460ff1916600117905590505b3360009081526101da60205260408120546128a89083906154af565b90508047101560405180604001604052806002815260200161313360f01b815250906128e75760405162461bcd60e51b8152600401611687919061538f565b503360008181526101da60205260408082208290555190919083908381818185875af1925050503d806000811461293a576040519150601f19603f3d011682016040523d82523d6000602084013e61293f565b606091505b50509050806129605760405162461bcd60e51b815260040161168790615518565b60405182815233907f0ba90eb685b3b0006a3c394dd506a37e5e136aa5340c16793a2d546bd6721b8f9060200160405180910390a2505050506129a3600160c955565b565b600054610100900460ff166129cc5760405162461bcd60e51b8152600401611687906157e5565b6001600160a01b038116612a225760405162461bcd60e51b815260206004820181905260248201527f4f776e65722063616e6e6f7420626520746865207a65726f20616464726573736044820152606401611687565b612a2a613f0c565b612a32613f33565b612a3a613f62565b612a52600080516020615d8583398151915282613f91565b612a6a600080516020615da583398151915282613f91565b612a90600080516020615da5833981519152600080516020615d85833981519152613f9b565b611e9f600080516020615d8583398151915280613f9b565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b612adb612f1e565b612af75760405162461bcd60e51b8152600401611687906153bf565b604080518082019091526002815261313960f01b6020820152600563ffffffff831611612b375760405162461bcd60e51b8152600401611687919061538f565b506101c3805463ffffffff191663ffffffff92909216919091179055565b612b5d612f1e565b612b795760405162461bcd60e51b8152600401611687906153bf565b620186a0612b8d60608301604084016154d8565b612b9d60408401602085016154d8565b612baa60208501856154d8565b612bb491906154f5565b612bbe91906154f5565b62ffffff16111560405180604001604052806002815260200161313160f01b81525090612bfe5760405162461bcd60e51b8152600401611687919061538f565b50612c0c60208201826154d8565b6101c9805462ffffff191662ffffff92909216919091179055612c3560408201602083016154d8565b6101c9805462ffffff9290921663010000000265ffffff00000019909216919091179055612c6960608201604083016154d8565b6101c9805462ffffff928316600160301b0268ffffff000000000000198216811792839055612ca89363010000009093048316929081169116176154f5565b612cba9062ffffff16620186a0615830565b63ffffffff166101cb5550565b612ccf613a6c565b6101c7546101d6546101c3546040516362d764b560e01b8152600481019390935260248301919091526001600160a01b038084166044840152600160281b9091041660648201526101df60848201526101e460a482015273d5cc46388c7046fb9770ae1191c14686eaec63c6906362d764b59060c40160006040518083038186803b158015612d5d57600080fd5b505af4158015612d71573d6000803e3d6000fd5b50505050611e9f600160c955565b60008181526101df602052604081206101c754831115612da25750600092915050565b600a8101546101cf5460009190612dbd90620186a090615453565b612dc79190615488565b6009830154612de29190600160301b900462ffffff166154af565b9050600082600901600201548210612dfe57600b830154612e00565b815b95945050505050565b60008181526101df602052604090206101c75460609190831115612e4d5760408051600180825281830190925290602080830190803683370190505b509392505050565b600081600701546001600160401b03811115612e6b57612e6b61559d565b604051908082528060200260200182016040528015612e94578160200160208202803683370190505b5090508160060154600003612eaa579392505050565b60005b8260070154811015612e455760008581526101dd6020908152604080832084845290915290205482516001600160a01b0390911690839083908110612ef457612ef46154c2565b6001600160a01b039092166020928302919091019091015280612f168161584d565b915050612ead565b60006127cc600080516020615d8583398151915233612aa8565b612f40612f1e565b612f5c5760405162461bcd60e51b8152600401611687906153bf565b6101c38054911515600160201b0264ff0000000019909216919091179055565b612f84613a6c565b612f8d33613ac5565b3360009081526101d760209081526040918290205482518084019093526002835261062760f31b91830191909152612fd85760405162461bcd60e51b8152600401611687919061538f565b503360009081526101d760209081526040808320805493905580518082019091526002815261062760f31b918101919091524782111561302b5760405162461bcd60e51b8152600401611687919061538f565b50604051600090339083908381818185875af1925050503d806000811461306e576040519150601f19603f3d011682016040523d82523d6000602084013e613073565b606091505b50509050806130945760405162461bcd60e51b815260040161168790615518565b50506129a3600160c955565b6130a8612f1e565b6130c45760405162461bcd60e51b8152600401611687906153bf565b60405163430021db60e11b81526002604360981b019063860043b690611811903090859060040161540a565b600054610100900460ff16158080156131105750600054600160ff909116105b8061312a5750303b15801561312a575060005460ff166001145b61318d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611687565b6000805460ff1916600117905580156131b0576000805461ff0019166101001790555b6101e580546001600160a01b03808a166001600160a01b0319928316179092556101e680548984169083161790556101c6805485841692169190911790556101c38054918716600160281b02600160281b600160c81b03199092169190911790556132183390565b6101ea80546001600160a01b03199081166001600160a01b03938416179091556101c4805482168684169081179091556101c580549092169287169290921790556040516336b91f2b60e01b81526336b91f2b9061327a908790600401614cdf565b600060405180830381600087803b15801561329457600080fd5b505af11580156132a8573d6000803e3d6000fd5b505050506002604360981b016001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156132ee57600080fd5b505af1158015613302573d6000803e3d6000fd5b505050506002604360981b016001600160a01b031663f098767a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561334857600080fd5b505af115801561335c573d6000803e3d6000fd5b50505050613368613fe6565b6101c7805460009081526101df6020526040902060018101805463ffffffff19164263ffffffff16179055905481556101cd546006909101556133aa336129a5565b80156133f0576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b613401612f1e565b61341d5760405162461bcd60e51b8152600401611687906153bf565b60405163662aa11d60e01b81526002604360981b019063662aa11d90611811903090859060040161540a565b6101e5546101e654604051631711922960e31b81526000926001600160a01b039081169263b88c9148926134839290911690600401614cdf565b602060405180830381865afa1580156134a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134c49190615866565b6001600160801b0316905090565b6134da612f1e565b6134f65760405162461bcd60e51b8152600401611687906153bf565b6101c75460009081526101df6020526040902060018101546135279063ffffffff600160201b82048116911661555c565b63ffffffff164211806135435750600181015463ffffffff1642105b604051806040016040528060018152602001600d60fa1b8152509061357b5760405162461bcd60e51b8152600401611687919061538f565b508263ffffffff168463ffffffff16111560405180604001604052806002815260200161189b60f11b815250906135c55760405162461bcd60e51b8152600401611687919061538f565b50604080518082019091526002815261031360f41b6020820152876135fd5760405162461bcd60e51b8152600401611687919061538f565b50506101c8949094556101d6929092556101d0805463ffffffff938416600160201b0267ffffffffffffffff1990911693909216929092171790556101cd919091556101d3805462ffffff90921662ffffff19909216919091179055565b60008281526065602052604090206001015461367681613c0a565b61189b8383613c9a565b613688612f1e565b6136a45760405162461bcd60e51b8152600401611687906153bf565b60006136b660808301606084016154d8565b6136c660608401604085016154d8565b6136d660408501602086016154d8565b6136e360208601866154d8565b6136ed91906154f5565b6136f791906154f5565b61370191906154f5565b62ffffff169050620186a063ffffffff16811460405180604001604052806002815260200161313160f01b8152509061374d5760405162461bcd60e51b8152600401611687919061538f565b5061375b60208301836154d8565b6101d0805462ffffff92909216600160701b0262ffffff60701b1990921691909117905561378f60408301602084016154d8565b6101d0805462ffffff92909216600160581b0262ffffff60581b199092169190911790556137c360608301604084016154d8565b6101d0805462ffffff92909216600160881b0262ffffff60881b199092169190911790556137f760808301606084016154d8565b6101d060086101000a81548162ffffff021916908362ffffff1602179055505050565b6101c75460009081526101df6020526040812081806138388561387c565b60018401549091506138599063ffffffff600160201b82048116911661555c565b63ffffffff164211156138725761386f8561191a565b91505b612e0082826154af565b6001600160a01b03811660009081526101e06020908152604080832080548085526101df9093529083206101c754919290911115806138e05750815460009081526101d9602090815260408083206001600160a01b038816845290915290205460ff165b15613904575050506001600160a01b031660009081526101da602052604090205490565b6001600160a01b03841660008181526101da6020908152604080832054865484526101dc83528184209484529390915281205460038401546009850154919291620186a09161395e91600160481b900462ffffff16615453565b6139689190615488565b90506000846006015460001461399c57846006015482866003015461398d919061549c565b6139979190615488565b61399f565b60005b865460009081526101db60205260409020549091506001600160a01b03808a169116036139fc5784600601546000036139ef578185600301546139e2919061549c565b6139ec90856154af565b93505b6139f982856154af565b93505b8215613a6057855460009081526101db60205260409020546001600160a01b0316613a495782856006015483613a329190615488565b613a3c9190615453565b613a4690856154af565b93505b613a538382615453565b613a5d90856154af565b93505b50919695505050505050565b600260c95403613abe5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611687565b600260c955565b6101c354604051632992684f60e01b81526101e060048201526101e160248201526101d7604482015263ffffffff90911660648201526001600160a01b038216608482015273d5cc46388c7046fb9770ae1191c14686eaec63c690632992684f9060a40160006040518083038186803b158015613b4157600080fd5b505af4158015613b55573d6000803e3d6000fd5b5050505050565b6001600160a01b03811660009081526101e0602052604090206101c754815410613b84575050565b805460009081526101d9602090815260408083206001600160a01b038616845290915290205460ff16613bfa57613bba8261387c565b6001600160a01b03831660008181526101da6020908152604080832094909455845482526101d981528382209282529190915220805460ff191660011790555b6101c754905550565b600160c955565b611e9f81336140ca565b613c1e8282612aa8565b6117bd5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff19166001179055613c563390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b613ca48282612aa8565b156117bd5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6101e5546001600160a01b0316336001600160a01b03161460405180604001604052806002815260200161189960f11b81525090613d525760405162461bcd60e51b8152600401611687919061538f565b506101c75460008181526101df602090815260408083206101e38352818420546001600160401b03891685526101e78452828520549585526101e184528285206001600160a01b0390961680865295909352928190206101c35491516310d481af60e11b8152600481018590526024810182905263ffffffff9092166044830152929391929073d5cc46388c7046fb9770ae1191c14686eaec63c6906321a9035e9060640160006040518083038186803b158015613e0f57600080fd5b505af4158015613e23573d6000803e3d6000fd5b50505050613e318482614123565b60048101546000808080613e448a61439c565b93509350935093506000613e5b8b60001c87614467565b90506000613e758662ffffff8087169086168f8e8e61450d565b80516020820151919250906000816003811115613e9457613e946152a5565b03613eaa57613ea488888d614901565b90925090505b60058a0180546002919060ff60401b1916600160401b83021790555082604001516101e360006101c754815260200190815260200160002081905550613efa8b8f60001c6101c754858886614a46565b50505050505050505050505050505050565b600054610100900460ff166129a35760405162461bcd60e51b8152600401611687906157e5565b600054610100900460ff16613f5a5760405162461bcd60e51b8152600401611687906157e5565b6129a3614aa7565b600054610100900460ff16613f895760405162461bcd60e51b8152600401611687906157e5565b6129a3614ada565b6117bd8282613c14565b600082815260656020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b660e35fa931a00006101c88190556101d655600a6101cd556101c38054603c63ffffffff199091161790556101d080546001600160a01b0319166f3a980144380007d0000001a4000001a41790556101c9805468ffffffffffffffffff199081166664003a980005dc17918290556101ce80549091166801117000fde80088b81790556113886101ca556140899062ffffff6301000000909104166105dc6154f5565b61409b9062ffffff16620186a0615830565b63ffffffff166101cb5560056101d48190556101e85560036101d1556101d3805462ffffff19166103e8179055565b6140d48282612aa8565b6117bd576140e181614b01565b6140ec836020614b13565b6040516020016140fd92919061588f565b60408051601f198184030181529082905262461bcd60e51b82526116879160040161538f565b600e820154600c8301546003830154600091620186a0916141449190615453565b61414e9190615488565b6101c354604051919250600091600160281b9091046001600160a01b03169083908381818185875af1925050503d80600081146141a7576040519150601f19603f3d011682016040523d82523d6000602084013e6141ac565b606091505b50509050806141fd5760405162461bcd60e51b815260206004820181905260248201527f4661696c656420746f2073656e6420457468657220746f2074726561737572796044820152606401611687565b6101d4546101e954101561430a5760016101e9600082825461421f91906154af565b90915550506003840154600090620186a09061423c908690615453565b6142469190615488565b6101ea546040519192506001600160a01b0316908290600081818185875af1925050503d8060008114614295576040519150601f19603f3d011682016040523d82523d6000602084013e61429a565b606091505b505080925050816143045760405162461bcd60e51b815260206004820152602e60248201527f4661696c656420746f2073656e64205365656420457468657220746f2070726960448201526d1e99481c1bdbdb081dd85b1b195d60921b6064820152608401611687565b60009350505b600f850154600d860154604051600162beb8ff60e01b031981526004810188905260248101879052604481018690526064810192909252608482015273d5cc46388c7046fb9770ae1191c14686eaec63c69063ff4147019060a40160006040518083038186803b15801561437d57600080fd5b505af4158015614391573d6000803e3d6000fd5b505050505050505050565b6101c75460009081526101df6020526040812060098101548291829182919062ffffff8082169184916143d7916301000000900416836154af565b600a8401546101cf549192506000916143f490620186a090615453565b6143fe9190615488565b60098501546144199190600160301b900462ffffff166154af565b905060008460090160020154821061443557600b850154614437565b815b905061444383826154af565b90506000614454620186a08c6158fe565b9b919a5093985091965090945050505050565b6101c75460009081526101df60205260409081902090516327dba2ff60e11b81526004810184905260248101839052604481018290526060919073d5cc46388c7046fb9770ae1191c14686eaec63c690634fb745fe90606401600060405180830381865af41580156144dd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526145059190810190615912565b949350505050565b60408051606081018252600080825260208201819052918101919091526040805160e0810182526101c75480825260208083018890526101d154838501526101d2546060840152608083018b905260a083018a905260c0830189905260009182526101df9052828120925163108c9e0360e11b815291929091829173d5cc46388c7046fb9770ae1191c14686eaec63c6916321193c06916145ba9187918a918c906101e290600401615b0c565b6040805180830381865af41580156145d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145fa9190615579565b6040805160c0810182526101c7548152602081018e90528082018d9052606081018c9052608081018490526101d35462ffffff1660a08201529051631585364760e31b8152929450909250906000908190819073d5cc46388c7046fb9770ae1191c14686eaec63c69063ac29b238906146819087908d906101df906101db90600401615c94565b606060405180830381865af415801561469e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146c29190615cc8565b9194509250905060028260038111156146dd576146dd6152a5565b036147855760016101cf60008282546146f691906154af565b90915550506101c75460408051918252600160208301526000908201526001600160a01b038a16907fe74013133fb67b03a3cba620837d933f19e9141c42fbf501232300c7f981fc639060600160405180910390a2604051806060016040528084815260200183600381111561476e5761476e6152a5565b8152602001868152509750505050505050506148f7565b60405163d984928f60e01b815273d5cc46388c7046fb9770ae1191c14686eaec63c69063d984928f906147ce9087908d906101df906101dd906101de906101dc90600401615d05565b606060405180830381865af41580156147eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061480f9190615cc8565b91945092509050600382600381111561482a5761482a6152a5565b036148c15760016101cf600082825461484391906154af565b90915550506101d1546101d2541061485e576101d25461486d565b6101d25461486d9060016154af565b6101d2556101c754604080519182526000602083015281018290526001600160a01b038a16907fe74013133fb67b03a3cba620837d933f19e9141c42fbf501232300c7f981fc639060600160405180910390a25b60405180606001604052808481526020018360038111156148e4576148e46152a5565b8152602001868152509750505050505050505b9695505050505050565b6000808362ffffff16851015614a1d576101c7546101cf54604051630633166360e01b8152600481019290925260248201526001600160a01b03841660448201526101df60648201526101da6084820152600090819073d5cc46388c7046fb9770ae1191c14686eaec63c69063063316639060a4016040805180830381865af4158015614992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149b69190615579565b60006101cf556101c7546040805191825260208201839052810183905291935091506001600160a01b038616907f3f88442eb3441ef91803cd74336f2222c81a2d7f987cb61024e76b1b02eeecfb9060600160405180910390a2925060019150614a3e9050565b60016101cf6000828254614a3191906154af565b9091555060009250829150505b935093915050565b806003811115614a5857614a586152a5565b866001600160a01b03167fc338cfe35c3d868fb81af4e8541c0468d009b25f0849de36101d3369ee3667ef87878787604051614a979493929190615d48565b60405180910390a3505050505050565b600054610100900460ff16614ace5760405162461bcd60e51b8152600401611687906157e5565b6097805460ff19169055565b600054610100900460ff16613c035760405162461bcd60e51b8152600401611687906157e5565b606061156b6001600160a01b03831660145b60606000614b22836002615453565b614b2d9060026154af565b6001600160401b03811115614b4457614b4461559d565b6040519080825280601f01601f191660200182016040528015614b6e576020820181803683370190505b509050600360fc1b81600081518110614b8957614b896154c2565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110614bb857614bb86154c2565b60200101906001600160f81b031916908160001a9053506000614bdc846002615453565b614be79060016154af565b90505b6001811115614c5f576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110614c1b57614c1b6154c2565b1a60f81b828281518110614c3157614c316154c2565b60200101906001600160f81b031916908160001a90535060049490941c93614c5881615d6d565b9050614bea565b508315614cae5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401611687565b9392505050565b600060208284031215614cc757600080fd5b81356001600160e01b031981168114614cae57600080fd5b6001600160a01b0391909116815260200190565b80356001600160a01b0381168114614d0a57600080fd5b919050565b60008060408385031215614d2257600080fd5b614d2b83614cf3565b946020939093013593505050565b60008060408385031215614d4c57600080fd5b82359150614d5c60208401614cf3565b90509250929050565b6001600160401b0381168114611e9f57600080fd5b600060208284031215614d8c57600080fd5b8135614cae81614d65565b600060208284031215614da957600080fd5b5035919050565b600060208284031215614dc257600080fd5b614cae82614cf3565b600060608284031215614ddd57600080fd5b82606083011115614ded57600080fd5b50919050565b600080600060608486031215614e0857600080fd5b8335614e1381614d65565b9250614e2160208501614cf3565b9150604084013590509250925092565b60008060408385031215614e4457600080fd5b50508035926020909101359150565b60008060008060808587031215614e6957600080fd5b614e7285614cf3565b9350614e8060208601614cf3565b9250614e8e60408601614cf3565b9150614e9c60608601614cf3565b905092959194509250565b63ffffffff81168114611e9f57600080fd5b600080600060608486031215614ece57600080fd5b8335614ed981614ea7565b95602085013595506040909401359392505050565b805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e083015261010080820151818401525061012080820151818401525061014080820151818401525061016080820151818401525061018080820151614f808285018263ffffffff169052565b50506101a08181015163ffffffff81168483015250506101c08181015163ffffffff81168483015250506101e08181015190830152610200808201519083015261022090810151910152565b60006105c0820190508f825263ffffffff8f16602083015263ffffffff8e16604083015263ffffffff8d1660608301528b60808301528a60a08301528960c08301528860e0830152876101008301528661012083015261507e61014083018762ffffff80825116835280602083015116602084015280604083015116604084015250606081015163ffffffff80821660608501528060808401511660808501528060a08401511660a085015250505050565b845162ffffff9081166102008401526020860151811661022084015260408601518116610240840152606086015181166102608401526080860151811661028084015260a0860151166102a083015260c08501516102c083015260e08501516102e0830152835161030083015260208401516103208301526040840151610340830152606084015161036083015261511a610380830184614eee565b9f9e505050505050505050505050505050565b60006020828403121561513f57600080fd5b8135614cae81614ea7565b6020808252825182820181905260009190848201906040850190845b8181101561518b5783516001600160a01b031683529284019291840191600101615166565b50909695505050505050565b6000602082840312156151a957600080fd5b81358015158114614cae57600080fd5b60008060008060008060c087890312156151d257600080fd5b6151db87614cf3565b95506151e960208801614cf3565b94506151f760408801614cf3565b935061520560608801614cf3565b925061521360808801614cf3565b915061522160a08801614cf3565b90509295509295509295565b62ffffff81168114611e9f57600080fd5b60008060008060008060c0878903121561525757600080fd5b863595506020870135945060408701359350606087013561527781614ea7565b9250608087013561528781614ea7565b915060a08701356152978161522d565b809150509295509295509295565b634e487b7160e01b600052602160045260246000fd5b600060e0820190508882528760208301528660408301528560608301528460808301526001600160401b03841660a08301526003831061530b57634e487b7160e01b600052602160045260246000fd5b8260c083015298975050505050505050565b60006080828403121561532f57600080fd5b82608083011115614ded57600080fd5b60005b8381101561535a578181015183820152602001615342565b50506000910152565b6000815180845261537b81602086016020860161533f565b601f01601f19169290920160200192915050565b602081526000614cae6020830184615363565b6000602082840312156153b457600080fd5b8151614cae81614d65565b6020808252602b908201527f4d75737420686176652061646d696e20726f6c6520746f20706572666f726d2060408201526a3a3434b99030b1ba34b7b760a91b606082015260800190565b6001600160a01b0392831681529116602082015260400190565b60006020828403121561543657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561546d5761546d61543d565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261549757615497615472565b500490565b8181038181111561156b5761156b61543d565b8082018082111561156b5761156b61543d565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156154ea57600080fd5b8135614cae8161522d565b62ffffff8181168382160190808211156155115761551161543d565b5092915050565b60208082526024908201527f4661696c656420746f2073656e6420457468657220746f20626c617374207769604082015263373732b960e11b606082015260800190565b63ffffffff8181168382160190808211156155115761551161543d565b6000806040838503121561558c57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052604160045260246000fd5b60405161024081016001600160401b03811182821017156155d6576155d661559d565b60405290565b8051614d0a81614ea7565b600061024082840312156155fa57600080fd5b6156026155b3565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e082015261010080840151818301525061012080840151818301525061014080840151818301525061016080840151818301525061018061568a8185016155dc565b908201526101a061569c8482016155dc565b908201526101c06156ae8482016155dc565b908201526101e083810151908201526102008084015190820152610220928301519281019290925250919050565b600060c082840312156156ee57600080fd5b60405160c081018181106001600160401b03821117156157105761571061559d565b604052825161571e8161522d565b8152602083015161572e8161522d565b602082015260408301516157418161522d565b6040820152606083015161575481614ea7565b6060820152608083015161576781614ea7565b608082015260a083015161577a81614ea7565b60a08201529392505050565b60006105a0820190508782526020878184015286604084015285606084015263ffffffff8516608084015260a083018460005b60288110156157d6578151835291830191908301906001016157b9565b50505050979650505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b63ffffffff8281168282160390808211156155115761551161543d565b60006001820161585f5761585f61543d565b5060010190565b60006020828403121561587857600080fd5b81516001600160801b0381168114614cae57600080fd5b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516158c181601785016020880161533f565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516158f281602884016020880161533f565b01602801949350505050565b60008261590d5761590d615472565b500690565b60006020828403121561592457600080fd5b81516001600160401b038082111561593b57600080fd5b818401915084601f83011261594f57600080fd5b8151818111156159615761596161559d565b604051601f8201601f19908116603f011681019083821181831017156159895761598961559d565b816040528281528760208487010111156159a257600080fd5b6159b383602083016020880161533f565b979650505050505050565b805462ffffff8082168452808260181c166020850152808260301c166040850152808260481c166060850152615a0060808501828460601c1662ffffff169052565b615a1660a08501828460781c1662ffffff169052565b5050600181015460c08301526002015460e090910152565b8054825260018101546020830152600281015460408301526003810154606083015260048101546080830152600581015460a0830152600681015460c0830152600781015460e083015260088101546101008301526009810154610120830152600a810154610140830152600b810154610160830152600c81015463ffffffff808216610180850152615acf6101a08501828460201c1663ffffffff169052565b615ae76101c08501828460401c1663ffffffff169052565b5050600d8101546101e0830152600e810154610200830152600f015461022090910152565b6107008101818760005b6007811015615b35578151835260209283019290910190600101615b16565b5050506001600160a01b03861660e08301528454610100830152600185015463ffffffff808216610120850152602082901c811661014085015260409190911c8116610160840152600286015461018084015260038601546101a084015260048601546101c084015260058601546101e084015260068601546102008401526007860154610220840152600886015462ffffff808216610240860152601882901c8116610260860152603082901c16610280850152604881901c82166102a0850152606881901c82166102c085015260881c166102e0830152615c1f6103008301600987016159be565b600c850154610400830152600d850154610420830152600e850154610440830152600f850154610460830152615c5c610480830160108701615a2e565b6106c08201939093526106e001529392505050565b8060005b6006811015611d76578151845260209384019390910190600101615c75565b6101208101615ca38287615c71565b6001600160a01b039490941660c082015260e081019290925261010090910152919050565b600080600060608486031215615cdd57600080fd5b83519250602084015160048110615cf357600080fd5b80925050604084015190509250925092565b6101608101615d148289615c71565b6001600160a01b039690961660c082015260e081019490945261010084019290925261012083015261014090910152919050565b8481528360208201528260408201526080606082015260006148f76080830184615363565b600081615d7c57615d7c61543d565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa2646970667358221220d8d037784a19318b8b19324601143d915adb1ac064c74a871d0b79a547729ef764736f6c63430008100033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.