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,
address _owner,
address _admin,
address _operator
) external initializer {
entropy = IEntropy(_entropy);
provider = _provider;
config = IBTBConfig(_config);
ballTreasury = payable(_ballTreasury);
adminAddr = payable(_admin);
BlastPointsAddress = _BlastPointsAddress;
pointsOperator = _pointsOperator;
IBlastPoints(BlastPointsAddress).configurePointsOperator(_pointsOperator);
IBlast(0x4300000000000000000000000000000000000002).configureClaimableGas();
IBlast(0x4300000000000000000000000000000000000002).configureClaimableYield();
_initVariables_();
_initEmptyRound_();
__Base_init(_owner, _admin, _operator);
}
// ============================== 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
*/
function updateSystemAddress(
address _entropy,
address _provider,
address _newTreasury
) 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);
entropy = IEntropy(_entropy);
provider = _provider;
ballTreasury = payable(_newTreasury);
// 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(_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 onlyOperator {
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 onlyOwner {
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 onlyOwner {
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");
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_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, address admin, address operator) 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, admin);
_setupRole(OPERATOR_ROLE, operator);
_setupRole(ADMIN_ROLE, admin);
_setRoleAdmin(PAUSER_ROLE, OWNER_ROLE);
_setRoleAdmin(OPERATOR_ROLE, OWNER_ROLE);
_setRoleAdmin(ADMIN_ROLE, OWNER_ROLE);
_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);
}
function isOperator() public view returns (bool) {
return hasRole(OPERATOR_ROLE, _msgSender());
}
function isAdmin() public view returns (bool) {
return hasRole(ADMIN_ROLE, _msgSender());
}
function isOwner() public view returns (bool) {
return hasRole(OWNER_ROLE, _msgSender());
}
modifier onlyOperator() {
require(isOperator(), "Must have operator role to perform this action");
_;
}
modifier onlyAdmin() {
require(isAdmin(), "Must have admin role to perform this action");
_;
}
modifier onlyOwner() {
require(isOwner(), "Must have owner 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": "0xc7a19772216604277a629d0642826360c0541ae6"
}
}
}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":"ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"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":"OPERATOR_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"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"operator","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"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOwner","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"}],"name":"updateSystemAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b615f5280620000f36000396000f3fe6080604052600436106104e15760003560e01c80638c65c81f1161027f578063bb0c485311610159578063e12f3a61116100c6578063e7487eb511610082578063e7487eb5146114db578063edcc846114611517578063f5b541a614611537578063f5e95acb14611559578063f7cb789a14611579578063f9b3d1ad1461159757005b8063e12f3a6114611404578063e2eb41ff14611424578063e3ec42c614611452578063e45ed31e14611469578063e58378bb14611497578063e63ab1e9146114b957005b8063ced72f8711610115578063ced72f87146112e7578063d00c9179146112fc578063d0efe3c714611320578063d547741f14611340578063d731907a14611360578063dce54178146113e457005b8063bb0c485314611218578063c18e8ac81461122d578063c2d94aec14611252578063c913600614611272578063cabb1ae4146112a9578063cd2002f5146112c757005b8063a178a472116101f7578063a97223ed116101b3578063a97223ed14611158578063affed0e01461117c578063b3cd425414611193578063b6db75a0146111bf578063b7a52bfb146111d4578063b80163a9146111f857005b8063a178a4721461107e578063a217fddf146110a2578063a2ee631b146110b7578063a420f7b2146110e4578063a65d60af14611108578063a86b11b81461111f57005b8063936c8a5111610246578063936c8a5114610fb257806399221b2714610ff45780639b6bb91d146110145780639bbe2391146110345780639df6efd21461104b578063a170dfc91461105e57005b80638c65c81f14610b3d5780638f32d59b14610f2a578063906e3d9f14610f3f5780639119ddc514610f5657806391d1485414610f9257005b80634456eda2116103bb5780635c975abb1161032857806379502c55116102e457806379502c5514610a895780637d7e58f514610aaa57806380c2c89714610aca5780638183059314610ae157806387f9798914610b025780638bed5bd214610b2657005b80635c975abb146109ce5780635ead5a32146109e657806368e9f95414610a1f5780636919ed7214610a3f57806370740ac914610a5257806375b238fc14610a6757005b80634dbb78b7116103775780634dbb78b7146108f15780634f1d7f6e146109155780635237fa551461092c57806352a5f1f81461094c5780635312ea8e1461096c5780635508edf11461098c57005b80634456eda21461083d57806344599e341461085257806346eacf1b1461086f57806347ce07cc1461088f57806347fb4553146108b05780634b750bd5146108d157005b80631f0f01ef116104595780632c4106bd116104155780632c4106bd146107815780632cc5d624146107985780632f2ff15d146107b857806330858ae2146107d857806336568abe146108065780633de3786a1461082657005b80631f0f01ef146106b857806322bc2852146106d5578063248a9ca3146106ec578063272b13231461071c5780632a3d57411461073c5780632bc79c121461075357005b80630e9d0c32116104a85780630e9d0c32146105cd5780630ecb3c89146105f2578063120aa8771461060557806316cfaa161461063e5780631aba27301461065f5780631b43987f1461069657005b806301ffc9a7146104ea5780630621b8381461051f578063085d48831461053f578063088803b41461056d5780630a1d562f146105a557005b366104e857005b005b3480156104f657600080fd5b5061050a610505366004614d5f565b6115b4565b60405190151581526020015b60405180910390f35b34801561052b57600080fd5b506104e861053a366004614da5565b6115eb565b34801561054b57600080fd5b506101e654610560906001600160a01b031681565b6040516105169190614de8565b34801561057957600080fd5b506101ce5461059190600160301b900462ffffff1681565b60405162ffffff9091168152602001610516565b3480156105b157600080fd5b506101c35461056090600160281b90046001600160a01b031681565b3480156105d957600080fd5b506105e46101cc5481565b604051908152602001610516565b6104e8610600366004614dfc565b611778565b34801561061157600080fd5b506105e4610620366004614e26565b6101d860209081526000928352604080842090915290825290205481565b34801561064a57600080fd5b506101c454610560906001600160a01b031681565b34801561066b57600080fd5b5061056061067a366004614e67565b6101e7602052600090815260409020546001600160a01b031681565b3480156106a257600080fd5b506101c35461050a90600160201b900460ff1681565b3480156106c457600080fd5b506101d3546105919062ffffff1681565b3480156106e157600080fd5b506105e46101cb5481565b3480156106f857600080fd5b506105e4610707366004614e84565b60009081526065602052604090206001015490565b34801561072857600080fd5b506104e8610737366004614e9d565b6119bf565b34801561074857600080fd5b506105e46101d15481565b34801561075f57600080fd5b506105e461076e366004614e9d565b6101da6020526000908152604090205481565b34801561078d57600080fd5b506105e46101c85481565b3480156107a457600080fd5b506105e46107b3366004614e84565b611a52565b3480156107c457600080fd5b506104e86107d3366004614e26565b611a74565b3480156107e457600080fd5b506105e46107f3366004614e84565b6101e36020526000908152604090205481565b34801561081257600080fd5b506104e8610821366004614e26565b611a99565b34801561083257600080fd5b506105e46101cd5481565b34801561084957600080fd5b5061050a611b13565b34801561085e57600080fd5b506101ce546105919062ffffff1681565b34801561087b57600080fd5b506105e461088a366004614e9d565b611b32565b34801561089b57600080fd5b506101e554610560906001600160a01b031681565b3480156108bc57600080fd5b506101c554610560906001600160a01b031681565b3480156108dd57600080fd5b506104e86108ec366004614e84565b611cd3565b3480156108fd57600080fd5b506101c954610591906301000000900462ffffff1681565b34801561092157600080fd5b506105e46101d45481565b34801561093857600080fd5b506104e8610947366004614eb8565b611d3b565b34801561095857600080fd5b506104e8610967366004614ee0565b611eb8565b34801561097857600080fd5b506104e8610987366004614e84565b611f94565b34801561099857600080fd5b506105606109a7366004614f1e565b6101dd6020908152600092835260408084209091529082529020546001600160a01b031681565b3480156109da57600080fd5b5060975460ff1661050a565b3480156109f257600080fd5b506105e4610a01366004614e26565b6101dc60209081526000928352604080842090915290825290205481565b348015610a2b57600080fd5b506104e8610a3a366004614f52565b6120ba565b6104e8610a4d366004614e84565b6121b3565b348015610a5e57600080fd5b506104e8612849565b348015610a7357600080fd5b506105e4600080516020615efd83398151915281565b348015610a9557600080fd5b506101c654610560906001600160a01b031681565b348015610ab657600080fd5b506104e8610ac5366004614da5565b612a1d565b348015610ad657600080fd5b506105e46101ca5481565b348015610aed57600080fd5b506101ea54610560906001600160a01b031681565b348015610b0e57600080fd5b506101c95461059190600160301b900462ffffff1681565b348015610b3257600080fd5b506105e46101e95481565b348015610b4957600080fd5b50610f10610b58366004614e84565b6101df6020528060005260406000206000915090508060000154908060010160009054906101000a900463ffffffff16908060010160049054906101000a900463ffffffff16908060010160089054906101000a900463ffffffff1690806002015490806003015490806004015490806005015490806006015490806007015490806008016040518060c00160405290816000820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160039054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160069054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160099054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600d9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160119054906101000a900463ffffffff1663ffffffff1663ffffffff16815250509080600901604051806101000160405290816000820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160039054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160069054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160099054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600c9054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600f9054906101000a900462ffffff1662ffffff1662ffffff168152602001600182015481526020016002820154815250509080600c0160405180608001604052908160008201548152602001600182015481526020016002820154815260200160038201548152505090806010016040518061024001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152602001600782015481526020016008820154815260200160098201548152602001600a8201548152602001600b8201548152602001600c820160009054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600c820160049054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600c820160089054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600d8201548152602001600e8201548152602001600f8201548152505090508e565b6040516105169e9d9c9b9a99989796959493929190615065565b348015610f3657600080fd5b5061050a612b57565b348015610f4b57600080fd5b506105e46101cf5481565b348015610f6257600080fd5b5061050a610f71366004614e26565b6101d960209081526000928352604080842090915290825290205460ff1681565b348015610f9e57600080fd5b5061050a610fad366004614e26565b612b6d565b348015610fbe57600080fd5b50610560610fcd366004614f1e565b6101e26020908152600092835260408084209091529082529020546001600160a01b031681565b34801561100057600080fd5b506104e861100f3660046151c6565b612b98565b34801561102057600080fd5b506104e861102f366004614eb8565b612c1a565b34801561104057600080fd5b506105e46101d65481565b6104e8611059366004614e9d565b612d8c565b34801561106a57600080fd5b506105e4611079366004614e84565b612e44565b34801561108a57600080fd5b506101d05461059190600160581b900462ffffff1681565b3480156110ae57600080fd5b506105e4600081565b3480156110c357600080fd5b506110d76110d2366004614e84565b612ece565b60405161051691906151e3565b3480156110f057600080fd5b506101d05461059190600160881b900462ffffff1681565b34801561111457600080fd5b506105e46101e85481565b34801561112b57600080fd5b506105e461113a366004614e26565b6101de60209081526000928352604080842090915290825290205481565b34801561116457600080fd5b506101d05461059190600160401b900462ffffff1681565b34801561118857600080fd5b506105e46101c75481565b34801561119f57600080fd5b506111aa620186a081565b60405163ffffffff9091168152602001610516565b3480156111cb57600080fd5b5061050a612fe3565b3480156111e057600080fd5b506101ce54610591906301000000900462ffffff1681565b34801561120457600080fd5b506104e8611213366004615230565b612ffd565b34801561122457600080fd5b506104e8613041565b34801561123957600080fd5b506101d0546111aa90600160201b900463ffffffff1681565b34801561125e57600080fd5b506104e861126d366004614e9d565b613165565b34801561127e57600080fd5b5061056061128d366004614e84565b6101db602052600090815260409020546001600160a01b031681565b3480156112b557600080fd5b506101c3546111aa9063ffffffff1681565b3480156112d357600080fd5b506104e86112e2366004614e9d565b6131b5565b3480156112f357600080fd5b506105e4613205565b34801561130857600080fd5b506101d05461059190600160701b900462ffffff1681565b34801561132c57600080fd5b506104e861133b366004615263565b61328e565b34801561134c57600080fd5b506104e861135b366004614e26565b613417565b34801561136c57600080fd5b506113d161137b366004614e26565b6101e160209081526000928352604080842090915290825290208054600182015460028301546003840154600485015460059095015493949293919290916001600160401b03811690600160401b900460ff1687565b60405161051697969594939291906152e0565b3480156113f057600080fd5b506104e86113ff366004615342565b61343c565b34801561141057600080fd5b506105e461141f366004614e9d565b6135d6565b34801561143057600080fd5b506105e461143f366004614e9d565b6101e06020526000908152604090205481565b34801561145e57600080fd5b506105e46101d25481565b34801561147557600080fd5b506105e4611484366004614e9d565b6101d76020526000908152604090205481565b3480156114a357600080fd5b506105e4600080516020615e9d83398151915281565b3480156114c557600080fd5b506105e4600080516020615edd83398151915281565b3480156114e757600080fd5b5061050a6114f6366004614e26565b6101e460209081526000928352604080842090915290825290205460ff1681565b34801561152357600080fd5b506105e4611532366004614e9d565b613638565b34801561154357600080fd5b506105e4600080516020615ebd83398151915281565b34801561156557600080fd5b506104e8611574366004615364565b613828565b34801561158557600080fd5b506101d0546111aa9063ffffffff1681565b3480156115a357600080fd5b506101c9546105919062ffffff1681565b60006001600160e01b03198216637965db0b60e01b14806115e557506301ffc9a760e01b6001600160e01b03198316145b92915050565b600054610100900460ff1661161b5760405162461bcd60e51b81526004016116129061540c565b60405180910390fd5b6001600160a01b0383166116715760405162461bcd60e51b815260206004820181905260248201527f4f776e65722063616e6e6f7420626520746865207a65726f20616464726573736044820152606401611612565b611679613b16565b611681613b3d565b611689613b6c565b6116a1600080516020615e9d83398151915284613b9b565b6116b9600080516020615edd83398151915283613b9b565b6116d1600080516020615ebd83398151915282613b9b565b6116e9600080516020615efd83398151915283613b9b565b61170f600080516020615edd833981519152600080516020615e9d833981519152613ba5565b611735600080516020615ebd833981519152600080516020615e9d833981519152613ba5565b61175b600080516020615efd833981519152600080516020615e9d833981519152613ba5565b611773600080516020615e9d83398151915280613ba5565b505050565b611780613bf0565b6101c75460009081526101df602090815260408083206101e183528184206001600160a01b03871685529092529091206117b984613c49565b604051638f4fa25160e01b8152600481018390526024810182905273c7a19772216604277a629d0642826360c0541ae690638f4fa2519060440160006040518083038186803b15801561180b57600080fd5b505af415801561181f573d6000803e3d6000fd5b5050505061182c84613ce0565b6101c75460009081526101e4602090815260408083206001600160a01b03881684528252918290205482518084019093526002835261032360f41b9183019190915260ff1661188e5760405162461bcd60e51b815260040161161291906154a7565b506101c7546101c8546101e6546101e554604051631295edbd60e21b8152600481019490945234602485015260448401929092526001600160a01b038088166064850152908116608484015260a483018490521660c48201526101e760e4820152610104810184905260009073c7a19772216604277a629d0642826360c0541ae690634a57b6f49061012401602060405180830381865af4158015611937573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195b91906154ba565b6101c754604080519182526001600160401b03831660208301529192506001600160a01b038716917f5a0920da7c4df7f0e5da0ce23542a31a806ddda495b3f8da7ca95e92ad030dbc910160405180910390a25050506119bb600160c955565b5050565b6119c7612fe3565b6119e35760405162461bcd60e51b8152600401611612906154d7565b604051634aa7d2f760e11b81526002604360981b019063954fa5ee90611a0f9030908590600401615522565b6020604051808303816000875af1158015611a2e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119bb919061553c565b6101d58181548110611a6357600080fd5b600091825260209091200154905081565b600082815260656020526040902060010154611a8f81613d8e565b6117738383613d98565b6001600160a01b0381163314611b095760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401611612565b6119bb8282613e1e565b6000611b2d600080516020615ebd83398151915233612b6d565b905090565b6101c75460009081526101df602090815260408083206101d983528184206001600160a01b0386168552909252822054829060ff1615611b73579392505050565b6101c75460009081526101dc602090815260408083206001600160a01b038816845290915281205460038401546009850154919291620186a091611bc291600160481b900462ffffff1661556b565b611bcc91906155a0565b905060008460060154600014611c00578460060154828660030154611bf191906155b4565b611bfb91906155a0565b611c03565b60005b6101c75460009081526101db60205260409020549091506001600160a01b03808916911603611c62578460060154600003611c5557818560030154611c4891906155b4565b611c5290856155c7565b93505b611c5f82856155c7565b93505b8215611cc8576101c75460009081526101db60205260409020546001600160a01b0316611cb15782856006015483611c9a91906155a0565b611ca4919061556b565b611cae90856155c7565b93505b611cbb838261556b565b611cc590856155c7565b93505b509195945050505050565b611cdb612fe3565b611cf75760405162461bcd60e51b8152600401611612906154d7565b604080518082019091526002815261313160f01b6020820152620186a0821115611d345760405162461bcd60e51b815260040161161291906154a7565b506101ca55565b611d43612fe3565b611d5f5760405162461bcd60e51b8152600401611612906154d7565b6000611d7160408301602084016155f0565b611d7e60208401846155f0565b611d88919061560d565b62ffffff169050620186a063ffffffff1681111560405180604001604052806002815260200161313160f01b81525090611dd55760405162461bcd60e51b815260040161161291906154a7565b50620186a0611dea60608401604085016155f0565b62ffffff16111560405180604001604052806002815260200161313160f01b81525090611e2a5760405162461bcd60e51b815260040161161291906154a7565b50611e3860208301836155f0565b6101ce805462ffffff191662ffffff92909216919091179055611e6160408301602084016155f0565b6101ce805462ffffff9290921663010000000265ffffff00000019909216919091179055611e9560608301604084016155f0565b6101ce60066101000a81548162ffffff021916908362ffffff1602179055505050565b6000611ecd6101e5546001600160a01b031690565b90506001600160a01b038116611f1f5760405162461bcd60e51b8152602060048201526017602482015276115b9d1c9bdc1e481859191c995cdcc81b9bdd081cd95d604a1b6044820152606401611612565b336001600160a01b03821614611f835760405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920456e74726f70792063616e2063616c6c20746869732066756e637460448201526234b7b760e91b6064820152608401611612565b611f8e848484613e85565b50505050565b611f9c613bf0565b611fa4612b57565b611fc05760405162461bcd60e51b815260040161161290615630565b6101c3546040805180820190915260028152610c4d60f21b602082015290600160201b900460ff166120055760405162461bcd60e51b815260040161161291906154a7565b508047101560405180604001604052806002815260200161062760f31b815250906120435760405162461bcd60e51b815260040161161291906154a7565b50604051600090339083908381818185875af1925050503d8060008114612086576040519150601f19603f3d011682016040523d82523d6000602084013e61208b565b606091505b50509050806120ac5760405162461bcd60e51b81526004016116129061567b565b506120b7600160c955565b50565b6120c2612fe3565b6120de5760405162461bcd60e51b8152600401611612906154d7565b6101c75460009081526101df60205260409020600181015461210f9063ffffffff600160201b8204811691166156bf565b63ffffffff1642118061212b5750600181015463ffffffff1642105b604051806040016040528060018152602001600d60fa1b815250906121635760405162461bcd60e51b815260040161161291906154a7565b50604080518082019091526002815261031360f41b60208201528261219b5760405162461bcd60e51b815260040161161291906154a7565b505063ffffffff9092166101e8556101d4556101d155565b6121bb611b13565b61221e5760405162461bcd60e51b815260206004820152602e60248201527f4d7573742068617665206f70657261746f7220726f6c6520746f20706572666f60448201526d3936903a3434b99030b1ba34b7b760911b6064820152608401611612565b6101c75460009081526101df6020526040908190206101d054915163063f43a360e41b81526004810184905263ffffffff9092166024830152604482018190529073c7a19772216604277a629d0642826360c0541ae6906363f43a309060640160006040518083038186803b15801561229657600080fd5b505af41580156122aa573d6000803e3d6000fd5b50506101c7546101e8546101c8546101d05460405163fce0536160e01b8152600481019490945260248401929092526044830152600160581b900462ffffff166064820152608481018490526101db60a48201526000925082915073c7a19772216604277a629d0642826360c0541ae69063fce053619060c4016040805180830381865af4158015612340573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236491906156dc565b9150915080600003612379576101e95461237c565b60005b6101e98190555060016101c7600082825461239791906155c7565b909155505060006101d28190556101c75481526101df60205260408082206101c65482516315cef56d60e11b815292519193926001600160a01b0390911691632b9deada91600480820192610240929091908290030181865afa158015612402573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612426919061574a565b905060006101c660009054906101000a90046001600160a01b03166001600160a01b031663a8bcf2ab6040518163ffffffff1660e01b815260040160c060405180830381865afa15801561247e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a2919061583f565b905060006040518061050001604052806101c75481526020016101d060009054906101000a900463ffffffff1663ffffffff1681526020016101d060049054906101000a900463ffffffff1663ffffffff1681526020016101cd548152602001836000015162ffffff168152602001836020015162ffffff168152602001836040015162ffffff168152602001836060015163ffffffff168152602001836080015163ffffffff1681526020018360a0015163ffffffff1681526020016101c960009054906101000a900462ffffff1662ffffff1681526020016101c960039054906101000a900462ffffff1662ffffff1681526020016101c960069054906101000a900462ffffff1662ffffff1681526020016101ce60009054906101000a900462ffffff1662ffffff1681526020016101ce60039054906101000a900462ffffff1662ffffff1681526020016101ce60069054906101000a900462ffffff1662ffffff1681526020016101ca5481526020016101cb54815260200184600001518152602001846020015181526020018460400151815260200184606001518152602001846080015181526020018460a0015181526020018460c0015181526020018460e001518152602001846101000151815260200184610120015181526020018461014001518152602001846101600151815260200184610180015163ffffffff168152602001846101a0015163ffffffff168152602001846101c0015163ffffffff168152602001846101e001518152602001846102000151815260200184610220015181526020016101d060089054906101000a900462ffffff1662ffffff1681526020016101d060119054906101000a900462ffffff1662ffffff1681526020016101d0600b9054906101000a900462ffffff1662ffffff1681526020016101d0600e9054906101000a900462ffffff1662ffffff16815250905073c7a19772216604277a629d0642826360c0541ae663353fd196858989898d876040518763ffffffff1660e01b81526004016127a4969594939291906158e9565b60006040518083038186803b1580156127bc57600080fd5b505af41580156127d0573d6000803e3d6000fd5b505050506127db3390565b6101c75460018601546040805192835263ffffffff8083166020850152600160201b90920490911682820152516001600160a01b0392909216917fd4f4eda7fb0fd42c44eceae5e61ca3734aa4c9843303a9bed659b38d6872b26a9181900360600190a25050505050505050565b612851613bf0565b6101c75460009081526101df6020526040902061286d33613c49565b61287633613ce0565b60018101546000906128979063ffffffff600160201b8204811691166156bf565b63ffffffff16421180156128ca57506101c75460009081526101d96020908152604080832033845290915290205460ff16155b15612904576128d833611b32565b6101c75460009081526101d9602090815260408083203384529091529020805460ff1916600117905590505b3360009081526101da60205260408120546129209083906155c7565b90508047101560405180604001604052806002815260200161313360f01b8152509061295f5760405162461bcd60e51b815260040161161291906154a7565b503360008181526101da60205260408082208290555190919083908381818185875af1925050503d80600081146129b2576040519150601f19603f3d011682016040523d82523d6000602084013e6129b7565b606091505b50509050806129d85760405162461bcd60e51b81526004016116129061567b565b60405182815233907f0ba90eb685b3b0006a3c394dd506a37e5e136aa5340c16793a2d546bd6721b8f9060200160405180910390a250505050612a1b600160c955565b565b612a25612fe3565b612a415760405162461bcd60e51b8152600401611612906154d7565b6040805180820190915260018152600360fc1b60208201526001600160a01b038416612a805760405162461bcd60e51b815260040161161291906154a7565b506040805180820190915260018152600360fc1b60208201526001600160a01b038316612ac05760405162461bcd60e51b815260040161161291906154a7565b506040805180820190915260018152600360fc1b60208201526001600160a01b038216612b005760405162461bcd60e51b815260040161161291906154a7565b506101e580546001600160a01b039485166001600160a01b0319918216179091556101e6805493851693909116929092179091556101c3805491909216600160281b02600160281b600160c81b0319909116179055565b6000611b2d600080516020615e9d833981519152335b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b612ba0612fe3565b612bbc5760405162461bcd60e51b8152600401611612906154d7565b604080518082019091526002815261313960f01b6020820152600563ffffffff831611612bfc5760405162461bcd60e51b815260040161161291906154a7565b506101c3805463ffffffff191663ffffffff92909216919091179055565b612c22612fe3565b612c3e5760405162461bcd60e51b8152600401611612906154d7565b620186a0612c5260608301604084016155f0565b612c6260408401602085016155f0565b612c6f60208501856155f0565b612c79919061560d565b612c83919061560d565b62ffffff16111560405180604001604052806002815260200161313160f01b81525090612cc35760405162461bcd60e51b815260040161161291906154a7565b50612cd160208201826155f0565b6101c9805462ffffff191662ffffff92909216919091179055612cfa60408201602083016155f0565b6101c9805462ffffff9290921663010000000265ffffff00000019909216919091179055612d2e60608201604083016155f0565b6101c9805462ffffff928316600160301b0268ffffff000000000000198216811792839055612d6d93630100000090930483169290811691161761560d565b612d7f9062ffffff16620186a0615948565b63ffffffff166101cb5550565b612d94613bf0565b6101c7546101d6546101c3546040516362d764b560e01b8152600481019390935260248301919091526001600160a01b038084166044840152600160281b9091041660648201526101df60848201526101e460a482015273c7a19772216604277a629d0642826360c0541ae6906362d764b59060c40160006040518083038186803b158015612e2257600080fd5b505af4158015612e36573d6000803e3d6000fd5b505050506120b7600160c955565b60008181526101df602052604081206101c754831115612e675750600092915050565b600a8101546101cf5460009190612e8290620186a09061556b565b612e8c91906155a0565b6009830154612ea79190600160301b900462ffffff166155c7565b9050600082600901600201548210612ec357600b830154612ec5565b815b95945050505050565b60008181526101df602052604090206101c75460609190831115612f125760408051600180825281830190925290602080830190803683370190505b509392505050565b600081600701546001600160401b03811115612f3057612f30615700565b604051908082528060200260200182016040528015612f59578160200160208202803683370190505b5090508160060154600003612f6f579392505050565b60005b8260070154811015612f0a5760008581526101dd6020908152604080832084845290915290205482516001600160a01b0390911690839083908110612fb957612fb96155da565b6001600160a01b039092166020928302919091019091015280612fdb81615965565b915050612f72565b6000611b2d600080516020615efd83398151915233612b6d565b613005612b57565b6130215760405162461bcd60e51b815260040161161290615630565b6101c38054911515600160201b0264ff0000000019909216919091179055565b613049613bf0565b61305233613c49565b3360009081526101d760209081526040918290205482518084019093526002835261062760f31b9183019190915261309d5760405162461bcd60e51b815260040161161291906154a7565b503360009081526101d760209081526040808320805493905580518082019091526002815261062760f31b91810191909152478211156130f05760405162461bcd60e51b815260040161161291906154a7565b50604051600090339083908381818185875af1925050503d8060008114613133576040519150601f19603f3d011682016040523d82523d6000602084013e613138565b606091505b50509050806131595760405162461bcd60e51b81526004016116129061567b565b5050612a1b600160c955565b61316d612fe3565b6131895760405162461bcd60e51b8152600401611612906154d7565b60405163430021db60e11b81526002604360981b019063860043b690611a0f9030908590600401615522565b6131bd612fe3565b6131d95760405162461bcd60e51b8152600401611612906154d7565b60405163662aa11d60e01b81526002604360981b019063662aa11d90611a0f9030908590600401615522565b6101e5546101e654604051631711922960e31b81526000926001600160a01b039081169263b88c91489261323f9290911690600401614de8565b602060405180830381865afa15801561325c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613280919061597e565b6001600160801b0316905090565b613296612fe3565b6132b25760405162461bcd60e51b8152600401611612906154d7565b6101c75460009081526101df6020526040902060018101546132e39063ffffffff600160201b8204811691166156bf565b63ffffffff164211806132ff5750600181015463ffffffff1642105b604051806040016040528060018152602001600d60fa1b815250906133375760405162461bcd60e51b815260040161161291906154a7565b508263ffffffff168463ffffffff16111560405180604001604052806002815260200161189b60f11b815250906133815760405162461bcd60e51b815260040161161291906154a7565b50604080518082019091526002815261031360f41b6020820152876133b95760405162461bcd60e51b815260040161161291906154a7565b50506101c8949094556101d6929092556101d0805463ffffffff938416600160201b0267ffffffffffffffff1990911693909216929092171790556101cd919091556101d3805462ffffff90921662ffffff19909216919091179055565b60008281526065602052604090206001015461343281613d8e565b6117738383613e1e565b613444612fe3565b6134605760405162461bcd60e51b8152600401611612906154d7565b600061347260808301606084016155f0565b61348260608401604085016155f0565b61349260408501602086016155f0565b61349f60208601866155f0565b6134a9919061560d565b6134b3919061560d565b6134bd919061560d565b62ffffff169050620186a063ffffffff16811460405180604001604052806002815260200161313160f01b815250906135095760405162461bcd60e51b815260040161161291906154a7565b5061351760208301836155f0565b6101d0805462ffffff92909216600160701b0262ffffff60701b1990921691909117905561354b60408301602084016155f0565b6101d0805462ffffff92909216600160581b0262ffffff60581b1990921691909117905561357f60608301604084016155f0565b6101d0805462ffffff92909216600160881b0262ffffff60881b199092169190911790556135b360808301606084016155f0565b6101d060086101000a81548162ffffff021916908362ffffff1602179055505050565b6101c75460009081526101df6020526040812081806135f485613638565b60018401549091506136159063ffffffff600160201b8204811691166156bf565b63ffffffff1642111561362e5761362b85611b32565b91505b612ec582826155c7565b6001600160a01b03811660009081526101e06020908152604080832080548085526101df9093529083206101c7549192909111158061369c5750815460009081526101d9602090815260408083206001600160a01b038816845290915290205460ff165b156136c0575050506001600160a01b031660009081526101da602052604090205490565b6001600160a01b03841660008181526101da6020908152604080832054865484526101dc83528184209484529390915281205460038401546009850154919291620186a09161371a91600160481b900462ffffff1661556b565b61372491906155a0565b90506000846006015460001461375857846006015482866003015461374991906155b4565b61375391906155a0565b61375b565b60005b865460009081526101db60205260409020549091506001600160a01b03808a169116036137b85784600601546000036137ab5781856003015461379e91906155b4565b6137a890856155c7565b93505b6137b582856155c7565b93505b821561381c57855460009081526101db60205260409020546001600160a01b031661380557828560060154836137ee91906155a0565b6137f8919061556b565b61380290856155c7565b93505b61380f838261556b565b61381990856155c7565b93505b50919695505050505050565b600054610100900460ff16158080156138485750600054600160ff909116105b806138625750303b158015613862575060005460ff166001145b6138c55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611612565b6000805460ff1916600117905580156138e8576000805461ff0019166101001790555b6101e580546001600160a01b03199081166001600160a01b038d8116919091179092556101e6805482168c84161790556101c6805482168884161790556101c38054600160281b600160c81b031916600160281b8c8516021790556101ea805482168684161790556101c4805482168984169081179091556101c58054909216928a169290921790556040516336b91f2b60e01b81526336b91f2b90613992908a90600401614de8565b600060405180830381600087803b1580156139ac57600080fd5b505af11580156139c0573d6000803e3d6000fd5b505050506002604360981b016001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a0657600080fd5b505af1158015613a1a573d6000803e3d6000fd5b505050506002604360981b016001600160a01b031663f098767a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a6057600080fd5b505af1158015613a74573d6000803e3d6000fd5b50505050613a80614090565b6101c7805460009081526101df6020526040902060018101805463ffffffff19164263ffffffff16179055905481556101cd54600690910155613ac48484846115eb565b8015613b0a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b600054610100900460ff16612a1b5760405162461bcd60e51b81526004016116129061540c565b600054610100900460ff16613b645760405162461bcd60e51b81526004016116129061540c565b612a1b614174565b600054610100900460ff16613b935760405162461bcd60e51b81526004016116129061540c565b612a1b6141a7565b6119bb8282613d98565b600082815260656020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b600260c95403613c425760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611612565b600260c955565b6101c354604051632992684f60e01b81526101e060048201526101e160248201526101d7604482015263ffffffff90911660648201526001600160a01b038216608482015273c7a19772216604277a629d0642826360c0541ae690632992684f9060a40160006040518083038186803b158015613cc557600080fd5b505af4158015613cd9573d6000803e3d6000fd5b5050505050565b6001600160a01b03811660009081526101e0602052604090206101c754815410613d08575050565b805460009081526101d9602090815260408083206001600160a01b038616845290915290205460ff16613d7e57613d3e82613638565b6001600160a01b03831660008181526101da6020908152604080832094909455845482526101d981528382209282529190915220805460ff191660011790555b6101c754905550565b600160c955565b6120b781336141ce565b613da28282612b6d565b6119bb5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff19166001179055613dda3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b613e288282612b6d565b156119bb5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6101e5546001600160a01b0316336001600160a01b03161460405180604001604052806002815260200161189960f11b81525090613ed65760405162461bcd60e51b815260040161161291906154a7565b506101c75460008181526101df602090815260408083206101e38352818420546001600160401b03891685526101e78452828520549585526101e184528285206001600160a01b0390961680865295909352928190206101c35491516310d481af60e11b8152600481018590526024810182905263ffffffff9092166044830152929391929073c7a19772216604277a629d0642826360c0541ae6906321a9035e9060640160006040518083038186803b158015613f9357600080fd5b505af4158015613fa7573d6000803e3d6000fd5b50505050613fb58482614227565b60048101546000808080613fc88a6144a0565b93509350935093506000613fdf8b60001c8761456b565b90506000613ff98662ffffff8087169086168f8e8e614611565b80516020820151919250906000816003811115614018576140186152ca565b0361402e5761402888888d614a05565b90925090505b60058a0180546002919060ff60401b1916600160401b83021790555082604001516101e360006101c75481526020019081526020016000208190555061407e8b8f60001c6101c754858886614b4a565b50505050505050505050505050505050565b660e35fa931a00006101c88190556101d655600a6101cd556101c38054603c63ffffffff199091161790556101d080546001600160a01b0319166f3a980144380007d0000001a4000001a41790556101c9805468ffffffffffffffffff199081166664003a980005dc17918290556101ce80549091166801117000fde80088b81790556113886101ca556141339062ffffff6301000000909104166105dc61560d565b6141459062ffffff16620186a0615948565b63ffffffff166101cb5560056101d48190556101e85560036101d1556101d3805462ffffff19166103e8179055565b600054610100900460ff1661419b5760405162461bcd60e51b81526004016116129061540c565b6097805460ff19169055565b600054610100900460ff16613d875760405162461bcd60e51b81526004016116129061540c565b6141d88282612b6d565b6119bb576141e581614bab565b6141f0836020614bbd565b6040516020016142019291906159a7565b60408051601f198184030181529082905262461bcd60e51b8252611612916004016154a7565b600e820154600c8301546003830154600091620186a091614248919061556b565b61425291906155a0565b6101c354604051919250600091600160281b9091046001600160a01b03169083908381818185875af1925050503d80600081146142ab576040519150601f19603f3d011682016040523d82523d6000602084013e6142b0565b606091505b50509050806143015760405162461bcd60e51b815260206004820181905260248201527f4661696c656420746f2073656e6420457468657220746f2074726561737572796044820152606401611612565b6101d4546101e954101561440e5760016101e9600082825461432391906155c7565b90915550506003840154600090620186a09061434090869061556b565b61434a91906155a0565b6101ea546040519192506001600160a01b0316908290600081818185875af1925050503d8060008114614399576040519150601f19603f3d011682016040523d82523d6000602084013e61439e565b606091505b505080925050816144085760405162461bcd60e51b815260206004820152602e60248201527f4661696c656420746f2073656e64205365656420457468657220746f2070726960448201526d1e99481c1bdbdb081dd85b1b195d60921b6064820152608401611612565b60009350505b600f850154600d860154604051600162beb8ff60e01b031981526004810188905260248101879052604481018690526064810192909252608482015273c7a19772216604277a629d0642826360c0541ae69063ff4147019060a40160006040518083038186803b15801561448157600080fd5b505af4158015614495573d6000803e3d6000fd5b505050505050505050565b6101c75460009081526101df6020526040812060098101548291829182919062ffffff8082169184916144db916301000000900416836155c7565b600a8401546101cf549192506000916144f890620186a09061556b565b61450291906155a0565b600985015461451d9190600160301b900462ffffff166155c7565b905060008460090160020154821061453957600b85015461453b565b815b905061454783826155c7565b90506000614558620186a08c615a16565b9b919a5093985091965090945050505050565b6101c75460009081526101df60205260409081902090516327dba2ff60e11b81526004810184905260248101839052604481018290526060919073c7a19772216604277a629d0642826360c0541ae690634fb745fe90606401600060405180830381865af41580156145e1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526146099190810190615a2a565b949350505050565b60408051606081018252600080825260208201819052918101919091526040805160e0810182526101c75480825260208083018890526101d154838501526101d2546060840152608083018b905260a083018a905260c0830189905260009182526101df9052828120925163108c9e0360e11b815291929091829173c7a19772216604277a629d0642826360c0541ae6916321193c06916146be9187918a918c906101e290600401615c24565b6040805180830381865af41580156146da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146fe91906156dc565b6040805160c0810182526101c7548152602081018e90528082018d9052606081018c9052608081018490526101d35462ffffff1660a08201529051631585364760e31b8152929450909250906000908190819073c7a19772216604277a629d0642826360c0541ae69063ac29b238906147859087908d906101df906101db90600401615dac565b606060405180830381865af41580156147a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147c69190615de0565b9194509250905060028260038111156147e1576147e16152ca565b036148895760016101cf60008282546147fa91906155c7565b90915550506101c75460408051918252600160208301526000908201526001600160a01b038a16907fe74013133fb67b03a3cba620837d933f19e9141c42fbf501232300c7f981fc639060600160405180910390a26040518060600160405280848152602001836003811115614872576148726152ca565b8152602001868152509750505050505050506149fb565b60405163d984928f60e01b815273c7a19772216604277a629d0642826360c0541ae69063d984928f906148d29087908d906101df906101dd906101de906101dc90600401615e1d565b606060405180830381865af41580156148ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149139190615de0565b91945092509050600382600381111561492e5761492e6152ca565b036149c55760016101cf600082825461494791906155c7565b90915550506101d1546101d25410614962576101d254614971565b6101d2546149719060016155c7565b6101d2556101c754604080519182526000602083015281018290526001600160a01b038a16907fe74013133fb67b03a3cba620837d933f19e9141c42fbf501232300c7f981fc639060600160405180910390a25b60405180606001604052808481526020018360038111156149e8576149e86152ca565b8152602001868152509750505050505050505b9695505050505050565b6000808362ffffff16851015614b21576101c7546101cf54604051630633166360e01b8152600481019290925260248201526001600160a01b03841660448201526101df60648201526101da6084820152600090819073c7a19772216604277a629d0642826360c0541ae69063063316639060a4016040805180830381865af4158015614a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614aba91906156dc565b60006101cf556101c7546040805191825260208201839052810183905291935091506001600160a01b038616907f3f88442eb3441ef91803cd74336f2222c81a2d7f987cb61024e76b1b02eeecfb9060600160405180910390a2925060019150614b429050565b60016101cf6000828254614b3591906155c7565b9091555060009250829150505b935093915050565b806003811115614b5c57614b5c6152ca565b866001600160a01b03167fc338cfe35c3d868fb81af4e8541c0468d009b25f0849de36101d3369ee3667ef87878787604051614b9b9493929190615e60565b60405180910390a3505050505050565b60606115e56001600160a01b03831660145b60606000614bcc83600261556b565b614bd79060026155c7565b6001600160401b03811115614bee57614bee615700565b6040519080825280601f01601f191660200182016040528015614c18576020820181803683370190505b509050600360fc1b81600081518110614c3357614c336155da565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110614c6257614c626155da565b60200101906001600160f81b031916908160001a9053506000614c8684600261556b565b614c919060016155c7565b90505b6001811115614d09576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110614cc557614cc56155da565b1a60f81b828281518110614cdb57614cdb6155da565b60200101906001600160f81b031916908160001a90535060049490941c93614d0281615e85565b9050614c94565b508315614d585760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401611612565b9392505050565b600060208284031215614d7157600080fd5b81356001600160e01b031981168114614d5857600080fd5b80356001600160a01b0381168114614da057600080fd5b919050565b600080600060608486031215614dba57600080fd5b614dc384614d89565b9250614dd160208501614d89565b9150614ddf60408501614d89565b90509250925092565b6001600160a01b0391909116815260200190565b60008060408385031215614e0f57600080fd5b614e1883614d89565b946020939093013593505050565b60008060408385031215614e3957600080fd5b82359150614e4960208401614d89565b90509250929050565b6001600160401b03811681146120b757600080fd5b600060208284031215614e7957600080fd5b8135614d5881614e52565b600060208284031215614e9657600080fd5b5035919050565b600060208284031215614eaf57600080fd5b614d5882614d89565b600060608284031215614eca57600080fd5b82606083011115614eda57600080fd5b50919050565b600080600060608486031215614ef557600080fd5b8335614f0081614e52565b9250614f0e60208501614d89565b9150604084013590509250925092565b60008060408385031215614f3157600080fd5b50508035926020909101359150565b63ffffffff811681146120b757600080fd5b600080600060608486031215614f6757600080fd5b8335614f7281614f40565b95602085013595506040909401359392505050565b805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e0830152610100808201518184015250610120808201518184015250610140808201518184015250610160808201518184015250610180808201516150198285018263ffffffff169052565b50506101a08181015163ffffffff81168483015250506101c08181015163ffffffff81168483015250506101e08181015190830152610200808201519083015261022090810151910152565b60006105c0820190508f825263ffffffff8f16602083015263ffffffff8e16604083015263ffffffff8d1660608301528b60808301528a60a08301528960c08301528860e0830152876101008301528661012083015261511761014083018762ffffff80825116835280602083015116602084015280604083015116604084015250606081015163ffffffff80821660608501528060808401511660808501528060a08401511660a085015250505050565b845162ffffff9081166102008401526020860151811661022084015260408601518116610240840152606086015181166102608401526080860151811661028084015260a0860151166102a083015260c08501516102c083015260e08501516102e083015283516103008301526020840151610320830152604084015161034083015260608401516103608301526151b3610380830184614f87565b9f9e505050505050505050505050505050565b6000602082840312156151d857600080fd5b8135614d5881614f40565b6020808252825182820181905260009190848201906040850190845b818110156152245783516001600160a01b0316835292840192918401916001016151ff565b50909695505050505050565b60006020828403121561524257600080fd5b81358015158114614d5857600080fd5b62ffffff811681146120b757600080fd5b60008060008060008060c0878903121561527c57600080fd5b863595506020870135945060408701359350606087013561529c81614f40565b925060808701356152ac81614f40565b915060a08701356152bc81615252565b809150509295509295509295565b634e487b7160e01b600052602160045260246000fd5b600060e0820190508882528760208301528660408301528560608301528460808301526001600160401b03841660a08301526003831061533057634e487b7160e01b600052602160045260246000fd5b8260c083015298975050505050505050565b60006080828403121561535457600080fd5b82608083011115614eda57600080fd5b60008060008060008060008060006101208a8c03121561538357600080fd5b61538c8a614d89565b985061539a60208b01614d89565b97506153a860408b01614d89565b96506153b660608b01614d89565b95506153c460808b01614d89565b94506153d260a08b01614d89565b93506153e060c08b01614d89565b92506153ee60e08b01614d89565b91506153fd6101008b01614d89565b90509295985092959850929598565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60005b8381101561547257818101518382015260200161545a565b50506000910152565b60008151808452615493816020860160208601615457565b601f01601f19169290920160200192915050565b602081526000614d58602083018461547b565b6000602082840312156154cc57600080fd5b8151614d5881614e52565b6020808252602b908201527f4d75737420686176652061646d696e20726f6c6520746f20706572666f726d2060408201526a3a3434b99030b1ba34b7b760a91b606082015260800190565b6001600160a01b0392831681529116602082015260400190565b60006020828403121561554e57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561558557615585615555565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826155af576155af61558a565b500490565b818103818111156115e5576115e5615555565b808201808211156115e5576115e5615555565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561560257600080fd5b8135614d5881615252565b62ffffff81811683821601908082111561562957615629615555565b5092915050565b6020808252602b908201527f4d7573742068617665206f776e657220726f6c6520746f20706572666f726d2060408201526a3a3434b99030b1ba34b7b760a91b606082015260800190565b60208082526024908201527f4661696c656420746f2073656e6420457468657220746f20626c617374207769604082015263373732b960e11b606082015260800190565b63ffffffff81811683821601908082111561562957615629615555565b600080604083850312156156ef57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052604160045260246000fd5b60405161024081016001600160401b038111828210171561573957615739615700565b60405290565b8051614da081614f40565b6000610240828403121561575d57600080fd5b615765615716565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101408084015181830152506101608084015181830152506101806157ed81850161573f565b908201526101a06157ff84820161573f565b908201526101c061581184820161573f565b908201526101e083810151908201526102008084015190820152610220928301519281019290925250919050565b600060c0828403121561585157600080fd5b60405160c081018181106001600160401b038211171561587357615873615700565b604052825161588181615252565b8152602083015161589181615252565b602082015260408301516158a481615252565b604082015260608301516158b781614f40565b606082015260808301516158ca81614f40565b608082015260a08301516158dd81614f40565b60a08201529392505050565b60006105a0820190508782526020878184015286604084015285606084015263ffffffff8516608084015260a083018460005b60288110156159395781518352918301919083019060010161591c565b50505050979650505050505050565b63ffffffff82811682821603908082111561562957615629615555565b60006001820161597757615977615555565b5060010190565b60006020828403121561599057600080fd5b81516001600160801b0381168114614d5857600080fd5b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516159d9816017850160208801615457565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615a0a816028840160208801615457565b01602801949350505050565b600082615a2557615a2561558a565b500690565b600060208284031215615a3c57600080fd5b81516001600160401b0380821115615a5357600080fd5b818401915084601f830112615a6757600080fd5b815181811115615a7957615a79615700565b604051601f8201601f19908116603f01168101908382118183101715615aa157615aa1615700565b81604052828152876020848701011115615aba57600080fd5b615acb836020830160208801615457565b979650505050505050565b805462ffffff8082168452808260181c166020850152808260301c166040850152808260481c166060850152615b1860808501828460601c1662ffffff169052565b615b2e60a08501828460781c1662ffffff169052565b5050600181015460c08301526002015460e090910152565b8054825260018101546020830152600281015460408301526003810154606083015260048101546080830152600581015460a0830152600681015460c0830152600781015460e083015260088101546101008301526009810154610120830152600a810154610140830152600b810154610160830152600c81015463ffffffff808216610180850152615be76101a08501828460201c1663ffffffff169052565b615bff6101c08501828460401c1663ffffffff169052565b5050600d8101546101e0830152600e810154610200830152600f015461022090910152565b6107008101818760005b6007811015615c4d578151835260209283019290910190600101615c2e565b5050506001600160a01b03861660e08301528454610100830152600185015463ffffffff808216610120850152602082901c811661014085015260409190911c8116610160840152600286015461018084015260038601546101a084015260048601546101c084015260058601546101e084015260068601546102008401526007860154610220840152600886015462ffffff808216610240860152601882901c8116610260860152603082901c16610280850152604881901c82166102a0850152606881901c82166102c085015260881c166102e0830152615d37610300830160098701615ad6565b600c850154610400830152600d850154610420830152600e850154610440830152600f850154610460830152615d74610480830160108701615b46565b6106c08201939093526106e001529392505050565b8060005b6006811015611f8e578151845260209384019390910190600101615d8d565b6101208101615dbb8287615d89565b6001600160a01b039490941660c082015260e081019290925261010090910152919050565b600080600060608486031215615df557600080fd5b83519250602084015160048110615e0b57600080fd5b80925050604084015190509250925092565b6101608101615e2c8289615d89565b6001600160a01b039690961660c082015260e081019490945261010084019290925261012083015261014090910152919050565b8481528360208201528260408201526080606082015260006149fb608083018461547b565b600081615e9457615e94615555565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92965d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a2646970667358221220e45f617c28c455ccd0c8a1d05eeeb94a361382c5ba2955fc46e270b3fcfd0bdf64736f6c63430008100033
Deployed Bytecode
0x6080604052600436106104e15760003560e01c80638c65c81f1161027f578063bb0c485311610159578063e12f3a61116100c6578063e7487eb511610082578063e7487eb5146114db578063edcc846114611517578063f5b541a614611537578063f5e95acb14611559578063f7cb789a14611579578063f9b3d1ad1461159757005b8063e12f3a6114611404578063e2eb41ff14611424578063e3ec42c614611452578063e45ed31e14611469578063e58378bb14611497578063e63ab1e9146114b957005b8063ced72f8711610115578063ced72f87146112e7578063d00c9179146112fc578063d0efe3c714611320578063d547741f14611340578063d731907a14611360578063dce54178146113e457005b8063bb0c485314611218578063c18e8ac81461122d578063c2d94aec14611252578063c913600614611272578063cabb1ae4146112a9578063cd2002f5146112c757005b8063a178a472116101f7578063a97223ed116101b3578063a97223ed14611158578063affed0e01461117c578063b3cd425414611193578063b6db75a0146111bf578063b7a52bfb146111d4578063b80163a9146111f857005b8063a178a4721461107e578063a217fddf146110a2578063a2ee631b146110b7578063a420f7b2146110e4578063a65d60af14611108578063a86b11b81461111f57005b8063936c8a5111610246578063936c8a5114610fb257806399221b2714610ff45780639b6bb91d146110145780639bbe2391146110345780639df6efd21461104b578063a170dfc91461105e57005b80638c65c81f14610b3d5780638f32d59b14610f2a578063906e3d9f14610f3f5780639119ddc514610f5657806391d1485414610f9257005b80634456eda2116103bb5780635c975abb1161032857806379502c55116102e457806379502c5514610a895780637d7e58f514610aaa57806380c2c89714610aca5780638183059314610ae157806387f9798914610b025780638bed5bd214610b2657005b80635c975abb146109ce5780635ead5a32146109e657806368e9f95414610a1f5780636919ed7214610a3f57806370740ac914610a5257806375b238fc14610a6757005b80634dbb78b7116103775780634dbb78b7146108f15780634f1d7f6e146109155780635237fa551461092c57806352a5f1f81461094c5780635312ea8e1461096c5780635508edf11461098c57005b80634456eda21461083d57806344599e341461085257806346eacf1b1461086f57806347ce07cc1461088f57806347fb4553146108b05780634b750bd5146108d157005b80631f0f01ef116104595780632c4106bd116104155780632c4106bd146107815780632cc5d624146107985780632f2ff15d146107b857806330858ae2146107d857806336568abe146108065780633de3786a1461082657005b80631f0f01ef146106b857806322bc2852146106d5578063248a9ca3146106ec578063272b13231461071c5780632a3d57411461073c5780632bc79c121461075357005b80630e9d0c32116104a85780630e9d0c32146105cd5780630ecb3c89146105f2578063120aa8771461060557806316cfaa161461063e5780631aba27301461065f5780631b43987f1461069657005b806301ffc9a7146104ea5780630621b8381461051f578063085d48831461053f578063088803b41461056d5780630a1d562f146105a557005b366104e857005b005b3480156104f657600080fd5b5061050a610505366004614d5f565b6115b4565b60405190151581526020015b60405180910390f35b34801561052b57600080fd5b506104e861053a366004614da5565b6115eb565b34801561054b57600080fd5b506101e654610560906001600160a01b031681565b6040516105169190614de8565b34801561057957600080fd5b506101ce5461059190600160301b900462ffffff1681565b60405162ffffff9091168152602001610516565b3480156105b157600080fd5b506101c35461056090600160281b90046001600160a01b031681565b3480156105d957600080fd5b506105e46101cc5481565b604051908152602001610516565b6104e8610600366004614dfc565b611778565b34801561061157600080fd5b506105e4610620366004614e26565b6101d860209081526000928352604080842090915290825290205481565b34801561064a57600080fd5b506101c454610560906001600160a01b031681565b34801561066b57600080fd5b5061056061067a366004614e67565b6101e7602052600090815260409020546001600160a01b031681565b3480156106a257600080fd5b506101c35461050a90600160201b900460ff1681565b3480156106c457600080fd5b506101d3546105919062ffffff1681565b3480156106e157600080fd5b506105e46101cb5481565b3480156106f857600080fd5b506105e4610707366004614e84565b60009081526065602052604090206001015490565b34801561072857600080fd5b506104e8610737366004614e9d565b6119bf565b34801561074857600080fd5b506105e46101d15481565b34801561075f57600080fd5b506105e461076e366004614e9d565b6101da6020526000908152604090205481565b34801561078d57600080fd5b506105e46101c85481565b3480156107a457600080fd5b506105e46107b3366004614e84565b611a52565b3480156107c457600080fd5b506104e86107d3366004614e26565b611a74565b3480156107e457600080fd5b506105e46107f3366004614e84565b6101e36020526000908152604090205481565b34801561081257600080fd5b506104e8610821366004614e26565b611a99565b34801561083257600080fd5b506105e46101cd5481565b34801561084957600080fd5b5061050a611b13565b34801561085e57600080fd5b506101ce546105919062ffffff1681565b34801561087b57600080fd5b506105e461088a366004614e9d565b611b32565b34801561089b57600080fd5b506101e554610560906001600160a01b031681565b3480156108bc57600080fd5b506101c554610560906001600160a01b031681565b3480156108dd57600080fd5b506104e86108ec366004614e84565b611cd3565b3480156108fd57600080fd5b506101c954610591906301000000900462ffffff1681565b34801561092157600080fd5b506105e46101d45481565b34801561093857600080fd5b506104e8610947366004614eb8565b611d3b565b34801561095857600080fd5b506104e8610967366004614ee0565b611eb8565b34801561097857600080fd5b506104e8610987366004614e84565b611f94565b34801561099857600080fd5b506105606109a7366004614f1e565b6101dd6020908152600092835260408084209091529082529020546001600160a01b031681565b3480156109da57600080fd5b5060975460ff1661050a565b3480156109f257600080fd5b506105e4610a01366004614e26565b6101dc60209081526000928352604080842090915290825290205481565b348015610a2b57600080fd5b506104e8610a3a366004614f52565b6120ba565b6104e8610a4d366004614e84565b6121b3565b348015610a5e57600080fd5b506104e8612849565b348015610a7357600080fd5b506105e4600080516020615efd83398151915281565b348015610a9557600080fd5b506101c654610560906001600160a01b031681565b348015610ab657600080fd5b506104e8610ac5366004614da5565b612a1d565b348015610ad657600080fd5b506105e46101ca5481565b348015610aed57600080fd5b506101ea54610560906001600160a01b031681565b348015610b0e57600080fd5b506101c95461059190600160301b900462ffffff1681565b348015610b3257600080fd5b506105e46101e95481565b348015610b4957600080fd5b50610f10610b58366004614e84565b6101df6020528060005260406000206000915090508060000154908060010160009054906101000a900463ffffffff16908060010160049054906101000a900463ffffffff16908060010160089054906101000a900463ffffffff1690806002015490806003015490806004015490806005015490806006015490806007015490806008016040518060c00160405290816000820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160039054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160069054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160099054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600d9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160119054906101000a900463ffffffff1663ffffffff1663ffffffff16815250509080600901604051806101000160405290816000820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160039054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160069054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160099054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600c9054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600f9054906101000a900462ffffff1662ffffff1662ffffff168152602001600182015481526020016002820154815250509080600c0160405180608001604052908160008201548152602001600182015481526020016002820154815260200160038201548152505090806010016040518061024001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152602001600782015481526020016008820154815260200160098201548152602001600a8201548152602001600b8201548152602001600c820160009054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600c820160049054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600c820160089054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001600d8201548152602001600e8201548152602001600f8201548152505090508e565b6040516105169e9d9c9b9a99989796959493929190615065565b348015610f3657600080fd5b5061050a612b57565b348015610f4b57600080fd5b506105e46101cf5481565b348015610f6257600080fd5b5061050a610f71366004614e26565b6101d960209081526000928352604080842090915290825290205460ff1681565b348015610f9e57600080fd5b5061050a610fad366004614e26565b612b6d565b348015610fbe57600080fd5b50610560610fcd366004614f1e565b6101e26020908152600092835260408084209091529082529020546001600160a01b031681565b34801561100057600080fd5b506104e861100f3660046151c6565b612b98565b34801561102057600080fd5b506104e861102f366004614eb8565b612c1a565b34801561104057600080fd5b506105e46101d65481565b6104e8611059366004614e9d565b612d8c565b34801561106a57600080fd5b506105e4611079366004614e84565b612e44565b34801561108a57600080fd5b506101d05461059190600160581b900462ffffff1681565b3480156110ae57600080fd5b506105e4600081565b3480156110c357600080fd5b506110d76110d2366004614e84565b612ece565b60405161051691906151e3565b3480156110f057600080fd5b506101d05461059190600160881b900462ffffff1681565b34801561111457600080fd5b506105e46101e85481565b34801561112b57600080fd5b506105e461113a366004614e26565b6101de60209081526000928352604080842090915290825290205481565b34801561116457600080fd5b506101d05461059190600160401b900462ffffff1681565b34801561118857600080fd5b506105e46101c75481565b34801561119f57600080fd5b506111aa620186a081565b60405163ffffffff9091168152602001610516565b3480156111cb57600080fd5b5061050a612fe3565b3480156111e057600080fd5b506101ce54610591906301000000900462ffffff1681565b34801561120457600080fd5b506104e8611213366004615230565b612ffd565b34801561122457600080fd5b506104e8613041565b34801561123957600080fd5b506101d0546111aa90600160201b900463ffffffff1681565b34801561125e57600080fd5b506104e861126d366004614e9d565b613165565b34801561127e57600080fd5b5061056061128d366004614e84565b6101db602052600090815260409020546001600160a01b031681565b3480156112b557600080fd5b506101c3546111aa9063ffffffff1681565b3480156112d357600080fd5b506104e86112e2366004614e9d565b6131b5565b3480156112f357600080fd5b506105e4613205565b34801561130857600080fd5b506101d05461059190600160701b900462ffffff1681565b34801561132c57600080fd5b506104e861133b366004615263565b61328e565b34801561134c57600080fd5b506104e861135b366004614e26565b613417565b34801561136c57600080fd5b506113d161137b366004614e26565b6101e160209081526000928352604080842090915290825290208054600182015460028301546003840154600485015460059095015493949293919290916001600160401b03811690600160401b900460ff1687565b60405161051697969594939291906152e0565b3480156113f057600080fd5b506104e86113ff366004615342565b61343c565b34801561141057600080fd5b506105e461141f366004614e9d565b6135d6565b34801561143057600080fd5b506105e461143f366004614e9d565b6101e06020526000908152604090205481565b34801561145e57600080fd5b506105e46101d25481565b34801561147557600080fd5b506105e4611484366004614e9d565b6101d76020526000908152604090205481565b3480156114a357600080fd5b506105e4600080516020615e9d83398151915281565b3480156114c557600080fd5b506105e4600080516020615edd83398151915281565b3480156114e757600080fd5b5061050a6114f6366004614e26565b6101e460209081526000928352604080842090915290825290205460ff1681565b34801561152357600080fd5b506105e4611532366004614e9d565b613638565b34801561154357600080fd5b506105e4600080516020615ebd83398151915281565b34801561156557600080fd5b506104e8611574366004615364565b613828565b34801561158557600080fd5b506101d0546111aa9063ffffffff1681565b3480156115a357600080fd5b506101c9546105919062ffffff1681565b60006001600160e01b03198216637965db0b60e01b14806115e557506301ffc9a760e01b6001600160e01b03198316145b92915050565b600054610100900460ff1661161b5760405162461bcd60e51b81526004016116129061540c565b60405180910390fd5b6001600160a01b0383166116715760405162461bcd60e51b815260206004820181905260248201527f4f776e65722063616e6e6f7420626520746865207a65726f20616464726573736044820152606401611612565b611679613b16565b611681613b3d565b611689613b6c565b6116a1600080516020615e9d83398151915284613b9b565b6116b9600080516020615edd83398151915283613b9b565b6116d1600080516020615ebd83398151915282613b9b565b6116e9600080516020615efd83398151915283613b9b565b61170f600080516020615edd833981519152600080516020615e9d833981519152613ba5565b611735600080516020615ebd833981519152600080516020615e9d833981519152613ba5565b61175b600080516020615efd833981519152600080516020615e9d833981519152613ba5565b611773600080516020615e9d83398151915280613ba5565b505050565b611780613bf0565b6101c75460009081526101df602090815260408083206101e183528184206001600160a01b03871685529092529091206117b984613c49565b604051638f4fa25160e01b8152600481018390526024810182905273c7a19772216604277a629d0642826360c0541ae690638f4fa2519060440160006040518083038186803b15801561180b57600080fd5b505af415801561181f573d6000803e3d6000fd5b5050505061182c84613ce0565b6101c75460009081526101e4602090815260408083206001600160a01b03881684528252918290205482518084019093526002835261032360f41b9183019190915260ff1661188e5760405162461bcd60e51b815260040161161291906154a7565b506101c7546101c8546101e6546101e554604051631295edbd60e21b8152600481019490945234602485015260448401929092526001600160a01b038088166064850152908116608484015260a483018490521660c48201526101e760e4820152610104810184905260009073c7a19772216604277a629d0642826360c0541ae690634a57b6f49061012401602060405180830381865af4158015611937573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195b91906154ba565b6101c754604080519182526001600160401b03831660208301529192506001600160a01b038716917f5a0920da7c4df7f0e5da0ce23542a31a806ddda495b3f8da7ca95e92ad030dbc910160405180910390a25050506119bb600160c955565b5050565b6119c7612fe3565b6119e35760405162461bcd60e51b8152600401611612906154d7565b604051634aa7d2f760e11b81526002604360981b019063954fa5ee90611a0f9030908590600401615522565b6020604051808303816000875af1158015611a2e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119bb919061553c565b6101d58181548110611a6357600080fd5b600091825260209091200154905081565b600082815260656020526040902060010154611a8f81613d8e565b6117738383613d98565b6001600160a01b0381163314611b095760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401611612565b6119bb8282613e1e565b6000611b2d600080516020615ebd83398151915233612b6d565b905090565b6101c75460009081526101df602090815260408083206101d983528184206001600160a01b0386168552909252822054829060ff1615611b73579392505050565b6101c75460009081526101dc602090815260408083206001600160a01b038816845290915281205460038401546009850154919291620186a091611bc291600160481b900462ffffff1661556b565b611bcc91906155a0565b905060008460060154600014611c00578460060154828660030154611bf191906155b4565b611bfb91906155a0565b611c03565b60005b6101c75460009081526101db60205260409020549091506001600160a01b03808916911603611c62578460060154600003611c5557818560030154611c4891906155b4565b611c5290856155c7565b93505b611c5f82856155c7565b93505b8215611cc8576101c75460009081526101db60205260409020546001600160a01b0316611cb15782856006015483611c9a91906155a0565b611ca4919061556b565b611cae90856155c7565b93505b611cbb838261556b565b611cc590856155c7565b93505b509195945050505050565b611cdb612fe3565b611cf75760405162461bcd60e51b8152600401611612906154d7565b604080518082019091526002815261313160f01b6020820152620186a0821115611d345760405162461bcd60e51b815260040161161291906154a7565b506101ca55565b611d43612fe3565b611d5f5760405162461bcd60e51b8152600401611612906154d7565b6000611d7160408301602084016155f0565b611d7e60208401846155f0565b611d88919061560d565b62ffffff169050620186a063ffffffff1681111560405180604001604052806002815260200161313160f01b81525090611dd55760405162461bcd60e51b815260040161161291906154a7565b50620186a0611dea60608401604085016155f0565b62ffffff16111560405180604001604052806002815260200161313160f01b81525090611e2a5760405162461bcd60e51b815260040161161291906154a7565b50611e3860208301836155f0565b6101ce805462ffffff191662ffffff92909216919091179055611e6160408301602084016155f0565b6101ce805462ffffff9290921663010000000265ffffff00000019909216919091179055611e9560608301604084016155f0565b6101ce60066101000a81548162ffffff021916908362ffffff1602179055505050565b6000611ecd6101e5546001600160a01b031690565b90506001600160a01b038116611f1f5760405162461bcd60e51b8152602060048201526017602482015276115b9d1c9bdc1e481859191c995cdcc81b9bdd081cd95d604a1b6044820152606401611612565b336001600160a01b03821614611f835760405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920456e74726f70792063616e2063616c6c20746869732066756e637460448201526234b7b760e91b6064820152608401611612565b611f8e848484613e85565b50505050565b611f9c613bf0565b611fa4612b57565b611fc05760405162461bcd60e51b815260040161161290615630565b6101c3546040805180820190915260028152610c4d60f21b602082015290600160201b900460ff166120055760405162461bcd60e51b815260040161161291906154a7565b508047101560405180604001604052806002815260200161062760f31b815250906120435760405162461bcd60e51b815260040161161291906154a7565b50604051600090339083908381818185875af1925050503d8060008114612086576040519150601f19603f3d011682016040523d82523d6000602084013e61208b565b606091505b50509050806120ac5760405162461bcd60e51b81526004016116129061567b565b506120b7600160c955565b50565b6120c2612fe3565b6120de5760405162461bcd60e51b8152600401611612906154d7565b6101c75460009081526101df60205260409020600181015461210f9063ffffffff600160201b8204811691166156bf565b63ffffffff1642118061212b5750600181015463ffffffff1642105b604051806040016040528060018152602001600d60fa1b815250906121635760405162461bcd60e51b815260040161161291906154a7565b50604080518082019091526002815261031360f41b60208201528261219b5760405162461bcd60e51b815260040161161291906154a7565b505063ffffffff9092166101e8556101d4556101d155565b6121bb611b13565b61221e5760405162461bcd60e51b815260206004820152602e60248201527f4d7573742068617665206f70657261746f7220726f6c6520746f20706572666f60448201526d3936903a3434b99030b1ba34b7b760911b6064820152608401611612565b6101c75460009081526101df6020526040908190206101d054915163063f43a360e41b81526004810184905263ffffffff9092166024830152604482018190529073c7a19772216604277a629d0642826360c0541ae6906363f43a309060640160006040518083038186803b15801561229657600080fd5b505af41580156122aa573d6000803e3d6000fd5b50506101c7546101e8546101c8546101d05460405163fce0536160e01b8152600481019490945260248401929092526044830152600160581b900462ffffff166064820152608481018490526101db60a48201526000925082915073c7a19772216604277a629d0642826360c0541ae69063fce053619060c4016040805180830381865af4158015612340573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236491906156dc565b9150915080600003612379576101e95461237c565b60005b6101e98190555060016101c7600082825461239791906155c7565b909155505060006101d28190556101c75481526101df60205260408082206101c65482516315cef56d60e11b815292519193926001600160a01b0390911691632b9deada91600480820192610240929091908290030181865afa158015612402573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612426919061574a565b905060006101c660009054906101000a90046001600160a01b03166001600160a01b031663a8bcf2ab6040518163ffffffff1660e01b815260040160c060405180830381865afa15801561247e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a2919061583f565b905060006040518061050001604052806101c75481526020016101d060009054906101000a900463ffffffff1663ffffffff1681526020016101d060049054906101000a900463ffffffff1663ffffffff1681526020016101cd548152602001836000015162ffffff168152602001836020015162ffffff168152602001836040015162ffffff168152602001836060015163ffffffff168152602001836080015163ffffffff1681526020018360a0015163ffffffff1681526020016101c960009054906101000a900462ffffff1662ffffff1681526020016101c960039054906101000a900462ffffff1662ffffff1681526020016101c960069054906101000a900462ffffff1662ffffff1681526020016101ce60009054906101000a900462ffffff1662ffffff1681526020016101ce60039054906101000a900462ffffff1662ffffff1681526020016101ce60069054906101000a900462ffffff1662ffffff1681526020016101ca5481526020016101cb54815260200184600001518152602001846020015181526020018460400151815260200184606001518152602001846080015181526020018460a0015181526020018460c0015181526020018460e001518152602001846101000151815260200184610120015181526020018461014001518152602001846101600151815260200184610180015163ffffffff168152602001846101a0015163ffffffff168152602001846101c0015163ffffffff168152602001846101e001518152602001846102000151815260200184610220015181526020016101d060089054906101000a900462ffffff1662ffffff1681526020016101d060119054906101000a900462ffffff1662ffffff1681526020016101d0600b9054906101000a900462ffffff1662ffffff1681526020016101d0600e9054906101000a900462ffffff1662ffffff16815250905073c7a19772216604277a629d0642826360c0541ae663353fd196858989898d876040518763ffffffff1660e01b81526004016127a4969594939291906158e9565b60006040518083038186803b1580156127bc57600080fd5b505af41580156127d0573d6000803e3d6000fd5b505050506127db3390565b6101c75460018601546040805192835263ffffffff8083166020850152600160201b90920490911682820152516001600160a01b0392909216917fd4f4eda7fb0fd42c44eceae5e61ca3734aa4c9843303a9bed659b38d6872b26a9181900360600190a25050505050505050565b612851613bf0565b6101c75460009081526101df6020526040902061286d33613c49565b61287633613ce0565b60018101546000906128979063ffffffff600160201b8204811691166156bf565b63ffffffff16421180156128ca57506101c75460009081526101d96020908152604080832033845290915290205460ff16155b15612904576128d833611b32565b6101c75460009081526101d9602090815260408083203384529091529020805460ff1916600117905590505b3360009081526101da60205260408120546129209083906155c7565b90508047101560405180604001604052806002815260200161313360f01b8152509061295f5760405162461bcd60e51b815260040161161291906154a7565b503360008181526101da60205260408082208290555190919083908381818185875af1925050503d80600081146129b2576040519150601f19603f3d011682016040523d82523d6000602084013e6129b7565b606091505b50509050806129d85760405162461bcd60e51b81526004016116129061567b565b60405182815233907f0ba90eb685b3b0006a3c394dd506a37e5e136aa5340c16793a2d546bd6721b8f9060200160405180910390a250505050612a1b600160c955565b565b612a25612fe3565b612a415760405162461bcd60e51b8152600401611612906154d7565b6040805180820190915260018152600360fc1b60208201526001600160a01b038416612a805760405162461bcd60e51b815260040161161291906154a7565b506040805180820190915260018152600360fc1b60208201526001600160a01b038316612ac05760405162461bcd60e51b815260040161161291906154a7565b506040805180820190915260018152600360fc1b60208201526001600160a01b038216612b005760405162461bcd60e51b815260040161161291906154a7565b506101e580546001600160a01b039485166001600160a01b0319918216179091556101e6805493851693909116929092179091556101c3805491909216600160281b02600160281b600160c81b0319909116179055565b6000611b2d600080516020615e9d833981519152335b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b612ba0612fe3565b612bbc5760405162461bcd60e51b8152600401611612906154d7565b604080518082019091526002815261313960f01b6020820152600563ffffffff831611612bfc5760405162461bcd60e51b815260040161161291906154a7565b506101c3805463ffffffff191663ffffffff92909216919091179055565b612c22612fe3565b612c3e5760405162461bcd60e51b8152600401611612906154d7565b620186a0612c5260608301604084016155f0565b612c6260408401602085016155f0565b612c6f60208501856155f0565b612c79919061560d565b612c83919061560d565b62ffffff16111560405180604001604052806002815260200161313160f01b81525090612cc35760405162461bcd60e51b815260040161161291906154a7565b50612cd160208201826155f0565b6101c9805462ffffff191662ffffff92909216919091179055612cfa60408201602083016155f0565b6101c9805462ffffff9290921663010000000265ffffff00000019909216919091179055612d2e60608201604083016155f0565b6101c9805462ffffff928316600160301b0268ffffff000000000000198216811792839055612d6d93630100000090930483169290811691161761560d565b612d7f9062ffffff16620186a0615948565b63ffffffff166101cb5550565b612d94613bf0565b6101c7546101d6546101c3546040516362d764b560e01b8152600481019390935260248301919091526001600160a01b038084166044840152600160281b9091041660648201526101df60848201526101e460a482015273c7a19772216604277a629d0642826360c0541ae6906362d764b59060c40160006040518083038186803b158015612e2257600080fd5b505af4158015612e36573d6000803e3d6000fd5b505050506120b7600160c955565b60008181526101df602052604081206101c754831115612e675750600092915050565b600a8101546101cf5460009190612e8290620186a09061556b565b612e8c91906155a0565b6009830154612ea79190600160301b900462ffffff166155c7565b9050600082600901600201548210612ec357600b830154612ec5565b815b95945050505050565b60008181526101df602052604090206101c75460609190831115612f125760408051600180825281830190925290602080830190803683370190505b509392505050565b600081600701546001600160401b03811115612f3057612f30615700565b604051908082528060200260200182016040528015612f59578160200160208202803683370190505b5090508160060154600003612f6f579392505050565b60005b8260070154811015612f0a5760008581526101dd6020908152604080832084845290915290205482516001600160a01b0390911690839083908110612fb957612fb96155da565b6001600160a01b039092166020928302919091019091015280612fdb81615965565b915050612f72565b6000611b2d600080516020615efd83398151915233612b6d565b613005612b57565b6130215760405162461bcd60e51b815260040161161290615630565b6101c38054911515600160201b0264ff0000000019909216919091179055565b613049613bf0565b61305233613c49565b3360009081526101d760209081526040918290205482518084019093526002835261062760f31b9183019190915261309d5760405162461bcd60e51b815260040161161291906154a7565b503360009081526101d760209081526040808320805493905580518082019091526002815261062760f31b91810191909152478211156130f05760405162461bcd60e51b815260040161161291906154a7565b50604051600090339083908381818185875af1925050503d8060008114613133576040519150601f19603f3d011682016040523d82523d6000602084013e613138565b606091505b50509050806131595760405162461bcd60e51b81526004016116129061567b565b5050612a1b600160c955565b61316d612fe3565b6131895760405162461bcd60e51b8152600401611612906154d7565b60405163430021db60e11b81526002604360981b019063860043b690611a0f9030908590600401615522565b6131bd612fe3565b6131d95760405162461bcd60e51b8152600401611612906154d7565b60405163662aa11d60e01b81526002604360981b019063662aa11d90611a0f9030908590600401615522565b6101e5546101e654604051631711922960e31b81526000926001600160a01b039081169263b88c91489261323f9290911690600401614de8565b602060405180830381865afa15801561325c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613280919061597e565b6001600160801b0316905090565b613296612fe3565b6132b25760405162461bcd60e51b8152600401611612906154d7565b6101c75460009081526101df6020526040902060018101546132e39063ffffffff600160201b8204811691166156bf565b63ffffffff164211806132ff5750600181015463ffffffff1642105b604051806040016040528060018152602001600d60fa1b815250906133375760405162461bcd60e51b815260040161161291906154a7565b508263ffffffff168463ffffffff16111560405180604001604052806002815260200161189b60f11b815250906133815760405162461bcd60e51b815260040161161291906154a7565b50604080518082019091526002815261031360f41b6020820152876133b95760405162461bcd60e51b815260040161161291906154a7565b50506101c8949094556101d6929092556101d0805463ffffffff938416600160201b0267ffffffffffffffff1990911693909216929092171790556101cd919091556101d3805462ffffff90921662ffffff19909216919091179055565b60008281526065602052604090206001015461343281613d8e565b6117738383613e1e565b613444612fe3565b6134605760405162461bcd60e51b8152600401611612906154d7565b600061347260808301606084016155f0565b61348260608401604085016155f0565b61349260408501602086016155f0565b61349f60208601866155f0565b6134a9919061560d565b6134b3919061560d565b6134bd919061560d565b62ffffff169050620186a063ffffffff16811460405180604001604052806002815260200161313160f01b815250906135095760405162461bcd60e51b815260040161161291906154a7565b5061351760208301836155f0565b6101d0805462ffffff92909216600160701b0262ffffff60701b1990921691909117905561354b60408301602084016155f0565b6101d0805462ffffff92909216600160581b0262ffffff60581b1990921691909117905561357f60608301604084016155f0565b6101d0805462ffffff92909216600160881b0262ffffff60881b199092169190911790556135b360808301606084016155f0565b6101d060086101000a81548162ffffff021916908362ffffff1602179055505050565b6101c75460009081526101df6020526040812081806135f485613638565b60018401549091506136159063ffffffff600160201b8204811691166156bf565b63ffffffff1642111561362e5761362b85611b32565b91505b612ec582826155c7565b6001600160a01b03811660009081526101e06020908152604080832080548085526101df9093529083206101c7549192909111158061369c5750815460009081526101d9602090815260408083206001600160a01b038816845290915290205460ff165b156136c0575050506001600160a01b031660009081526101da602052604090205490565b6001600160a01b03841660008181526101da6020908152604080832054865484526101dc83528184209484529390915281205460038401546009850154919291620186a09161371a91600160481b900462ffffff1661556b565b61372491906155a0565b90506000846006015460001461375857846006015482866003015461374991906155b4565b61375391906155a0565b61375b565b60005b865460009081526101db60205260409020549091506001600160a01b03808a169116036137b85784600601546000036137ab5781856003015461379e91906155b4565b6137a890856155c7565b93505b6137b582856155c7565b93505b821561381c57855460009081526101db60205260409020546001600160a01b031661380557828560060154836137ee91906155a0565b6137f8919061556b565b61380290856155c7565b93505b61380f838261556b565b61381990856155c7565b93505b50919695505050505050565b600054610100900460ff16158080156138485750600054600160ff909116105b806138625750303b158015613862575060005460ff166001145b6138c55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611612565b6000805460ff1916600117905580156138e8576000805461ff0019166101001790555b6101e580546001600160a01b03199081166001600160a01b038d8116919091179092556101e6805482168c84161790556101c6805482168884161790556101c38054600160281b600160c81b031916600160281b8c8516021790556101ea805482168684161790556101c4805482168984169081179091556101c58054909216928a169290921790556040516336b91f2b60e01b81526336b91f2b90613992908a90600401614de8565b600060405180830381600087803b1580156139ac57600080fd5b505af11580156139c0573d6000803e3d6000fd5b505050506002604360981b016001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a0657600080fd5b505af1158015613a1a573d6000803e3d6000fd5b505050506002604360981b016001600160a01b031663f098767a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613a6057600080fd5b505af1158015613a74573d6000803e3d6000fd5b50505050613a80614090565b6101c7805460009081526101df6020526040902060018101805463ffffffff19164263ffffffff16179055905481556101cd54600690910155613ac48484846115eb565b8015613b0a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b600054610100900460ff16612a1b5760405162461bcd60e51b81526004016116129061540c565b600054610100900460ff16613b645760405162461bcd60e51b81526004016116129061540c565b612a1b614174565b600054610100900460ff16613b935760405162461bcd60e51b81526004016116129061540c565b612a1b6141a7565b6119bb8282613d98565b600082815260656020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b600260c95403613c425760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611612565b600260c955565b6101c354604051632992684f60e01b81526101e060048201526101e160248201526101d7604482015263ffffffff90911660648201526001600160a01b038216608482015273c7a19772216604277a629d0642826360c0541ae690632992684f9060a40160006040518083038186803b158015613cc557600080fd5b505af4158015613cd9573d6000803e3d6000fd5b5050505050565b6001600160a01b03811660009081526101e0602052604090206101c754815410613d08575050565b805460009081526101d9602090815260408083206001600160a01b038616845290915290205460ff16613d7e57613d3e82613638565b6001600160a01b03831660008181526101da6020908152604080832094909455845482526101d981528382209282529190915220805460ff191660011790555b6101c754905550565b600160c955565b6120b781336141ce565b613da28282612b6d565b6119bb5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff19166001179055613dda3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b613e288282612b6d565b156119bb5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6101e5546001600160a01b0316336001600160a01b03161460405180604001604052806002815260200161189960f11b81525090613ed65760405162461bcd60e51b815260040161161291906154a7565b506101c75460008181526101df602090815260408083206101e38352818420546001600160401b03891685526101e78452828520549585526101e184528285206001600160a01b0390961680865295909352928190206101c35491516310d481af60e11b8152600481018590526024810182905263ffffffff9092166044830152929391929073c7a19772216604277a629d0642826360c0541ae6906321a9035e9060640160006040518083038186803b158015613f9357600080fd5b505af4158015613fa7573d6000803e3d6000fd5b50505050613fb58482614227565b60048101546000808080613fc88a6144a0565b93509350935093506000613fdf8b60001c8761456b565b90506000613ff98662ffffff8087169086168f8e8e614611565b80516020820151919250906000816003811115614018576140186152ca565b0361402e5761402888888d614a05565b90925090505b60058a0180546002919060ff60401b1916600160401b83021790555082604001516101e360006101c75481526020019081526020016000208190555061407e8b8f60001c6101c754858886614b4a565b50505050505050505050505050505050565b660e35fa931a00006101c88190556101d655600a6101cd556101c38054603c63ffffffff199091161790556101d080546001600160a01b0319166f3a980144380007d0000001a4000001a41790556101c9805468ffffffffffffffffff199081166664003a980005dc17918290556101ce80549091166801117000fde80088b81790556113886101ca556141339062ffffff6301000000909104166105dc61560d565b6141459062ffffff16620186a0615948565b63ffffffff166101cb5560056101d48190556101e85560036101d1556101d3805462ffffff19166103e8179055565b600054610100900460ff1661419b5760405162461bcd60e51b81526004016116129061540c565b6097805460ff19169055565b600054610100900460ff16613d875760405162461bcd60e51b81526004016116129061540c565b6141d88282612b6d565b6119bb576141e581614bab565b6141f0836020614bbd565b6040516020016142019291906159a7565b60408051601f198184030181529082905262461bcd60e51b8252611612916004016154a7565b600e820154600c8301546003830154600091620186a091614248919061556b565b61425291906155a0565b6101c354604051919250600091600160281b9091046001600160a01b03169083908381818185875af1925050503d80600081146142ab576040519150601f19603f3d011682016040523d82523d6000602084013e6142b0565b606091505b50509050806143015760405162461bcd60e51b815260206004820181905260248201527f4661696c656420746f2073656e6420457468657220746f2074726561737572796044820152606401611612565b6101d4546101e954101561440e5760016101e9600082825461432391906155c7565b90915550506003840154600090620186a09061434090869061556b565b61434a91906155a0565b6101ea546040519192506001600160a01b0316908290600081818185875af1925050503d8060008114614399576040519150601f19603f3d011682016040523d82523d6000602084013e61439e565b606091505b505080925050816144085760405162461bcd60e51b815260206004820152602e60248201527f4661696c656420746f2073656e64205365656420457468657220746f2070726960448201526d1e99481c1bdbdb081dd85b1b195d60921b6064820152608401611612565b60009350505b600f850154600d860154604051600162beb8ff60e01b031981526004810188905260248101879052604481018690526064810192909252608482015273c7a19772216604277a629d0642826360c0541ae69063ff4147019060a40160006040518083038186803b15801561448157600080fd5b505af4158015614495573d6000803e3d6000fd5b505050505050505050565b6101c75460009081526101df6020526040812060098101548291829182919062ffffff8082169184916144db916301000000900416836155c7565b600a8401546101cf549192506000916144f890620186a09061556b565b61450291906155a0565b600985015461451d9190600160301b900462ffffff166155c7565b905060008460090160020154821061453957600b85015461453b565b815b905061454783826155c7565b90506000614558620186a08c615a16565b9b919a5093985091965090945050505050565b6101c75460009081526101df60205260409081902090516327dba2ff60e11b81526004810184905260248101839052604481018290526060919073c7a19772216604277a629d0642826360c0541ae690634fb745fe90606401600060405180830381865af41580156145e1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526146099190810190615a2a565b949350505050565b60408051606081018252600080825260208201819052918101919091526040805160e0810182526101c75480825260208083018890526101d154838501526101d2546060840152608083018b905260a083018a905260c0830189905260009182526101df9052828120925163108c9e0360e11b815291929091829173c7a19772216604277a629d0642826360c0541ae6916321193c06916146be9187918a918c906101e290600401615c24565b6040805180830381865af41580156146da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146fe91906156dc565b6040805160c0810182526101c7548152602081018e90528082018d9052606081018c9052608081018490526101d35462ffffff1660a08201529051631585364760e31b8152929450909250906000908190819073c7a19772216604277a629d0642826360c0541ae69063ac29b238906147859087908d906101df906101db90600401615dac565b606060405180830381865af41580156147a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147c69190615de0565b9194509250905060028260038111156147e1576147e16152ca565b036148895760016101cf60008282546147fa91906155c7565b90915550506101c75460408051918252600160208301526000908201526001600160a01b038a16907fe74013133fb67b03a3cba620837d933f19e9141c42fbf501232300c7f981fc639060600160405180910390a26040518060600160405280848152602001836003811115614872576148726152ca565b8152602001868152509750505050505050506149fb565b60405163d984928f60e01b815273c7a19772216604277a629d0642826360c0541ae69063d984928f906148d29087908d906101df906101dd906101de906101dc90600401615e1d565b606060405180830381865af41580156148ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149139190615de0565b91945092509050600382600381111561492e5761492e6152ca565b036149c55760016101cf600082825461494791906155c7565b90915550506101d1546101d25410614962576101d254614971565b6101d2546149719060016155c7565b6101d2556101c754604080519182526000602083015281018290526001600160a01b038a16907fe74013133fb67b03a3cba620837d933f19e9141c42fbf501232300c7f981fc639060600160405180910390a25b60405180606001604052808481526020018360038111156149e8576149e86152ca565b8152602001868152509750505050505050505b9695505050505050565b6000808362ffffff16851015614b21576101c7546101cf54604051630633166360e01b8152600481019290925260248201526001600160a01b03841660448201526101df60648201526101da6084820152600090819073c7a19772216604277a629d0642826360c0541ae69063063316639060a4016040805180830381865af4158015614a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614aba91906156dc565b60006101cf556101c7546040805191825260208201839052810183905291935091506001600160a01b038616907f3f88442eb3441ef91803cd74336f2222c81a2d7f987cb61024e76b1b02eeecfb9060600160405180910390a2925060019150614b429050565b60016101cf6000828254614b3591906155c7565b9091555060009250829150505b935093915050565b806003811115614b5c57614b5c6152ca565b866001600160a01b03167fc338cfe35c3d868fb81af4e8541c0468d009b25f0849de36101d3369ee3667ef87878787604051614b9b9493929190615e60565b60405180910390a3505050505050565b60606115e56001600160a01b03831660145b60606000614bcc83600261556b565b614bd79060026155c7565b6001600160401b03811115614bee57614bee615700565b6040519080825280601f01601f191660200182016040528015614c18576020820181803683370190505b509050600360fc1b81600081518110614c3357614c336155da565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110614c6257614c626155da565b60200101906001600160f81b031916908160001a9053506000614c8684600261556b565b614c919060016155c7565b90505b6001811115614d09576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110614cc557614cc56155da565b1a60f81b828281518110614cdb57614cdb6155da565b60200101906001600160f81b031916908160001a90535060049490941c93614d0281615e85565b9050614c94565b508315614d585760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401611612565b9392505050565b600060208284031215614d7157600080fd5b81356001600160e01b031981168114614d5857600080fd5b80356001600160a01b0381168114614da057600080fd5b919050565b600080600060608486031215614dba57600080fd5b614dc384614d89565b9250614dd160208501614d89565b9150614ddf60408501614d89565b90509250925092565b6001600160a01b0391909116815260200190565b60008060408385031215614e0f57600080fd5b614e1883614d89565b946020939093013593505050565b60008060408385031215614e3957600080fd5b82359150614e4960208401614d89565b90509250929050565b6001600160401b03811681146120b757600080fd5b600060208284031215614e7957600080fd5b8135614d5881614e52565b600060208284031215614e9657600080fd5b5035919050565b600060208284031215614eaf57600080fd5b614d5882614d89565b600060608284031215614eca57600080fd5b82606083011115614eda57600080fd5b50919050565b600080600060608486031215614ef557600080fd5b8335614f0081614e52565b9250614f0e60208501614d89565b9150604084013590509250925092565b60008060408385031215614f3157600080fd5b50508035926020909101359150565b63ffffffff811681146120b757600080fd5b600080600060608486031215614f6757600080fd5b8335614f7281614f40565b95602085013595506040909401359392505050565b805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e0830152610100808201518184015250610120808201518184015250610140808201518184015250610160808201518184015250610180808201516150198285018263ffffffff169052565b50506101a08181015163ffffffff81168483015250506101c08181015163ffffffff81168483015250506101e08181015190830152610200808201519083015261022090810151910152565b60006105c0820190508f825263ffffffff8f16602083015263ffffffff8e16604083015263ffffffff8d1660608301528b60808301528a60a08301528960c08301528860e0830152876101008301528661012083015261511761014083018762ffffff80825116835280602083015116602084015280604083015116604084015250606081015163ffffffff80821660608501528060808401511660808501528060a08401511660a085015250505050565b845162ffffff9081166102008401526020860151811661022084015260408601518116610240840152606086015181166102608401526080860151811661028084015260a0860151166102a083015260c08501516102c083015260e08501516102e083015283516103008301526020840151610320830152604084015161034083015260608401516103608301526151b3610380830184614f87565b9f9e505050505050505050505050505050565b6000602082840312156151d857600080fd5b8135614d5881614f40565b6020808252825182820181905260009190848201906040850190845b818110156152245783516001600160a01b0316835292840192918401916001016151ff565b50909695505050505050565b60006020828403121561524257600080fd5b81358015158114614d5857600080fd5b62ffffff811681146120b757600080fd5b60008060008060008060c0878903121561527c57600080fd5b863595506020870135945060408701359350606087013561529c81614f40565b925060808701356152ac81614f40565b915060a08701356152bc81615252565b809150509295509295509295565b634e487b7160e01b600052602160045260246000fd5b600060e0820190508882528760208301528660408301528560608301528460808301526001600160401b03841660a08301526003831061533057634e487b7160e01b600052602160045260246000fd5b8260c083015298975050505050505050565b60006080828403121561535457600080fd5b82608083011115614eda57600080fd5b60008060008060008060008060006101208a8c03121561538357600080fd5b61538c8a614d89565b985061539a60208b01614d89565b97506153a860408b01614d89565b96506153b660608b01614d89565b95506153c460808b01614d89565b94506153d260a08b01614d89565b93506153e060c08b01614d89565b92506153ee60e08b01614d89565b91506153fd6101008b01614d89565b90509295985092959850929598565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60005b8381101561547257818101518382015260200161545a565b50506000910152565b60008151808452615493816020860160208601615457565b601f01601f19169290920160200192915050565b602081526000614d58602083018461547b565b6000602082840312156154cc57600080fd5b8151614d5881614e52565b6020808252602b908201527f4d75737420686176652061646d696e20726f6c6520746f20706572666f726d2060408201526a3a3434b99030b1ba34b7b760a91b606082015260800190565b6001600160a01b0392831681529116602082015260400190565b60006020828403121561554e57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561558557615585615555565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826155af576155af61558a565b500490565b818103818111156115e5576115e5615555565b808201808211156115e5576115e5615555565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561560257600080fd5b8135614d5881615252565b62ffffff81811683821601908082111561562957615629615555565b5092915050565b6020808252602b908201527f4d7573742068617665206f776e657220726f6c6520746f20706572666f726d2060408201526a3a3434b99030b1ba34b7b760a91b606082015260800190565b60208082526024908201527f4661696c656420746f2073656e6420457468657220746f20626c617374207769604082015263373732b960e11b606082015260800190565b63ffffffff81811683821601908082111561562957615629615555565b600080604083850312156156ef57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052604160045260246000fd5b60405161024081016001600160401b038111828210171561573957615739615700565b60405290565b8051614da081614f40565b6000610240828403121561575d57600080fd5b615765615716565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101408084015181830152506101608084015181830152506101806157ed81850161573f565b908201526101a06157ff84820161573f565b908201526101c061581184820161573f565b908201526101e083810151908201526102008084015190820152610220928301519281019290925250919050565b600060c0828403121561585157600080fd5b60405160c081018181106001600160401b038211171561587357615873615700565b604052825161588181615252565b8152602083015161589181615252565b602082015260408301516158a481615252565b604082015260608301516158b781614f40565b606082015260808301516158ca81614f40565b608082015260a08301516158dd81614f40565b60a08201529392505050565b60006105a0820190508782526020878184015286604084015285606084015263ffffffff8516608084015260a083018460005b60288110156159395781518352918301919083019060010161591c565b50505050979650505050505050565b63ffffffff82811682821603908082111561562957615629615555565b60006001820161597757615977615555565b5060010190565b60006020828403121561599057600080fd5b81516001600160801b0381168114614d5857600080fd5b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516159d9816017850160208801615457565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615a0a816028840160208801615457565b01602801949350505050565b600082615a2557615a2561558a565b500690565b600060208284031215615a3c57600080fd5b81516001600160401b0380821115615a5357600080fd5b818401915084601f830112615a6757600080fd5b815181811115615a7957615a79615700565b604051601f8201601f19908116603f01168101908382118183101715615aa157615aa1615700565b81604052828152876020848701011115615aba57600080fd5b615acb836020830160208801615457565b979650505050505050565b805462ffffff8082168452808260181c166020850152808260301c166040850152808260481c166060850152615b1860808501828460601c1662ffffff169052565b615b2e60a08501828460781c1662ffffff169052565b5050600181015460c08301526002015460e090910152565b8054825260018101546020830152600281015460408301526003810154606083015260048101546080830152600581015460a0830152600681015460c0830152600781015460e083015260088101546101008301526009810154610120830152600a810154610140830152600b810154610160830152600c81015463ffffffff808216610180850152615be76101a08501828460201c1663ffffffff169052565b615bff6101c08501828460401c1663ffffffff169052565b5050600d8101546101e0830152600e810154610200830152600f015461022090910152565b6107008101818760005b6007811015615c4d578151835260209283019290910190600101615c2e565b5050506001600160a01b03861660e08301528454610100830152600185015463ffffffff808216610120850152602082901c811661014085015260409190911c8116610160840152600286015461018084015260038601546101a084015260048601546101c084015260058601546101e084015260068601546102008401526007860154610220840152600886015462ffffff808216610240860152601882901c8116610260860152603082901c16610280850152604881901c82166102a0850152606881901c82166102c085015260881c166102e0830152615d37610300830160098701615ad6565b600c850154610400830152600d850154610420830152600e850154610440830152600f850154610460830152615d74610480830160108701615b46565b6106c08201939093526106e001529392505050565b8060005b6006811015611f8e578151845260209384019390910190600101615d8d565b6101208101615dbb8287615d89565b6001600160a01b039490941660c082015260e081019290925261010090910152919050565b600080600060608486031215615df557600080fd5b83519250602084015160048110615e0b57600080fd5b80925050604084015190509250925092565b6101608101615e2c8289615d89565b6001600160a01b039690961660c082015260e081019490945261010084019290925261012083015261014090910152919050565b8481528360208201528260408201526080606082015260006149fb608083018461547b565b600081615e9457615e94615555565b50600019019056feb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92965d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a2646970667358221220e45f617c28c455ccd0c8a1d05eeeb94a361382c5ba2955fc46e270b3fcfd0bdf64736f6c63430008100033
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.