Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 334,828 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Redeem | 16852754 | 19 secs ago | IN | 0 S | 0.0085972 | ||||
Redeem | 16852593 | 1 min ago | IN | 0 S | 0.00859721 | ||||
Redeem | 16852591 | 1 min ago | IN | 0 S | 0.0085972 | ||||
Redeem | 16852589 | 1 min ago | IN | 0 S | 0.0085972 | ||||
Redeem | 16852589 | 1 min ago | IN | 0 S | 0.0085972 | ||||
Redeem | 16852587 | 1 min ago | IN | 0 S | 0.00859721 | ||||
Redeem | 16852586 | 1 min ago | IN | 0 S | 0.0085965 | ||||
Redeem | 16852586 | 1 min ago | IN | 0 S | 0.00859721 | ||||
Redeem | 16852586 | 1 min ago | IN | 0 S | 0.00859721 | ||||
Redeem | 16852586 | 1 min ago | IN | 0 S | 0.00859721 | ||||
Redeem | 16852585 | 1 min ago | IN | 0 S | 0.00929742 | ||||
Redeem | 16852584 | 1 min ago | IN | 0 S | 0.00859721 | ||||
Redeem | 16852584 | 1 min ago | IN | 0 S | 0.00859651 | ||||
Redeem | 16852583 | 1 min ago | IN | 0 S | 0.00859721 | ||||
Redeem | 16852583 | 1 min ago | IN | 0 S | 0.00859575 | ||||
Redeem | 16852583 | 1 min ago | IN | 0 S | 0.0085972 | ||||
Redeem | 16852583 | 1 min ago | IN | 0 S | 0.00859721 | ||||
Redeem | 16852582 | 1 min ago | IN | 0 S | 0.0085972 | ||||
Redeem | 16852582 | 1 min ago | IN | 0 S | 0.00929742 | ||||
Redeem | 16852581 | 1 min ago | IN | 0 S | 0.00859651 | ||||
Redeem | 16852581 | 1 min ago | IN | 0 S | 0.00859721 | ||||
Redeem | 16852581 | 1 min ago | IN | 0 S | 0.0085972 | ||||
Redeem | 16852580 | 1 min ago | IN | 0 S | 0.00929742 | ||||
Redeem | 16852580 | 1 min ago | IN | 0 S | 0.00859721 | ||||
Redeem | 16852580 | 1 min ago | IN | 0 S | 0.00859651 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
16760778 | 9 hrs ago | 0.0216 S | ||||
16760756 | 9 hrs ago | 0.01925 S | ||||
16760737 | 9 hrs ago | 0.0216 S | ||||
16760724 | 9 hrs ago | 0.01925 S | ||||
16760701 | 9 hrs ago | 0.01925 S | ||||
16760671 | 9 hrs ago | 0.0216 S | ||||
16760671 | 9 hrs ago | 0.02560133 S | ||||
16760643 | 9 hrs ago | 0.01925 S | ||||
16760621 | 9 hrs ago | 0.01925 S | ||||
16760600 | 9 hrs ago | 0.0216 S | ||||
16760599 | 9 hrs ago | 0.01925003 S | ||||
16760577 | 9 hrs ago | 0.01925 S | ||||
16760546 | 9 hrs ago | 0.01925 S | ||||
16760526 | 9 hrs ago | 0.0216 S | ||||
16760524 | 9 hrs ago | 0.01925 S | ||||
16760506 | 9 hrs ago | 0.01925 S | ||||
16760484 | 9 hrs ago | 0.01925 S | ||||
16760481 | 9 hrs ago | 0.01925 S | ||||
16760471 | 9 hrs ago | 0.0216 S | ||||
16760456 | 9 hrs ago | 0.01925 S | ||||
16760452 | 9 hrs ago | 0.01925 S | ||||
16760451 | 9 hrs ago | 0.0216 S | ||||
16760440 | 9 hrs ago | 0.01925 S | ||||
16760418 | 9 hrs ago | 0.0216 S | ||||
16760415 | 9 hrs ago | 0.01925 S |
Loading...
Loading
Contract Name:
DiceGame
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.19; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { TransferHelper } from "./libraries/TransferHelper.sol"; contract DiceGame is Ownable { using TransferHelper for address; struct GameRound { bool fulfilled; // whether the request has been successfully fulfilled address user; uint256 totalBet; uint256 totalWinnings; uint256[] betAmts; uint256[] diceRollResult; } uint256 public constant BANANA_POINTS_PREMINT = 100_000_000 ether; uint256 public constant WIN69_MULTIPLIER = 10; uint256 public constant CALLBACK_GAS = 300_000; uint256 public constant MAX_OPERATOR_GAS = 1_000_000; uint256 public constant MAX_NUM_WORDS = 3; uint256 public constant DELIMITER = 1e18; uint8 public constant decimals = 18; string public constant name = "Banana Points"; string public constant symbol = "BPT"; uint256 public rollOperatorGas = 800_000; uint256 public immutable gamePeriod; address public coin; address public immutable V3Deployer; address public wrappedNative; address public immutable gameRngWallet; address public immutable rollOperator; address public faucet; /// @notice Timestamp when the geme ower uint256 public endTime; /// @notice Initial rate of tokens per coin uint256 public initialTokenRate; uint256 public gameId; uint256 public lastFulfilledGameId; // The total supply of points in existence uint256 public totalSupply; // Maps an address to their current balance mapping(address => uint256) private userBalances; // Maps a game ID to its round information mapping(uint256 => GameRound) private gameRounds; /* gameId --> GameRound */ // Maps an address to their game IDs mapping(address => uint256[]) public userGameIds; address[] oldFaucets; constructor( address _gameRngWalletAddress, uint _gamePeriod, address _V3Deployer, address _rollOperator ) { gameRngWallet = _gameRngWalletAddress; if (_gameRngWalletAddress == address(0) || _V3Deployer == address(0)) revert ZeroValue(); if (_gamePeriod < 2 hours || _gamePeriod > 180 days) revert GamePeriod(); gamePeriod = _gamePeriod; rollOperator = _rollOperator; V3Deployer = _V3Deployer; transferOwnership(_V3Deployer); } event Transfer(address to, uint256 value); event MintPoints(address recipient, uint256 pointsAmount); event BurnPoints(address from, uint256 pointsAmount); event Redeem(address user, uint256 amount); event PurchasePoints(address user, uint256 paymentAmount); event Bet(uint256 gameId, address user, uint256 totalBetAmt); event BetFailed(address user); event ClaimAirDrop(address user, uint256 amount); error AmountOfEthSentIsTooSmall(uint256 sent, uint256 minimum); error InvalidGameId(uint256 id); error InvalidLength(); error InvaliddiceRollResult(uint256 id); error GamePeriod(); error ZeroValue(); error NotEnoughCoinBalance(uint256 want, uint256 have); error Forbidden(); // Modifiers modifier shouldGameIsNotOver() { require(gameNotOver(), "game over"); _; } modifier shouldGameIsOver() { require(gameOver(), "game is NOT over"); _; } /// @notice Receive ETH and forward to `sponsorWallet`. receive() external payable { (bool success, ) = gameRngWallet.call{ value: msg.value }(""); require(success); } /** * @notice Starts a new game with specific parameters, initial token rate, etc. * non-zero initial token rate, and game not already started (initialTokenRate == 0). * @param _initialTokenRate The initial rate used within the game logic, set at the start and never changed afterward. * @param _coin address of Coin token for this Game * @custom:modifier onlyOwner Restricts the function's execution to the contract's owner. */ function startGame( uint _initialTokenRate, address _coin, address _wrappedNative, address _faucet ) external payable onlyOwner { // Ensure the initial token rate is not already set require(initialTokenRate == 0, "o-o"); if (_coin == address(0) || _faucet == address(0)) revert ZeroValue(); // Initialize the initial token rate and calculate the end time based on the current timestamp initialTokenRate = _initialTokenRate; coin = _coin; wrappedNative = _wrappedNative; endTime = block.timestamp + gamePeriod; if (msg.value > 0) { (bool success, ) = gameRngWallet.call{ value: msg.value }(""); require(success); } faucet = _faucet; _mintPoints(_faucet, BANANA_POINTS_PREMINT); } /// @notice Retrieves the balance of a given account /// @dev Returns the current balance stored in `userBalances` /// @param account The address of the user whose balance we want to retrieve /// @return The balance of the user function balanceOf(address account) public view returns (uint256) { return userBalances[account]; } /// @notice Retrieves info of particular game id /// @param _gameId game number/id /// @return gameInfo GameRound struct function getGameRoundInfo(uint256 _gameId) public view returns (GameRound memory gameInfo) { gameInfo = gameRounds[_gameId]; } /// @notice Retrieves the list of game IDs associated with a given user /// @dev Fetches the array of game IDs from `userGameIds` using `.values()` /// @param user The address of the user whose game IDs we want to retrieve /// @return ids An array of game IDs that the user participated in function getUserGameIds(address user) public view returns (uint256[] memory ids) { ids = userGameIds[user]; } /// @notice Retrieves the number of games a user has participated in /// @dev Calculates the length of the user's game IDs set /// @param user The address of the user whose number of games we want to know /// @return num The number of games the user has participated in function getUserGamesNumber(address user) public view returns (uint256 num) { num = userGameIds[user].length; } // @notice Retrieves the last game information for a given user /// @dev Fetches the last game ID and corresponding round info from `userGameIds` and `gameRounds` /// @param user The address of the user whose last game information we want to retrieve /// @return id The ID of the last game the user participated in /// @return round The GameRound struct containing the details of the game round function getUserLastGameInfo( address user ) public view returns (uint256 id, GameRound memory round) { uint256 length = userGameIds[user].length; if (length > 0) { id = userGameIds[user][length - 1]; round = gameRounds[id]; } } /// @notice Determines whether the game is still ongoing or not /// @dev Compares the current block timestamp against `endTime`; also ensures that the game has started by requiring `_endTime` to be non-zero /// @return Whether the current time is before the game's end time (`true`) or after (`false`) function gameNotOver() public view returns (bool) { uint256 _endTime = endTime; _checkZero(_endTime); return block.timestamp < _endTime; } /** * @notice Checks if the game has been concluded based on the time limit. * @dev Returns true if the current block timestamp exceeds the end time of the game by 10 minutes. * This implies a grace period of 10 minutes after the official end time before declaring the game over. * The function requires that `endTime` is set and the game has started, otherwise it reverts with an error message. * * @return A boolean value indicating whether the game is over (true) or not (false). */ function gameOver() public view returns (bool) { uint256 _endTime = endTime; _checkZero(_endTime); return (block.timestamp > _endTime && gameId == lastFulfilledGameId); } struct GameState { uint256 gameId; uint256 betNumber; } /// @dev This function returns the state of games that have not yet been fulfilled. /// It constructs an array of `GameState` structures representing each unfulfilled game's /// ID and the count of bets placed in that game round. /// The function only includes games with IDs greater than `lastFulfilledGameId`. /// @return state An array of `GameState` structs for each unfulfilled game. function getGameState() public view returns (GameState[] memory state) { if (gameId > lastFulfilledGameId) { uint256 requests = gameId - lastFulfilledGameId; state = new GameState[](requests); uint256 index; while (lastFulfilledGameId + index < gameId) { uint256 id = lastFulfilledGameId + index + 1; state[index].gameId = id; state[index].betNumber = gameRounds[id].betAmts.length; index++; } } } /// @notice Allows a user to place a bet on a dice roll(s), record the bet details, and request randomness /// @dev Transfers the required ETH to sponsor wallet and creates a new game round with provided bets /// @param _betAmts An array of amounts representing individual bets for each roll of the dice function bet(uint256[] memory _betAmts) external payable shouldGameIsNotOver { // user must send enough native for the callback // otherwise the transaction will fail uint256 minimumSend = tx.gasprice * CALLBACK_GAS; _checkAmount(minimumSend); // Transfer the received native to the gameRngWallet wallet to cover the callback transaction costs (bool success, ) = gameRngWallet.call{ value: msg.value }(""); require(success); _bet(msg.sender, _betAmts); } struct OperatorInput { address user; uint256[] betAmts; } /// @notice Allows roll operator to place batch bets for different users. Operator must add users to batch who /// have enough wrapped native tokens, have given approval for it, and have fulfilled their last game round /// @param _inputs encoded input for array of OperatorInput structs function bet(bytes calldata _inputs) external payable shouldGameIsNotOver { if (msg.sender != rollOperator) revert(); OperatorInput[] memory batchInfo = abi.decode(_inputs, (OperatorInput[])); uint length = batchInfo.length; if (length == 0 || length > 30) revert InvalidLength(); uint256 minimumSend = tx.gasprice * CALLBACK_GAS * length; uint256 gasAmt = tx.gasprice * rollOperatorGas; _checkAmount(minimumSend); OperatorInput memory info; uint successCount; for (uint i; i < length; ) { info = batchInfo[i]; try this.processBatchBet(info.user, info.betAmts) { unchecked { ++successCount; } } catch { emit BetFailed(info.user); } unchecked { ++i; } } uint refund; if (successCount > 0) { uint gasRandomizer = (msg.value * successCount) / length; refund = msg.value - gasRandomizer; (bool success, ) = gameRngWallet.call{ value: gasRandomizer }(""); require(success); (bool result, ) = wrappedNative.call( abi.encodeWithSignature( "withdrawTo(address,uint256)", msg.sender, gasAmt * successCount ) ); require(result, "withdrawTo"); } else { refund = msg.value; } if (refund > 0) { (bool success, ) = msg.sender.call{ value: refund }(""); require(success); } } function processBatchBet(address _user, uint[] memory _betAmts) external shouldGameIsNotOver { if (tx.origin != rollOperator) revert(); uint gasAmt; unchecked { gasAmt = tx.gasprice * rollOperatorGas; } wrappedNative.safeTransferFrom(_user, address(this), gasAmt); _bet(_user, _betAmts); } /// @notice Allows roll operator place bets for users /// @param _user Address of certain user /// @param _betAmts An array of amounts representing individual bets for each roll of the dice function bet(address _user, uint256[] memory _betAmts) external payable shouldGameIsNotOver { if (msg.sender != rollOperator) revert(); // msg.value must be enough to cover randomizer gas spends uint256 minimumSend = tx.gasprice * CALLBACK_GAS; // take from user gas amount*gas.price uint256 gasAmt = tx.gasprice * rollOperatorGas; _checkAmount(minimumSend); wrappedNative.safeTransferFrom(_user, address(this), gasAmt); (bool success, ) = wrappedNative.call( abi.encodeWithSignature("withdrawTo(address,uint256)", msg.sender, gasAmt) ); require(success, "withdrawTo"); // send to randomizer 200_000gas*gas.price for callback (bool result, ) = gameRngWallet.call{ value: msg.value }(""); require(result); _bet(_user, _betAmts); } function _bet(address _user, uint256[] memory betAmts) internal { (uint256 id, GameRound memory round) = getUserLastGameInfo(_user); require(round.fulfilled || id == 0, "last round not fulfilled"); // Check if the number of dice rolls is within the permitted range uint256 numWords = betAmts.length; require(numWords > 0 && numWords <= MAX_NUM_WORDS, "invalid betAmts"); // Calculate the total bet amount from the array of bets uint256 totalBetAmt; for (uint i; i < numWords; ) { // Each bet amount must be greater than zero _checkZero(betAmts[i]); totalBetAmt += betAmts[i]; unchecked { ++i; } } // Ensure the user has enough points to cover their total bet // It is possible to resend a bid for the same balance, // so this check is also added to the callback function require(totalBetAmt <= balanceOf(_user), "points are not enough"); _burnPoints(_user, totalBetAmt); unchecked { ++gameId; } uint256 _gameId = gameId; // Record the game round details in the contract state gameRounds[_gameId] = GameRound({ fulfilled: false, user: _user, totalBet: totalBetAmt, totalWinnings: 0, betAmts: betAmts, diceRollResult: new uint256[](betAmts.length) }); // Associate the game ID with the user's address userGameIds[_user].push(_gameId); emit Bet(_gameId, _user, totalBetAmt); } struct RandomData { uint256 id; uint256[] rn; } /** * @notice Fulfills the generation of random words if gas requirement is met * @dev Processes each `RandomData` entries until either all are processed or minimum remaining gas is not met * @param minRemainingGas The minimum amount of gas that must be left for the function to continue processing * @param randomData An array of `RandomData` structs containing the IDs and random number arrays to process * Requirements: * - Only callable by the `gameRngWallet`. * - Will stop processing if the remaining gas is less than `minRemainingGas`. * Emits a `RandomWordsFulfilled` event upon successful processing of an entry. * Uses the `_fulfillRandomWords` internal function to process each entry. */ function fulfillRandomWords(uint256 minRemainingGas, RandomData[] memory randomData) external { require(msg.sender == gameRngWallet, "invalid caller"); for (uint256 i; i < randomData.length; ) { if (gasleft() < minRemainingGas) { break; } _fulfillRandomWords(randomData[i].id, randomData[i].rn); unchecked { ++i; } } } /// @notice Records the result of dice rolls, updates the game round, and handles payouts /// @dev Only callable by the `gameRngWallet`. Checks if the round can be fulfilled /// @param _gameId The unique identifier of the game round that the dice roll results correspond to /// @param _randomWords The array of random numbers provided by off-chain gameRngWallet service /// Using the gameRngWallet service is free, meaning there is no subscription fee to pay. /// There is a gas cost incurred on-chain when gameRngWallet places the random number on-chain in response to a request, /// which the requester needs to pay for. function _fulfillRandomWords(uint256 _gameId, uint256[] memory _randomWords) private { unchecked { ++lastFulfilledGameId; } // Retrieve the game round using the _gameId GameRound storage round = gameRounds[_gameId]; uint256 totalBet = round.totalBet; if (_gameId != lastFulfilledGameId || totalBet == 0) { revert InvalidGameId(_gameId); } uint256 length = _randomWords.length; if (length != round.diceRollResult.length) { revert InvaliddiceRollResult(_gameId); } // Mark the round as fulfilled round.fulfilled = true; uint256 totalWinnings; uint256 bitDice; bool double3; for (uint i; i < length; ) { // Get the dice number between 1 and 6 uint256 num = (_randomWords[i] % 6) + 1; // Calculate winnings based on even dice numbers if (num % 2 == 0) { totalWinnings += round.betAmts[i] * 2; } // Special logic for determining 33 if (num == 3 && !double3 && bitDice & (1 << num) == (1 << num)) { double3 = true; } bitDice |= (1 << num); round.diceRollResult[i] = num; unchecked { ++i; } } // Special logic for determining winnings if the special 69 condition is met // or if the special 666 condition is met // or if the special repdigit condition is met if (length == 3) { //Repdigit if ((bitDice & (bitDice - 1)) == 0) { totalWinnings = 0; if (bitDice == 64) { // 666 uint256 balance = balanceOf(round.user); if (balance > 0) { _burnPoints(round.user, balance); } } } else if ((bitDice == 72 && !double3) || bitDice == 112) { // 69 totalWinnings = totalBet * WIN69_MULTIPLIER; } } if (totalWinnings > 0) { round.totalWinnings = totalWinnings; _mintPoints(round.user, totalWinnings); } } /** * @notice Allows users to purchase a specified amount of points. * @param desiredAmountOut The exact amount of points the user wants to purchase. */ function purchasePoints(uint256 desiredAmountOut) external shouldGameIsNotOver { uint256 paymentAmount = calculatePaymentAmount(desiredAmountOut); coin.safeTransferFrom(msg.sender, address(this), paymentAmount); _checkZero(desiredAmountOut); _mintPoints(msg.sender, desiredAmountOut); emit PurchasePoints(msg.sender, paymentAmount); } /** * @notice Calculates the payment amount required for purchasing a specific amount of points. * @param desiredPointsAmount The desired amount of points. * @return paymentAmount The corresponding amount of payment currency that can be purchased/sold for the specified points. */ function calculatePaymentAmount( uint256 desiredPointsAmount ) public view returns (uint256 paymentAmount) { uint256 tokenRate = initialTokenRate; if (tokenRate == 0) revert ZeroValue(); uint256 intermediate = desiredPointsAmount * DELIMITER; paymentAmount = intermediate / tokenRate; // Round up only for buying if (paymentAmount == 0 || intermediate % tokenRate > 0) { paymentAmount += 1; } } /** * @notice Calculates the points amount a user receives for a given coin amount. * @param paymentAmount Amount of the payment currency (e.g., ETH) used to purchase tokens. * @return pointsAmount The resulting amount of tokens that can be purchased for the specified `paymentAmount`. */ function calculatePointsAmount( uint256 paymentAmount ) public view returns (uint256 pointsAmount) { uint256 rate = initialTokenRate; if (rate == 0) revert ZeroValue(); pointsAmount = (paymentAmount * rate) / DELIMITER; } function sendLiquidity() external shouldGameIsOver onlyOwner returns (uint amount) { amount = coin.getBalance(); coin.safeTransfer(V3Deployer, amount); } function setOperatorGas(uint256 _operatorGas) external onlyOwner { _checkZero(_operatorGas); if (_operatorGas > MAX_OPERATOR_GAS) revert(); rollOperatorGas = _operatorGas; } function setFaucet(address _faucet) external onlyOwner { oldFaucets.push(faucet); faucet = _faucet; } function mint(address to, uint256 amount) external onlyOwner { _checkZero(amount); userBalances[to] += amount; totalSupply += amount; emit MintPoints(to, amount); } function transfer(address to, uint256 amount) external shouldGameIsNotOver returns (bool) { if (msg.sender != faucet) revert Forbidden(); if (to == address(0)) revert ZeroValue(); uint256 fromBalance = userBalances[msg.sender]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { userBalances[msg.sender] = fromBalance - amount; userBalances[to] += amount; } emit Transfer(to, amount); return true; } function getOldFaucets() external view returns (address[] memory _oldFaucets) { _oldFaucets = oldFaucets; } /// @notice Redeem points for tokens. /// @dev Burns points from the redeemer's balance and mints equivalent tokens. /// Emits a Redeem event upon success. /// Requires the game to be over. /// Requires the Token to have been set and the caller to have a non-zero point balance. /// @param signature 65 bytes signature for verify eligibility redeem tokens /// @param voteFor Vote option (must be 1, 2, or 3) function redeem(bytes calldata signature, uint voteFor) external shouldGameIsOver { require(voteFor > 0 && voteFor < 4, "vote must be 1, 2 or 3"); _checkSignature(signature, voteFor); uint256 amount = balanceOf(msg.sender); _checkZero(amount); _burnPoints(msg.sender, amount); (bool success, ) = V3Deployer.call( abi.encodeWithSignature("redeem(address,uint256,uint256)", msg.sender, amount, voteFor) ); require(success); emit Redeem(msg.sender, amount); } function _checkSignature(bytes calldata signature, uint voteFor) private view { bytes32 message = _withPrefix( keccak256(abi.encodePacked(msg.sender, block.chainid, address(this), voteFor)) ); require(ECDSA.recover(message, signature) == rollOperator, "invalid signature!"); } function _withPrefix(bytes32 _hash) private pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)); } /// @notice Mints points and assigns them to a specified account /// @dev Increments `userBalances` and `totalSupply` by the given `amount` /// @param to The address of the recipient to whom points are to be minted /// @param amount The quantity of points to be minted function _mintPoints(address to, uint256 amount) private { userBalances[to] += amount; totalSupply += amount; emit MintPoints(to, amount); } /// @notice Burns points from a specified account's balance /// @dev Decrements `userBalances` and `totalSupply` by the given `amount` /// @param from The address from which points are to be burned /// @param amount The quantity of points to be burned function _burnPoints(address from, uint256 amount) private { userBalances[from] -= amount; totalSupply -= amount; emit BurnPoints(from, amount); } function _checkZero(uint256 amount) private pure { require(amount > 0, "is zero"); } function _checkAmount(uint256 minimumSend) private { if (msg.value < minimumSend) { revert AmountOfEthSentIsTooSmall(msg.value, minimumSend); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// 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 Math { 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 SignedMath { /** * @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/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { 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 = Math.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(SignedMath.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, Math.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: GPL-2.0-or-later // https://github.com/Uniswap/v3-periphery/blob/main/contracts/libraries/TransferHelper.sol pragma solidity 0.8.19; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; library TransferHelper { /// @notice Transfers tokens from the targeted address to the given destination /// @notice Errors with 'STF' if transfer fails /// @param token The contract address of the token to be transferred /// @param from The originating address from which the tokens will be transferred /// @param to The destination address of the transfer /// @param value The amount to be transferred function safeTransferFrom(address token, address from, address to, uint256 value) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "BP-STF"); } /// @notice Transfers tokens from msg.sender to a recipient /// @dev Errors with ST if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer function safeTransfer(address token, address to, uint256 value) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20.transfer.selector, to, value) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "BP-ST"); } function getBalance(address token) internal view returns (uint256 balance) { bytes memory callData = abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)); (bool success, bytes memory data) = token.staticcall(callData); require(success && data.length >= 32); balance = abi.decode(data, (uint256)); } function getBalanceOf(address token, address target) internal view returns (uint256 balance) { bytes memory callData = abi.encodeWithSelector(IERC20.balanceOf.selector, target); (bool success, bytes memory data) = token.staticcall(callData); require(success && data.length >= 32); balance = abi.decode(data, (uint256)); } function safeApprove(address token, address spender, uint256 amount) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20.approve.selector, spender, amount) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "BP-SA"); } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "none" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_gameRngWalletAddress","type":"address"},{"internalType":"uint256","name":"_gamePeriod","type":"uint256"},{"internalType":"address","name":"_V3Deployer","type":"address"},{"internalType":"address","name":"_rollOperator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"minimum","type":"uint256"}],"name":"AmountOfEthSentIsTooSmall","type":"error"},{"inputs":[],"name":"Forbidden","type":"error"},{"inputs":[],"name":"GamePeriod","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"InvalidGameId","type":"error"},{"inputs":[],"name":"InvalidLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"InvaliddiceRollResult","type":"error"},{"inputs":[{"internalType":"uint256","name":"want","type":"uint256"},{"internalType":"uint256","name":"have","type":"uint256"}],"name":"NotEnoughCoinBalance","type":"error"},{"inputs":[],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gameId","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalBetAmt","type":"uint256"}],"name":"Bet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"BetFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"pointsAmount","type":"uint256"}],"name":"BurnPoints","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimAirDrop","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"pointsAmount","type":"uint256"}],"name":"MintPoints","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"paymentAmount","type":"uint256"}],"name":"PurchasePoints","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BANANA_POINTS_PREMINT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALLBACK_GAS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELIMITER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_NUM_WORDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_OPERATOR_GAS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"V3Deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WIN69_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_inputs","type":"bytes"}],"name":"bet","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256[]","name":"_betAmts","type":"uint256[]"}],"name":"bet","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_betAmts","type":"uint256[]"}],"name":"bet","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"desiredPointsAmount","type":"uint256"}],"name":"calculatePaymentAmount","outputs":[{"internalType":"uint256","name":"paymentAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"paymentAmount","type":"uint256"}],"name":"calculatePointsAmount","outputs":[{"internalType":"uint256","name":"pointsAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"coin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"faucet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minRemainingGas","type":"uint256"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256[]","name":"rn","type":"uint256[]"}],"internalType":"struct DiceGame.RandomData[]","name":"randomData","type":"tuple[]"}],"name":"fulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gameId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameNotOver","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameOver","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gamePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameRngWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gameId","type":"uint256"}],"name":"getGameRoundInfo","outputs":[{"components":[{"internalType":"bool","name":"fulfilled","type":"bool"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"totalBet","type":"uint256"},{"internalType":"uint256","name":"totalWinnings","type":"uint256"},{"internalType":"uint256[]","name":"betAmts","type":"uint256[]"},{"internalType":"uint256[]","name":"diceRollResult","type":"uint256[]"}],"internalType":"struct DiceGame.GameRound","name":"gameInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGameState","outputs":[{"components":[{"internalType":"uint256","name":"gameId","type":"uint256"},{"internalType":"uint256","name":"betNumber","type":"uint256"}],"internalType":"struct DiceGame.GameState[]","name":"state","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOldFaucets","outputs":[{"internalType":"address[]","name":"_oldFaucets","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserGameIds","outputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserGamesNumber","outputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserLastGameInfo","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"bool","name":"fulfilled","type":"bool"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"totalBet","type":"uint256"},{"internalType":"uint256","name":"totalWinnings","type":"uint256"},{"internalType":"uint256[]","name":"betAmts","type":"uint256[]"},{"internalType":"uint256[]","name":"diceRollResult","type":"uint256[]"}],"internalType":"struct DiceGame.GameRound","name":"round","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialTokenRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastFulfilledGameId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256[]","name":"_betAmts","type":"uint256[]"}],"name":"processBatchBet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"}],"name":"purchasePoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"voteFor","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rollOperatorGas","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sendLiquidity","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_faucet","type":"address"}],"name":"setFaucet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_operatorGas","type":"uint256"}],"name":"setOperatorGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialTokenRate","type":"uint256"},{"internalType":"address","name":"_coin","type":"address"},{"internalType":"address","name":"_wrappedNative","type":"address"},{"internalType":"address","name":"_faucet","type":"address"}],"name":"startGame","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userGameIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wrappedNative","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
610100346200023a57601f62002fcf38819003918201601f191683019291906001600160401b038411838510176200023f5781608092849260409687528339810103126200023a57620000528162000255565b60208201516200007260606200006a86860162000255565b940162000255565b906200007e336200026a565b620c350060015560c08390526001600160a01b039283161580156200022f575b6200021e57611c208110801562000211575b620002005760805260e0528160a05233816000541603620001bd578116156200016a57620000de906200026a565b51612d1d9081620002b28239608051818181610b10015261146c015260a051818181610df001528181611cef0152611dc8015260c051818181602a015281816102fa015281816105fe01528181610a120152818161101a015281816115360152611848015260e05181818161095101528181610d72015281816116ab015281816117240152611ed00152f35b815162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b6064835162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b845163c8e9ad0d60e01b8152600490fd5b5062ed4e008111620000b0565b8451637c946ed760e01b8152600490fd5b50828416156200009e565b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036200023a57565b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a356fe60806040908082526004908136101561005e575b505050361561002157600080fd5b600080808080347f00000000000000000000000000000000000000000000000000000000000000005af1610053612275565b501561005b57005b80fd5b600092833560e01c91826306fdde0314611f1557508163090594b314611ea75781630a68ed3e14611e845781630cbf201414611e6557816311df999514611e3c57816318160ddd14611e1d5781631af41ba714611df757816325de603614611db35781632fc9255414611c53578163313ce56714611c375781633197cbb614611c185781633c56256b14611bda57816340c10f1914611b3457816340d6bb8214611b1857816342bac03a14611a54578163599eac8a146116da5781635d88cb4f1461169657816362bf0b9f146116615781636fcff4df1461164357816370a0823114611607578163715018a6146115ad578163734c7659146113e15781637708d837146113b85781638538928514610f9457816388704c7514610f755781638da5cb5b14610f4d57816395d89b4114610f125781639779ea4614610ef4578163995f567914610ed8578163a3622bf014610c61578163a9059cbb14610b33578163ae46631314610af8578163b0a6330114610a61578163b4f4c1ec1461092a578163b548765f146108e0578163b7d0628b1461076d578163bdb337d114610747578163c1e714fe1461071f578163c2884c0a146106e7578163c30cfda7146106c8578163c75a01031461062d578163cbf99dd1146105e9578163d3be4fe314610593578163d7c81b5514610574578163d8b31c77146104b9578163de5f72fd14610490578163eb6d3a1114610467578163f2fde38b146103a3578163f6b0692a14610351575063fecb03b1146102945780610013565b60203660031901126103365780356001600160401b03811161034d576102bd9036908301612092565b906102d46005546102cd81612be0565b4210612467565b620493e090813a02913a8304143a15171561033a57506102f390612c16565b81808080347f00000000000000000000000000000000000000000000000000000000000000005af1610323612275565b501561033657610333903361250b565b80f35b5080fd5b634e487b7160e01b845260119052602483fd5b8280fd5b8390346103365760203660031901126103365761039f9161038c9082906001600160a01b0361037e612060565b168152600c602052206122fc565b9051918291602083526020830190612132565b0390f35b9190503461034d57602036600319011261034d576103bf612060565b906103c861221d565b6001600160a01b0391821692831561041557505082546001600160a01b0319811683178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b83903461033657816003193601126103365760035490516001600160a01b039091168152602090f35b9190503461034d578260031936011261034d575490516001600160a01b03909116815260209150f35b505034610336576020366003190112610336576104d4612060565b6104dc61221d565b8154600d546001600160a01b039182169290600160401b811015610561576001810180600d5581101561054e577fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5016bffffffffffffffffffffffff60a01b9384825416179055169082541617905580f35b634e487b7160e01b865260328552602486fd5b634e487b7160e01b865260418552602486fd5b8390346103365781600319360112610336576020906007549051908152f35b8390346103365780600319360112610336576105ad612060565b6001600160a01b03168252600c6020528082208054602435939084101561005b57506020926105db916121ef565b91905490519160031b1c8152f35b839034610336578160031936011261033657517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b9190503461034d57602036600319011261034d577fb68479619550fd129cc13fd5926e396b807828988fd8d73efebc02c26a447186916106c29135906106786005546102cd81612be0565b6106ac6106848361288d565b9261069d8460018060a01b036002541630903390612c56565b6106a681612be0565b33612b1c565b5133815260208101919091529081906040820190565b0390a180f35b8390346103365781600319360112610336576020906001549051908152f35b8390346103365760203660031901126103365760209181906001600160a01b0361070f612060565b168152600c845220549051908152f35b9050823461005b57602036600319011261005b57506107406020923561288d565b9051908152f35b839034610336578160031936011261033657602090610764612432565b90519015158152f35b90503461034d578260031936011261034d57606091600754906008548083116107e1575b5050815160208082528451818301819052919586958686019590830194505b8382106107bd5786860387f35b845180518752830151868401528796509485019493820193600191909101906107b0565b909193506107f2818596949661234d565b906107fc8261207b565b9161080987519384611fdb565b808352610818601f199161207b565b01845b8181106108be57505081845b8661083282856122a5565b10156108af5761084281846122a5565b9060019182810180911161089c578061085b8388612453565b515287526020600b815260038a89200154906108778388612453565b51015260001981146108895701610827565b634e487b7160e01b875260118652602487fd5b634e487b7160e01b885260118752602488fd5b50945050505091388080610791565b60209088516108cc81611f59565b87815282888183015282870101520161081b565b9050823461005b57602036600319011261005b5750600654801561091c57610914670de0b6b3a7640000916020943561249f565b049051908152f35b5051637c946ed760e01b8152fd5b9050610935366120f0565b9190926109476005546102cd81612be0565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081163303610a5d57620493e091823a02923a8404143a151715610a4a5750610a0b9286928380936109ac6109a66001543a61249f565b93612c16565b6109bd8382600354168b3091612c56565b600354935163040b850f60e31b6020820190815233602483015260448201949094529316926109f981606481015b03601f198101835282611fdb565b51925af1610a05612275565b506124d2565b82808080347f00000000000000000000000000000000000000000000000000000000000000005af1610a3b612275565b501561034d576103339161250b565b634e487b7160e01b875260119052602486fd5b8580fd5b90503461034d57602036600319011261034d57610ae18161039f94610a846122c8565b5084358152600b6020522092825193610a9c85611f8a565b805460ff81161515865260081c6001600160a01b0316602086015260018101548486015260028101546060860152610ad6600382016122fc565b6080860152016122fc565b60a083015251918291602083526020830190612166565b839034610336578160031936011261033657602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b82843461005b578260031936011261005b57610b4d612060565b9060243592610b616005546102cd81612be0565b80546001600160a01b039081163303610c52578316908115610c4457338352600a6020528583205490858210610bf257338452600a6020908152878520878403905583855287852080548801905587516001600160a01b038716815280820188905288907f69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de290604090a15160018152f35b608490602088519162461bcd60e51b8352820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152fd5b8551637c946ed760e01b8152fd5b508451631dd2188d60e31b8152fd5b90503461034d578060031936011261034d5781356001600160401b038111610ed457610c9090369084016121c2565b9260243591610ca5610ca0612432565b6128fc565b82151580610ecb575b15610e8f57835194602095868101903360601b82524660348201523060601b605482015285606882015260688152610ce581611fc0565b5190208551878101917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008352603c820152603c8152610d2381611fa5565b519020610d2f82611ffc565b90610d3c87519283611fdb565b82825288368486011161005b578884610d6095610d68978387013784010152612a55565b91909161293b565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911603610e575750838091338252600a85528382205494610db386612be0565b610dbd8633612b8e565b845190810191632b83cccd60e01b8352336024830152866044830152606482015260648152610deb81611fc0565b5190827f00000000000000000000000000000000000000000000000000000000000000005af1610e19612275565b501561034d575133815260208101919091527f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a69080604081016106c2565b825162461bcd60e51b81529081018490526012602482015271696e76616c6964207369676e61747572652160701b6044820152606490fd5b835162461bcd60e51b81526020818401526016602482015275766f7465206d75737420626520312c2032206f72203360501b6044820152606490fd5b50818310610cae565b8380fd5b83903461033657816003193601126103365760209051600a8152f35b83903461033657816003193601126103365760209051620493e08152f35b839034610336578160031936011261033657805161039f91610f3382611f59565b600382526210941560ea1b60208301525191829182612017565b839034610336578160031936011261033657905490516001600160a01b039091168152602090f35b8390346103365781600319360112610336576020906006549051908152f35b9190503461034d578160031936011261034d576001600160401b0392813592602480359286841161005b573660238501121561005b578385013593610fd88561207b565b94610fe585519687611fdb565b808652602098848a88019260051b840101923684116113b457858101925b84841061135457506001600160a01b0396935050507f000000000000000000000000000000000000000000000000000000000000000085163303905061132257815b855181101561131657875a106113165761105f8187612453565b515190898061106e838a612453565b51015192600193600890600b8683540194858455848a5252868820938685015490841480159061130e575b6112f8578151938d860190815486036112e35750908b9392918860ff198854161787558a958b938c928d5b8381106111ec57505050600314611105575b505050826110e9575b5050505001611045565b838360026110fc96015554901c16612b1c565b388087816110df565b91949293509060001985018581116111da578c949392919086166111735750505086889314611137575b3880806110d6565b8354811c82166001600160a01b0381166000908152600a602052604090205480611163575b505061112f565b61116c91612b8e565b388061115c565b9091946048811491826111d1575b5081156111c6575b50611195575b5061112f565b909250600a808202925081159183041417156111b4578890913861118f565b634e487b7160e01b875260118b528787fd5b607091501438611189565b15915038611181565b634e487b7160e01b8b5260118f528b8bfd5b90919293949596975060066112018285612453565b5106968c8801978881116112cc57908d80939260029182910815611290575b506003891480611288575b8061127b575b611271575b61126290838a1b179861124983866121ef565b90919082549060031b91821b91600019901b1916179055565b01908f979695949392916110c4565b9195508591611236565b5082891b80821614611231565b50861561122b565b91928c6112a48560039e949e8093016121ef565b9054911b1c80911b9281840414901517156112cc578d92916112c5916122a5565b9938611220565b505050508f8c60118f92634e487b7160e01b835252fd5b8e8c918b5191630b75137d60e41b8352820152fd5b875163e8302cbd60e01b8152808e018590528a90fd5b508015611099565b50509550505050505080f35b5162461bcd60e51b8152808601889052600e818401526d34b73b30b634b21031b0b63632b960911b6044820152606490fd5b83358381116113b05782018860231982360301126113b05788519061137882611f59565b88810135825260448101358581116113ac579161139d8f94928b869536920101612092565b83820152815201930192611003565b8880fd5b8680fd5b8480fd5b8390346103365781600319360112610336576005546020916113d982612be0565b519042108152f35b8391506080366003190112610336576001600160a01b0360243581811690819003610ed4576044358281168091036113b4576064359283168093036113b45761142861221d565b600654611584578115801561157c575b61156c5790829186356006556bffffffffffffffffffffffff60a01b918260025416176002558160035416176003556114917f0000000000000000000000000000000000000000000000000000000000000000426122a5565b6005553461152d575b855416178455808352600a60205281832080546a52b7d2dcc80cd2e40000009182820180921161151a5755600954818101809111611507577f6ff849a3868dd59429d6eeae1c7cd02119b80ab215230e999e9b927df856447094955060095582519182526020820152a180f35b634e487b7160e01b855260118652602485fd5b634e487b7160e01b865260118752602486fd5b905083808080347f00000000000000000000000000000000000000000000000000000000000000005af161155f612275565b5015610ed457819061149a565b8351637c946ed760e01b81528690fd5b508215611438565b835162461bcd60e51b815260208188015260036024820152626f2d6f60e81b6044820152606490fd5b833461005b578060031936011261005b576115c661221d565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b83903461033657602036600319011261033657602090610740611628612060565b6001600160a01b03166000908152600a602052604090205490565b83903461033657816003193601126103365760209051620f42408152f35b505034610336576020366003190112610336573561167d61221d565b61168681612be0565b620f424081116103365760015580f35b839034610336578160031936011261033657517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b83915060208060031936011261034d576001600160401b0384358181116113b45761170890369087016121c2565b91906117196005546102cd81612be0565b6001600160a01b03927f0000000000000000000000000000000000000000000000000000000000000000841633036113b05781019084818303126113b057803590838211611a50570181601f820112156113b05780356117788161207b565b9261178588519485611fdb565b818452868085019260051b84010192818411611a4c57878101925b8484106119e85750505050508051801580156119de575b6119ce57620493e0803a02903a8204143a1517156119bb57816117dc9199949961249f565b916001906117f46117ee83543a61249f565b94612c16565b606087895161180281611f59565b8b815201528894899a5b848c106118e9575098995089985050831590506118dd5761183690611831843461249f565b6124b2565b94868080806118458a3461234d565b997f00000000000000000000000000000000000000000000000000000000000000005af1611871612275565b50156113b057866109eb6109f96118bd976118948498978598600354169761249f565b945163040b850f60e31b9181019182523360248201526044810195909552939182906064820190565b806118c55750f35b81808092335af16118d4612275565b501561005b5780f35b505050505050346118bd565b6118f38c84612453565b519b8c8a8a82511691015190303b156119b7578d8d92611933928451938492839263090594b360e01b84528a840152602496878401526044830190612132565b038183305af19182611995575b50508b8a8e9f8d931560001461198657519151911681528692917fe835ad64737fae407739c2bf764c9901751556ceb920e98995b44fa55ec87cca91a15b019b5061180c565b5050505096848091019761197e565b8482116119a657508c528b8a611940565b634e487b7160e01b8f52604186528efd5b8d80fd5b634e487b7160e01b885260118952602488fd5b855163251f56a160e21b81528890fd5b50601e81116117b7565b8335878111611a485782018a601f198286030112611a48578a5190611a0c82611f59565b8a8101358a811681036119b75782528b810135908982116119b75791611a39868d80969481960101612092565b838201528152019301926117a0565b8b80fd5b8980fd5b8780fd5b833461005b578060031936011261005b57908051918290600d549182855260208095018093600d84527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb590845b818110611afb5750505081611ab7910382611fdb565b83519485948186019282875251809352850193925b828110611adb57505050500390f35b83516001600160a01b031685528695509381019392810192600101611acc565b82546001600160a01b031684529288019260019283019201611aa1565b8390346103365781600319360112610336576020905160038152f35b8390346103365780600319360112610336577f6ff849a3868dd59429d6eeae1c7cd02119b80ab215230e999e9b927df856447090611b70612060565b6106c260243592611b7f61221d565b611b8884612be0565b6001600160a01b0383168652600a6020528086208054611ba99086906122a5565b9055611bb7846009546122a5565b600955516001600160a01b03909216825260208201929092529081906040820190565b833461005b57602036600319011261005b575061039f611c00611bfb612060565b61235a565b83929192519384938452806020850152830190612166565b8390346103365781600319360112610336576020906005549051908152f35b8390346103365781600319360112610336576020905160128152f35b90503461034d578260031936011261034d57611c70610ca0612432565b611c7861221d565b60018060a01b0360025416918151938080602096878101906370a0823160e01b825230602482015260248152611cad81611fa5565b5190875afa611cba612275565b9080611da8575b1561033657858180518101031261033657850151835163a9059cbb60e01b8188019081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166024830152604482018390529195839290918390611d3081606481016109eb565b51925af1611d3c612275565b81611d78575b5015611d4f575051908152f35b83606492519162461bcd60e51b8352820152600560248201526410940b54d560da1b6044820152fd5b80518015925086908315611d90575b50505038611d42565b611da09350820181019101612c3e565b388581611d87565b508581511015611cc1565b839034610336578160031936011261033657517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b839034610336578160031936011261033657602090516a52b7d2dcc80cd2e40000008152f35b8390346103365781600319360112610336576020906009549051908152f35b83903461033657816003193601126103365760025490516001600160a01b039091168152602090f35b8390346103365781600319360112610336576020906008549051908152f35b83903461033657816003193601126103365760209051670de0b6b3a76400008152f35b833461005b57611eb6366120f0565b611ec56005546102cd81612be0565b6001600160a01b03917f000000000000000000000000000000000000000000000000000000000000000083163203610ed457611f10610333936001543a029060035416833091612c56565b61250b565b84913461034d578260031936011261034d5761039f9250611f3582611f59565b600d82526c42616e616e6120506f696e747360981b60208301525191829182612017565b604081019081106001600160401b03821117611f7457604052565b634e487b7160e01b600052604160045260246000fd5b60c081019081106001600160401b03821117611f7457604052565b606081019081106001600160401b03821117611f7457604052565b60a081019081106001600160401b03821117611f7457604052565b90601f801991011681019081106001600160401b03821117611f7457604052565b6001600160401b038111611f7457601f01601f191660200190565b6020808252825181830181905290939260005b82811061204c57505060409293506000838284010152601f8019910116010190565b81810186015184820160400152850161202a565b600435906001600160a01b038216820361207657565b600080fd5b6001600160401b038111611f745760051b60200190565b81601f82011215612076578035916120a98361207b565b926120b76040519485611fdb565b808452602092838086019260051b820101928311612076578301905b8282106120e1575050505090565b813581529083019083016120d3565b906040600319830112612076576004356001600160a01b03811681036120765791602435906001600160401b0382116120765761212f91600401612092565b90565b90815180825260208080930193019160005b828110612152575050505090565b835185529381019392810192600101612144565b61212f9181511515815260018060a01b036020830151166020820152604082015160408201526060820151606082015260a06121b1608084015160c0608085015260c0840190612132565b9201519060a0818403910152612132565b9181601f84011215612076578235916001600160401b038311612076576020838186019501011161207657565b80548210156122075760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b6000546001600160a01b0316330361223157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b3d156122a0573d9061228682611ffc565b916122946040519384611fdb565b82523d6000602084013e565b606090565b919082018092116122b257565b634e487b7160e01b600052601160045260246000fd5b604051906122d582611f8a565b606060a0836000815260006020820152600060408201526000838201528260808201520152565b9060405191828154918282526020928383019160005283600020936000905b8282106123335750505061233192500383611fdb565b565b85548452600195860195889550938101939091019061231b565b919082039182116122b257565b60009160006123676122c8565b6001600160a01b039384168252600c602052604082208054919491908161238f575b50505050565b91939450919450600019820191821161241e5760406123b361240f936004936121ef565b90549060031b1c95868152600b60205220604051936123d185611f8a565b815460ff81161515865260081c1660208501526001810154604085015260028101546060850152612404600382016122fc565b6080850152016122fc565b60a08201529038808080612389565b634e487b7160e01b85526011600452602485fd5b60055461243e81612be0565b4211806124485790565b506007546008541490565b80518210156122075760209160051b010190565b1561246e57565b60405162461bcd60e51b815260206004820152600960248201526833b0b6b29037bb32b960b91b6044820152606490fd5b818102929181159184041417156122b257565b81156124bc570490565b634e487b7160e01b600052601260045260246000fd5b156124d957565b60405162461bcd60e51b815260206004820152600a6024820152697769746864726177546f60b01b6044820152606490fd5b6125148161235a565b511590811591612884575b501561283f5781519081151580612834575b156127fd5760009182905b8082106127c957505060018060a01b0381169182600052602091600a83526040908160002054831161278d578261257291612b8e565b6001938460075401938460075586519661258b8861207b565b976125988551998a611fdb565b8089526125a7601f199161207b565b0136838a01378351976125b989611f8a565b60008952828901848152858a0187815260608b01916000835260808c0194855260a08c0193845289600052600b8652876000209b5115159060ff8d5491610100600160a81b03905160081b169216906affffffffffffffffffffff60a81b1617178b5551898b01555160028a01556003890191519889516001600160401b0393848211611f7457600160401b9b8c8311611f745786908254848455808510612760575b500190600052856000208b60005b84811061274e57505050505060040190518051928311611f7457898311611f745783908254848455808510612721575b500190600052826000208860005b84811061270f57505050505081600052600c81528260002096875490811015611f745785611249827fca49f418dd97ad76b84ed6fb8e915ecccb519c5379cf6a4a455c2be7618fda2f9a60609a612701950181556121ef565b8251948552840152820152a1565b858451940193818401550189906126a8565b836000528a858460002092830192015b82811061273f57505061269a565b600081558794508c9101612731565b88845194019381840155018c9061266a565b836000528d858460002092830192015b82811061277e57505061265c565b600081558a94508f9101612770565b815162461bcd60e51b81526004810185905260156024820152740e0ded2dce8e640c2e4ca40dcdee840cadcdeeaced605b1b6044820152606490fd5b90926127f56001916127e46127de8789612453565b51612be0565b6127ee8688612453565b51906122a5565b93019061253c565b60405162461bcd60e51b815260206004820152600f60248201526e696e76616c696420626574416d747360881b6044820152606490fd5b506003821115612531565b60405162461bcd60e51b815260206004820152601860248201527f6c61737420726f756e64206e6f742066756c66696c6c656400000000000000006044820152606490fd5b9050153861251f565b906006549182156128ea57670de0b6b3a7640000908181029181830414901517156122b2576128bc83826124b2565b9283159182156128de575b50506128cf57565b90600181018091116122b25790565b061515905038806128c7565b604051637c946ed760e01b8152600490fd5b1561290357565b60405162461bcd60e51b815260206004820152601060248201526f33b0b6b29034b9902727aa1037bb32b960811b6044820152606490fd5b6005811015612a3f578061294c5750565b600181036129995760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036129e65760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b6003146129ef57565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b906041815114600014612a8357612a7f916020820151906060604084015193015160001a90612a8d565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311612b105791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa15612b035781516001600160a01b03811615612afd579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b907f6ff849a3868dd59429d6eeae1c7cd02119b80ab215230e999e9b927df85644709160018060a01b038116600052600a6020526040600020612b608382546122a5565b9055612b6e826009546122a5565b600955604080516001600160a01b039290921682526020820192909252a1565b907fa813766a77a805e8fc44fa2d6436a1c6a84d38d443c1238f20ed0424bcd587859160018060a01b038116600052600a6020526040600020612bd283825461234d565b9055612b6e8260095461234d565b15612be757565b60405162461bcd60e51b81526020600482015260076024820152666973207a65726f60c81b6044820152606490fd5b803410612c205750565b60449060405190633ce6d0ef60e21b82523460048301526024820152fd5b90816020910312612076575180151581036120765790565b9091600080949381946040519160208301946323b872dd60e01b865260018060a01b038092166024850152166044830152606482015260648152612c9981611fc0565b51925af1612ca5612275565b81612ce1575b5015612cb357565b60405162461bcd60e51b8152602060048201526006602482015265212816a9aa2360d11b6044820152606490fd5b8051801592508215612cf6575b505038612cab565b612d099250602080918301019101612c3e565b3880612cee56fea164736f6c6343000813000a00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c000000000000000000000000000000000000000000000000000000000003ca500000000000000000000000007e1998d5284a7fb08d59a53ab686561693341dfc000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c90153
Deployed Bytecode
0x60806040908082526004908136101561005e575b505050361561002157600080fd5b600080808080347f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c5af1610053612275565b501561005b57005b80fd5b600092833560e01c91826306fdde0314611f1557508163090594b314611ea75781630a68ed3e14611e845781630cbf201414611e6557816311df999514611e3c57816318160ddd14611e1d5781631af41ba714611df757816325de603614611db35781632fc9255414611c53578163313ce56714611c375781633197cbb614611c185781633c56256b14611bda57816340c10f1914611b3457816340d6bb8214611b1857816342bac03a14611a54578163599eac8a146116da5781635d88cb4f1461169657816362bf0b9f146116615781636fcff4df1461164357816370a0823114611607578163715018a6146115ad578163734c7659146113e15781637708d837146113b85781638538928514610f9457816388704c7514610f755781638da5cb5b14610f4d57816395d89b4114610f125781639779ea4614610ef4578163995f567914610ed8578163a3622bf014610c61578163a9059cbb14610b33578163ae46631314610af8578163b0a6330114610a61578163b4f4c1ec1461092a578163b548765f146108e0578163b7d0628b1461076d578163bdb337d114610747578163c1e714fe1461071f578163c2884c0a146106e7578163c30cfda7146106c8578163c75a01031461062d578163cbf99dd1146105e9578163d3be4fe314610593578163d7c81b5514610574578163d8b31c77146104b9578163de5f72fd14610490578163eb6d3a1114610467578163f2fde38b146103a3578163f6b0692a14610351575063fecb03b1146102945780610013565b60203660031901126103365780356001600160401b03811161034d576102bd9036908301612092565b906102d46005546102cd81612be0565b4210612467565b620493e090813a02913a8304143a15171561033a57506102f390612c16565b81808080347f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c5af1610323612275565b501561033657610333903361250b565b80f35b5080fd5b634e487b7160e01b845260119052602483fd5b8280fd5b8390346103365760203660031901126103365761039f9161038c9082906001600160a01b0361037e612060565b168152600c602052206122fc565b9051918291602083526020830190612132565b0390f35b9190503461034d57602036600319011261034d576103bf612060565b906103c861221d565b6001600160a01b0391821692831561041557505082546001600160a01b0319811683178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b83903461033657816003193601126103365760035490516001600160a01b039091168152602090f35b9190503461034d578260031936011261034d575490516001600160a01b03909116815260209150f35b505034610336576020366003190112610336576104d4612060565b6104dc61221d565b8154600d546001600160a01b039182169290600160401b811015610561576001810180600d5581101561054e577fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5016bffffffffffffffffffffffff60a01b9384825416179055169082541617905580f35b634e487b7160e01b865260328552602486fd5b634e487b7160e01b865260418552602486fd5b8390346103365781600319360112610336576020906007549051908152f35b8390346103365780600319360112610336576105ad612060565b6001600160a01b03168252600c6020528082208054602435939084101561005b57506020926105db916121ef565b91905490519160031b1c8152f35b839034610336578160031936011261033657517f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c6001600160a01b03168152602090f35b9190503461034d57602036600319011261034d577fb68479619550fd129cc13fd5926e396b807828988fd8d73efebc02c26a447186916106c29135906106786005546102cd81612be0565b6106ac6106848361288d565b9261069d8460018060a01b036002541630903390612c56565b6106a681612be0565b33612b1c565b5133815260208101919091529081906040820190565b0390a180f35b8390346103365781600319360112610336576020906001549051908152f35b8390346103365760203660031901126103365760209181906001600160a01b0361070f612060565b168152600c845220549051908152f35b9050823461005b57602036600319011261005b57506107406020923561288d565b9051908152f35b839034610336578160031936011261033657602090610764612432565b90519015158152f35b90503461034d578260031936011261034d57606091600754906008548083116107e1575b5050815160208082528451818301819052919586958686019590830194505b8382106107bd5786860387f35b845180518752830151868401528796509485019493820193600191909101906107b0565b909193506107f2818596949661234d565b906107fc8261207b565b9161080987519384611fdb565b808352610818601f199161207b565b01845b8181106108be57505081845b8661083282856122a5565b10156108af5761084281846122a5565b9060019182810180911161089c578061085b8388612453565b515287526020600b815260038a89200154906108778388612453565b51015260001981146108895701610827565b634e487b7160e01b875260118652602487fd5b634e487b7160e01b885260118752602488fd5b50945050505091388080610791565b60209088516108cc81611f59565b87815282888183015282870101520161081b565b9050823461005b57602036600319011261005b5750600654801561091c57610914670de0b6b3a7640000916020943561249f565b049051908152f35b5051637c946ed760e01b8152fd5b9050610935366120f0565b9190926109476005546102cd81612be0565b6001600160a01b037f000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c9015381163303610a5d57620493e091823a02923a8404143a151715610a4a5750610a0b9286928380936109ac6109a66001543a61249f565b93612c16565b6109bd8382600354168b3091612c56565b600354935163040b850f60e31b6020820190815233602483015260448201949094529316926109f981606481015b03601f198101835282611fdb565b51925af1610a05612275565b506124d2565b82808080347f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c5af1610a3b612275565b501561034d576103339161250b565b634e487b7160e01b875260119052602486fd5b8580fd5b90503461034d57602036600319011261034d57610ae18161039f94610a846122c8565b5084358152600b6020522092825193610a9c85611f8a565b805460ff81161515865260081c6001600160a01b0316602086015260018101548486015260028101546060860152610ad6600382016122fc565b6080860152016122fc565b60a083015251918291602083526020830190612166565b839034610336578160031936011261033657602090517f000000000000000000000000000000000000000000000000000000000003ca508152f35b82843461005b578260031936011261005b57610b4d612060565b9060243592610b616005546102cd81612be0565b80546001600160a01b039081163303610c52578316908115610c4457338352600a6020528583205490858210610bf257338452600a6020908152878520878403905583855287852080548801905587516001600160a01b038716815280820188905288907f69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de290604090a15160018152f35b608490602088519162461bcd60e51b8352820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152fd5b8551637c946ed760e01b8152fd5b508451631dd2188d60e31b8152fd5b90503461034d578060031936011261034d5781356001600160401b038111610ed457610c9090369084016121c2565b9260243591610ca5610ca0612432565b6128fc565b82151580610ecb575b15610e8f57835194602095868101903360601b82524660348201523060601b605482015285606882015260688152610ce581611fc0565b5190208551878101917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008352603c820152603c8152610d2381611fa5565b519020610d2f82611ffc565b90610d3c87519283611fdb565b82825288368486011161005b578884610d6095610d68978387013784010152612a55565b91909161293b565b6001600160a01b037f000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c901538116911603610e575750838091338252600a85528382205494610db386612be0565b610dbd8633612b8e565b845190810191632b83cccd60e01b8352336024830152866044830152606482015260648152610deb81611fc0565b5190827f0000000000000000000000007e1998d5284a7fb08d59a53ab686561693341dfc5af1610e19612275565b501561034d575133815260208101919091527f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a69080604081016106c2565b825162461bcd60e51b81529081018490526012602482015271696e76616c6964207369676e61747572652160701b6044820152606490fd5b835162461bcd60e51b81526020818401526016602482015275766f7465206d75737420626520312c2032206f72203360501b6044820152606490fd5b50818310610cae565b8380fd5b83903461033657816003193601126103365760209051600a8152f35b83903461033657816003193601126103365760209051620493e08152f35b839034610336578160031936011261033657805161039f91610f3382611f59565b600382526210941560ea1b60208301525191829182612017565b839034610336578160031936011261033657905490516001600160a01b039091168152602090f35b8390346103365781600319360112610336576020906006549051908152f35b9190503461034d578160031936011261034d576001600160401b0392813592602480359286841161005b573660238501121561005b578385013593610fd88561207b565b94610fe585519687611fdb565b808652602098848a88019260051b840101923684116113b457858101925b84841061135457506001600160a01b0396935050507f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c85163303905061132257815b855181101561131657875a106113165761105f8187612453565b515190898061106e838a612453565b51015192600193600890600b8683540194858455848a5252868820938685015490841480159061130e575b6112f8578151938d860190815486036112e35750908b9392918860ff198854161787558a958b938c928d5b8381106111ec57505050600314611105575b505050826110e9575b5050505001611045565b838360026110fc96015554901c16612b1c565b388087816110df565b91949293509060001985018581116111da578c949392919086166111735750505086889314611137575b3880806110d6565b8354811c82166001600160a01b0381166000908152600a602052604090205480611163575b505061112f565b61116c91612b8e565b388061115c565b9091946048811491826111d1575b5081156111c6575b50611195575b5061112f565b909250600a808202925081159183041417156111b4578890913861118f565b634e487b7160e01b875260118b528787fd5b607091501438611189565b15915038611181565b634e487b7160e01b8b5260118f528b8bfd5b90919293949596975060066112018285612453565b5106968c8801978881116112cc57908d80939260029182910815611290575b506003891480611288575b8061127b575b611271575b61126290838a1b179861124983866121ef565b90919082549060031b91821b91600019901b1916179055565b01908f979695949392916110c4565b9195508591611236565b5082891b80821614611231565b50861561122b565b91928c6112a48560039e949e8093016121ef565b9054911b1c80911b9281840414901517156112cc578d92916112c5916122a5565b9938611220565b505050508f8c60118f92634e487b7160e01b835252fd5b8e8c918b5191630b75137d60e41b8352820152fd5b875163e8302cbd60e01b8152808e018590528a90fd5b508015611099565b50509550505050505080f35b5162461bcd60e51b8152808601889052600e818401526d34b73b30b634b21031b0b63632b960911b6044820152606490fd5b83358381116113b05782018860231982360301126113b05788519061137882611f59565b88810135825260448101358581116113ac579161139d8f94928b869536920101612092565b83820152815201930192611003565b8880fd5b8680fd5b8480fd5b8390346103365781600319360112610336576005546020916113d982612be0565b519042108152f35b8391506080366003190112610336576001600160a01b0360243581811690819003610ed4576044358281168091036113b4576064359283168093036113b45761142861221d565b600654611584578115801561157c575b61156c5790829186356006556bffffffffffffffffffffffff60a01b918260025416176002558160035416176003556114917f000000000000000000000000000000000000000000000000000000000003ca50426122a5565b6005553461152d575b855416178455808352600a60205281832080546a52b7d2dcc80cd2e40000009182820180921161151a5755600954818101809111611507577f6ff849a3868dd59429d6eeae1c7cd02119b80ab215230e999e9b927df856447094955060095582519182526020820152a180f35b634e487b7160e01b855260118652602485fd5b634e487b7160e01b865260118752602486fd5b905083808080347f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c5af161155f612275565b5015610ed457819061149a565b8351637c946ed760e01b81528690fd5b508215611438565b835162461bcd60e51b815260208188015260036024820152626f2d6f60e81b6044820152606490fd5b833461005b578060031936011261005b576115c661221d565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b83903461033657602036600319011261033657602090610740611628612060565b6001600160a01b03166000908152600a602052604090205490565b83903461033657816003193601126103365760209051620f42408152f35b505034610336576020366003190112610336573561167d61221d565b61168681612be0565b620f424081116103365760015580f35b839034610336578160031936011261033657517f000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c901536001600160a01b03168152602090f35b83915060208060031936011261034d576001600160401b0384358181116113b45761170890369087016121c2565b91906117196005546102cd81612be0565b6001600160a01b03927f000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c90153841633036113b05781019084818303126113b057803590838211611a50570181601f820112156113b05780356117788161207b565b9261178588519485611fdb565b818452868085019260051b84010192818411611a4c57878101925b8484106119e85750505050508051801580156119de575b6119ce57620493e0803a02903a8204143a1517156119bb57816117dc9199949961249f565b916001906117f46117ee83543a61249f565b94612c16565b606087895161180281611f59565b8b815201528894899a5b848c106118e9575098995089985050831590506118dd5761183690611831843461249f565b6124b2565b94868080806118458a3461234d565b997f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c5af1611871612275565b50156113b057866109eb6109f96118bd976118948498978598600354169761249f565b945163040b850f60e31b9181019182523360248201526044810195909552939182906064820190565b806118c55750f35b81808092335af16118d4612275565b501561005b5780f35b505050505050346118bd565b6118f38c84612453565b519b8c8a8a82511691015190303b156119b7578d8d92611933928451938492839263090594b360e01b84528a840152602496878401526044830190612132565b038183305af19182611995575b50508b8a8e9f8d931560001461198657519151911681528692917fe835ad64737fae407739c2bf764c9901751556ceb920e98995b44fa55ec87cca91a15b019b5061180c565b5050505096848091019761197e565b8482116119a657508c528b8a611940565b634e487b7160e01b8f52604186528efd5b8d80fd5b634e487b7160e01b885260118952602488fd5b855163251f56a160e21b81528890fd5b50601e81116117b7565b8335878111611a485782018a601f198286030112611a48578a5190611a0c82611f59565b8a8101358a811681036119b75782528b810135908982116119b75791611a39868d80969481960101612092565b838201528152019301926117a0565b8b80fd5b8980fd5b8780fd5b833461005b578060031936011261005b57908051918290600d549182855260208095018093600d84527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb590845b818110611afb5750505081611ab7910382611fdb565b83519485948186019282875251809352850193925b828110611adb57505050500390f35b83516001600160a01b031685528695509381019392810192600101611acc565b82546001600160a01b031684529288019260019283019201611aa1565b8390346103365781600319360112610336576020905160038152f35b8390346103365780600319360112610336577f6ff849a3868dd59429d6eeae1c7cd02119b80ab215230e999e9b927df856447090611b70612060565b6106c260243592611b7f61221d565b611b8884612be0565b6001600160a01b0383168652600a6020528086208054611ba99086906122a5565b9055611bb7846009546122a5565b600955516001600160a01b03909216825260208201929092529081906040820190565b833461005b57602036600319011261005b575061039f611c00611bfb612060565b61235a565b83929192519384938452806020850152830190612166565b8390346103365781600319360112610336576020906005549051908152f35b8390346103365781600319360112610336576020905160128152f35b90503461034d578260031936011261034d57611c70610ca0612432565b611c7861221d565b60018060a01b0360025416918151938080602096878101906370a0823160e01b825230602482015260248152611cad81611fa5565b5190875afa611cba612275565b9080611da8575b1561033657858180518101031261033657850151835163a9059cbb60e01b8188019081526001600160a01b037f0000000000000000000000007e1998d5284a7fb08d59a53ab686561693341dfc166024830152604482018390529195839290918390611d3081606481016109eb565b51925af1611d3c612275565b81611d78575b5015611d4f575051908152f35b83606492519162461bcd60e51b8352820152600560248201526410940b54d560da1b6044820152fd5b80518015925086908315611d90575b50505038611d42565b611da09350820181019101612c3e565b388581611d87565b508581511015611cc1565b839034610336578160031936011261033657517f0000000000000000000000007e1998d5284a7fb08d59a53ab686561693341dfc6001600160a01b03168152602090f35b839034610336578160031936011261033657602090516a52b7d2dcc80cd2e40000008152f35b8390346103365781600319360112610336576020906009549051908152f35b83903461033657816003193601126103365760025490516001600160a01b039091168152602090f35b8390346103365781600319360112610336576020906008549051908152f35b83903461033657816003193601126103365760209051670de0b6b3a76400008152f35b833461005b57611eb6366120f0565b611ec56005546102cd81612be0565b6001600160a01b03917f000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c9015383163203610ed457611f10610333936001543a029060035416833091612c56565b61250b565b84913461034d578260031936011261034d5761039f9250611f3582611f59565b600d82526c42616e616e6120506f696e747360981b60208301525191829182612017565b604081019081106001600160401b03821117611f7457604052565b634e487b7160e01b600052604160045260246000fd5b60c081019081106001600160401b03821117611f7457604052565b606081019081106001600160401b03821117611f7457604052565b60a081019081106001600160401b03821117611f7457604052565b90601f801991011681019081106001600160401b03821117611f7457604052565b6001600160401b038111611f7457601f01601f191660200190565b6020808252825181830181905290939260005b82811061204c57505060409293506000838284010152601f8019910116010190565b81810186015184820160400152850161202a565b600435906001600160a01b038216820361207657565b600080fd5b6001600160401b038111611f745760051b60200190565b81601f82011215612076578035916120a98361207b565b926120b76040519485611fdb565b808452602092838086019260051b820101928311612076578301905b8282106120e1575050505090565b813581529083019083016120d3565b906040600319830112612076576004356001600160a01b03811681036120765791602435906001600160401b0382116120765761212f91600401612092565b90565b90815180825260208080930193019160005b828110612152575050505090565b835185529381019392810192600101612144565b61212f9181511515815260018060a01b036020830151166020820152604082015160408201526060820151606082015260a06121b1608084015160c0608085015260c0840190612132565b9201519060a0818403910152612132565b9181601f84011215612076578235916001600160401b038311612076576020838186019501011161207657565b80548210156122075760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b6000546001600160a01b0316330361223157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b3d156122a0573d9061228682611ffc565b916122946040519384611fdb565b82523d6000602084013e565b606090565b919082018092116122b257565b634e487b7160e01b600052601160045260246000fd5b604051906122d582611f8a565b606060a0836000815260006020820152600060408201526000838201528260808201520152565b9060405191828154918282526020928383019160005283600020936000905b8282106123335750505061233192500383611fdb565b565b85548452600195860195889550938101939091019061231b565b919082039182116122b257565b60009160006123676122c8565b6001600160a01b039384168252600c602052604082208054919491908161238f575b50505050565b91939450919450600019820191821161241e5760406123b361240f936004936121ef565b90549060031b1c95868152600b60205220604051936123d185611f8a565b815460ff81161515865260081c1660208501526001810154604085015260028101546060850152612404600382016122fc565b6080850152016122fc565b60a08201529038808080612389565b634e487b7160e01b85526011600452602485fd5b60055461243e81612be0565b4211806124485790565b506007546008541490565b80518210156122075760209160051b010190565b1561246e57565b60405162461bcd60e51b815260206004820152600960248201526833b0b6b29037bb32b960b91b6044820152606490fd5b818102929181159184041417156122b257565b81156124bc570490565b634e487b7160e01b600052601260045260246000fd5b156124d957565b60405162461bcd60e51b815260206004820152600a6024820152697769746864726177546f60b01b6044820152606490fd5b6125148161235a565b511590811591612884575b501561283f5781519081151580612834575b156127fd5760009182905b8082106127c957505060018060a01b0381169182600052602091600a83526040908160002054831161278d578261257291612b8e565b6001938460075401938460075586519661258b8861207b565b976125988551998a611fdb565b8089526125a7601f199161207b565b0136838a01378351976125b989611f8a565b60008952828901848152858a0187815260608b01916000835260808c0194855260a08c0193845289600052600b8652876000209b5115159060ff8d5491610100600160a81b03905160081b169216906affffffffffffffffffffff60a81b1617178b5551898b01555160028a01556003890191519889516001600160401b0393848211611f7457600160401b9b8c8311611f745786908254848455808510612760575b500190600052856000208b60005b84811061274e57505050505060040190518051928311611f7457898311611f745783908254848455808510612721575b500190600052826000208860005b84811061270f57505050505081600052600c81528260002096875490811015611f745785611249827fca49f418dd97ad76b84ed6fb8e915ecccb519c5379cf6a4a455c2be7618fda2f9a60609a612701950181556121ef565b8251948552840152820152a1565b858451940193818401550189906126a8565b836000528a858460002092830192015b82811061273f57505061269a565b600081558794508c9101612731565b88845194019381840155018c9061266a565b836000528d858460002092830192015b82811061277e57505061265c565b600081558a94508f9101612770565b815162461bcd60e51b81526004810185905260156024820152740e0ded2dce8e640c2e4ca40dcdee840cadcdeeaced605b1b6044820152606490fd5b90926127f56001916127e46127de8789612453565b51612be0565b6127ee8688612453565b51906122a5565b93019061253c565b60405162461bcd60e51b815260206004820152600f60248201526e696e76616c696420626574416d747360881b6044820152606490fd5b506003821115612531565b60405162461bcd60e51b815260206004820152601860248201527f6c61737420726f756e64206e6f742066756c66696c6c656400000000000000006044820152606490fd5b9050153861251f565b906006549182156128ea57670de0b6b3a7640000908181029181830414901517156122b2576128bc83826124b2565b9283159182156128de575b50506128cf57565b90600181018091116122b25790565b061515905038806128c7565b604051637c946ed760e01b8152600490fd5b1561290357565b60405162461bcd60e51b815260206004820152601060248201526f33b0b6b29034b9902727aa1037bb32b960811b6044820152606490fd5b6005811015612a3f578061294c5750565b600181036129995760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036129e65760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b6003146129ef57565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b906041815114600014612a8357612a7f916020820151906060604084015193015160001a90612a8d565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311612b105791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa15612b035781516001600160a01b03811615612afd579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b907f6ff849a3868dd59429d6eeae1c7cd02119b80ab215230e999e9b927df85644709160018060a01b038116600052600a6020526040600020612b608382546122a5565b9055612b6e826009546122a5565b600955604080516001600160a01b039290921682526020820192909252a1565b907fa813766a77a805e8fc44fa2d6436a1c6a84d38d443c1238f20ed0424bcd587859160018060a01b038116600052600a6020526040600020612bd283825461234d565b9055612b6e8260095461234d565b15612be757565b60405162461bcd60e51b81526020600482015260076024820152666973207a65726f60c81b6044820152606490fd5b803410612c205750565b60449060405190633ce6d0ef60e21b82523460048301526024820152fd5b90816020910312612076575180151581036120765790565b9091600080949381946040519160208301946323b872dd60e01b865260018060a01b038092166024850152166044830152606482015260648152612c9981611fc0565b51925af1612ca5612275565b81612ce1575b5015612cb357565b60405162461bcd60e51b8152602060048201526006602482015265212816a9aa2360d11b6044820152606490fd5b8051801592508215612cf6575b505038612cab565b612d099250602080918301019101612c3e565b3880612cee56fea164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c000000000000000000000000000000000000000000000000000000000003ca500000000000000000000000007e1998d5284a7fb08d59a53ab686561693341dfc000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c90153
-----Decoded View---------------
Arg [0] : _gameRngWalletAddress (address): 0x63795e0f9223Ec4BFeF5fBE3dbf9331F1C57cC5c
Arg [1] : _gamePeriod (uint256): 248400
Arg [2] : _V3Deployer (address): 0x7E1998D5284A7fb08d59a53Ab686561693341DfC
Arg [3] : _rollOperator (address): 0xD7BCEE2EaA9579F39c2290d48e0fA3c706C90153
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c
Arg [1] : 000000000000000000000000000000000000000000000000000000000003ca50
Arg [2] : 0000000000000000000000007e1998d5284a7fb08d59a53ab686561693341dfc
Arg [3] : 000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c90153
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
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.