More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 67 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Fulfill Random W... | 9812557 | 50 mins ago | IN | 0 S | 0.0126888 | ||||
Bet | 9812552 | 50 mins ago | IN | 0.01375 S | 0.0138837 | ||||
Fulfill Random W... | 9812531 | 51 mins ago | IN | 0 S | 0.01298958 | ||||
Bet | 9812524 | 51 mins ago | IN | 0.01375 S | 0.0138837 | ||||
Fulfill Random W... | 9812503 | 51 mins ago | IN | 0 S | 0.01373193 | ||||
Bet | 9812496 | 51 mins ago | IN | 0.01375 S | 0.0138837 | ||||
Fulfill Random W... | 9812422 | 51 mins ago | IN | 0 S | 0.02069472 | ||||
Bet | 9812417 | 51 mins ago | IN | 0.01974972 S | 0.0138837 | ||||
Fulfill Random W... | 9812386 | 51 mins ago | IN | 0 S | 0.02293233 | ||||
Bet | 9812380 | 51 mins ago | IN | 0.0246181 S | 0.02704624 | ||||
Purchase Points | 9812364 | 51 mins ago | IN | 0 S | 0.00630006 | ||||
Purchase Points | 9810664 | 1 hr ago | IN | 0 S | 0.0038339 | ||||
Fulfill Random W... | 9775889 | 4 hrs ago | IN | 0 S | 0.01491228 | ||||
Bet | 9775887 | 4 hrs ago | IN | 0.01375 S | 0.0138837 | ||||
Fulfill Random W... | 9775864 | 4 hrs ago | IN | 0 S | 0.01477247 | ||||
Bet | 9775858 | 4 hrs ago | IN | 0.02017295 S | 0.01856713 | ||||
Fulfill Random W... | 9775832 | 4 hrs ago | IN | 0 S | 0.0128034 | ||||
Bet | 9775827 | 4 hrs ago | IN | 0.01375 S | 0.0138837 | ||||
Fulfill Random W... | 9775804 | 4 hrs ago | IN | 0 S | 0.01280095 | ||||
Bet | 9775798 | 4 hrs ago | IN | 0.01375 S | 0.0133883 | ||||
Purchase Points | 9775785 | 4 hrs ago | IN | 0 S | 0.0040739 | ||||
Fulfill Random W... | 9767801 | 5 hrs ago | IN | 0 S | 0.01381726 | ||||
Bet | 9767797 | 5 hrs ago | IN | 0.01375 S | 0.0158777 | ||||
Fulfill Random W... | 9767766 | 5 hrs ago | IN | 0 S | 0.0126882 | ||||
Bet | 9767761 | 5 hrs ago | IN | 0.01489583 S | 0.0158777 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
9812552 | 50 mins ago | 0.01375 S | ||||
9812524 | 51 mins ago | 0.01375 S | ||||
9812496 | 51 mins ago | 0.01375 S | ||||
9812417 | 51 mins ago | 0.01974972 S | ||||
9812380 | 51 mins ago | 0.0246181 S | ||||
9775887 | 4 hrs ago | 0.01375 S | ||||
9775858 | 4 hrs ago | 0.02017295 S | ||||
9775827 | 4 hrs ago | 0.01375 S | ||||
9775798 | 4 hrs ago | 0.01375 S | ||||
9767797 | 5 hrs ago | 0.01375 S | ||||
9767761 | 5 hrs ago | 0.01489583 S | ||||
9767707 | 5 hrs ago | 0.01466666 S | ||||
9767641 | 5 hrs ago | 0.01375 S | ||||
9767581 | 5 hrs ago | 0.01375 S | ||||
9577613 | 24 hrs ago | 0.01805616 S | ||||
9577569 | 24 hrs ago | 0.0144 S | ||||
9577353 | 24 hrs ago | 0.0144 S | ||||
9577303 | 24 hrs ago | 0.0144 S | ||||
9577265 | 24 hrs ago | 0.01558366 S | ||||
9577212 | 24 hrs ago | 0.01375 S | ||||
9577171 | 24 hrs ago | 0.01375 S | ||||
9576812 | 24 hrs ago | 0.0191448 S | ||||
9576724 | 24 hrs ago | 0.0144 S | ||||
9576671 | 24 hrs ago | 0.01664288 S | ||||
9568407 | 25 hrs ago | 0.0144 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 WIN69_MULTIPLIER = 10; uint256 public constant CALLBACK_GAS = 200_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 = 700_000; uint256 public immutable gamePeriod; address public coin; address public immutable V3Deployer; address public wrappedNative; address public immutable gameRngWallet; address public immutable rollOperator; /// @notice Timestamp when the geme ower uint256 public endTime; /// @notice Initial rate of tokens per coin uint256 public initialTokenRate; uint256 public immutable airdropRate; 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; constructor( address _gameRngWalletAddress, uint _gamePeriod, address _V3Deployer, address _rollOperator, uint256 _airdropRate ) { 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; airdropRate = _airdropRate; transferOwnership(_V3Deployer); } 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 ) external payable onlyOwner { // Ensure the initial token rate is not already set require(initialTokenRate == 0, "o-o"); if (_coin == 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); } } /// @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; } /// @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 function redeem(bytes calldata signature) external shouldGameIsOver { _checkSignature(signature, "redeem"); uint256 amount = balanceOf(msg.sender); _checkZero(amount); _burnPoints(msg.sender, amount); (bool success, ) = V3Deployer.call( abi.encodeWithSignature("redeem(address,uint256)", msg.sender, amount) ); require(success); emit Redeem(msg.sender, amount); } /// @notice claimAirDrop for certain users. /// @dev Burns points from the users balance and mints equivalent coins corresponding to airdropRate. /// Emits a ClaimAirDrop event upon success. /// Requires the game to be over and distibuted /// 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 function claimAirDrop(bytes calldata signature) external { (bool success, bytes memory response) = V3Deployer.staticcall( abi.encodeWithSignature("distributedGames(address)", address(this)) ); require(success && response.length == 32); require(abi.decode(response, (bool)), "wait for distribution"); _checkSignature(signature, "claimAirDrop"); uint256 points = balanceOf(msg.sender); _checkZero(points); _burnPoints(msg.sender, points); uint amount = (points * airdropRate) / DELIMITER; require(coin.getBalance() >= amount, "top up coin"); coin.safeTransfer(msg.sender, amount); emit ClaimAirDrop(msg.sender, amount); } function _checkSignature(bytes calldata signature, string memory functionName) private view { bytes32 message = _withPrefix( keccak256(abi.encodePacked(msg.sender, block.chainid, address(this), functionName)) ); 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
[{"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"},{"internalType":"uint256","name":"_airdropRate","type":"uint256"}],"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"},{"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":[],"name":"airdropRate","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":[{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"claimAirDrop","outputs":[],"stateMutability":"nonpayable","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":[{"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":[{"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":[],"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"}],"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":"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"}],"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":"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
610120346200025c57601f62002d5d38819003918201601f1916830191906001600160401b0383118484101762000261578160a092859260409586528339810103126200025c57620000518262000277565b916020810151926200006583830162000277565b916080620000766060830162000277565b9101519462000085336200028c565b620aae6060015560c08390526001600160a01b0392831615801562000251575b6200024057611c208110801562000233575b620002225760805260e0528160a05261010093845233816000541603620001df578116156200018c57620000eb906200028c565b51612a899182620002d483396080518281816104d80152610ce5015260a0518281816105b901528181610dc00152818161189b01526118db015260c051828181602a015281816102cd0152818161050e015281816107f201528181610be701528181610f8901526115be015260e051828181610b260152818161143b0152818161148f015281816119bf015261252a01525181818161065f0152610ec00152f35b815162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b6064835162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b845163c8e9ad0d60e01b8152600490fd5b5062ed4e008111620000b7565b8451637c946ed760e01b8152600490fd5b5082841615620000a5565b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036200025c57565b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a356fe60806040908082526004908136101561005e575b505050361561002157600080fd5b600080808080347f00000000000000000000000000000000000000000000000000000000000000005af1610053611d6f565b501561005b57005b80fd5b600092833560e01c91826306fdde0314611a0857508163090594b3146119945781630a68ed3e146119715781630cbf20141461195257816311df99951461192957816318160ddd1461190a57816325de6036146118c65781632fc9255414611856578163313ce5671461183a5781633197cbb61461181b5781633c56256b146117dd57816340d6bb82146117c1578163599eac8a1461146a5781635d88cb4f1461142657816362bf0b9f146113f15781636fcff4df146113d357816370a0823114611397578163715018a61461133d5781637708d837146113135781638538928514610f0257816388704c7514610ee35781638891cf0d14610ea85781638da5cb5b14610e8057816395d89b4114610e455781639779ea4614610e275781639945e3d314610d24578163995f567914610d08578163ae46631314610ccd578163b0a6330114610c36578163b4f4c1ec14610b00578163b548765f14610ab6578163b7d0628b14610943578163bdb337d11461091d578163c1e714fe146108f5578163c2884c0a146108bd578163c30cfda71461089e578163c75a010314610821578163cbf99dd1146107dd578163d3be4fe314610787578163d7c81b5514610768578163e09af4401461057b578163e41d15b014610463578163eb6d3a111461043a578163f2fde38b14610376578163f6b0692a14610324575063fecb03b1146102685780610013565b60203660031901126103095780356001600160401b038111610320576102919036908301611b70565b906102a781546102a081612833565b4210611f61565b62030d4090813a02913a8304143a15171561030d57506102c690612869565b81808080347f00000000000000000000000000000000000000000000000000000000000000005af16102f6611d6f565b5015610309576103069033612005565b80f35b5080fd5b634e487b7160e01b845260119052602483fd5b8280fd5b839034610309576020366003190112610309576103729161035f9082906001600160a01b03610351611b3e565b168152600b60205220611df6565b9051918291602083526020830190611c10565b0390f35b9190503461032057602036600319011261032057610392611b3e565b9061039b611d17565b6001600160a01b039182169283156103e857505082546001600160a01b0319811683178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b83903461030957816003193601126103095760035490516001600160a01b039091168152602090f35b90506060366003190112610320576001600160a01b03906024358281169190829003610577576044359283168093036105775761049e611d17565b60055461054f578115610540575082356005556bffffffffffffffffffffffff60a01b9081600254161760025560035416176003556104fd7f000000000000000000000000000000000000000000000000000000000000000042611d9f565b9055346105075780f35b80808080347f00000000000000000000000000000000000000000000000000000000000000005af1610537611d6f565b501561005b5780f35b51637c946ed760e01b81528390fd5b5162461bcd60e51b815260208185015260036024820152626f2d6f60e81b6044820152606490fd5b8480fd5b9050346103205761058b36611ca0565b90825191858060209485810190634dffb8ed60e11b8252306024820152602481526105b581611a98565b51907f00000000000000000000000000000000000000000000000000000000000000005afa6105e2611d6f565b908061075e575b1561075a578084806106009351830101910161243a565b1561071f57906106339184519161061683611a4c565b600c83526b0636c61696d41697244726f760a41b85840152612452565b33845260098152670de0b6b3a76400006106848386205461065381612833565b61065d81336127e1565b7f000000000000000000000000000000000000000000000000000000000000000090611f99565b049260018060a01b0360025416918461069c84612a16565b106106ef57857f154a25614f47446861b76a16524acf5871d8ca809bd3e9bdc00a66c759aece996106e987876106d382338a612961565b5133815260208101919091529081906040820190565b0390a180f35b835162461bcd60e51b815291820152600b60248201526a3a37b8103ab81031b7b4b760a91b604482015260649150fd5b835162461bcd60e51b815280860184905260156024820152743bb0b4ba103337b9103234b9ba3934b13aba34b7b760591b6044820152606490fd5b8680fd5b50838151146105e9565b8390346103095781600319360112610309576020906006549051908152f35b8390346103095780600319360112610309576107a1611b3e565b6001600160a01b03168252600b6020528082208054602435939084101561005b57506020926107cf91611ce9565b91905490519160031b1c8152f35b839034610309578160031936011261030957517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b90503461032057602036600319011261032057816106e99161086a7fb68479619550fd129cc13fd5926e396b807828988fd8d73efebc02c26a447186943592546102a081612833565b6106d36108768361238c565b9261088f8460018060a01b036002541630903390612891565b61089881612833565b3361276f565b8390346103095781600319360112610309576020906001549051908152f35b8390346103095760203660031901126103095760209181906001600160a01b036108e5611b3e565b168152600b845220549051908152f35b9050823461005b57602036600319011261005b57506109166020923561238c565b9051908152f35b83903461030957816003193601126103095760209061093a611f2c565b90519015158152f35b905034610320578260031936011261032057606091600654906007548083116109b7575b5050815160208082528451818301819052919586958686019590830194505b8382106109935786860387f35b84518051875283015186840152879650948501949382019360019190910190610986565b909193506109c88185969496611e47565b906109d282611b59565b916109df87519384611ab3565b8083526109ee601f1991611b59565b01845b818110610a9457505081845b86610a088285611d9f565b1015610a8557610a188184611d9f565b90600191828101809111610a725780610a318388611f4d565b515287526020600a815260038a8920015490610a4d8388611f4d565b5101526000198114610a5f57016109fd565b634e487b7160e01b875260118652602487fd5b634e487b7160e01b885260118752602488fd5b50945050505091388080610967565b6020908851610aa281611a4c565b8781528288818301528287010152016109f1565b9050823461005b57602036600319011261005b57506005548015610af257610aea670de0b6b3a76400009160209435611f99565b049051908152f35b5051637c946ed760e01b8152fd5b9050610b0b36611bce565b919092610b1c81546102a081612833565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081163303610c325762030d4091823a02923a8404143a151715610c1f5750610be0928692838093610b81610b7b6001543a611f99565b93612869565b610b928382600354168b3091612891565b600354935163040b850f60e31b602082019081523360248301526044820194909452931692610bce81606481015b03601f198101835282611ab3565b51925af1610bda611d6f565b50611fcc565b82808080347f00000000000000000000000000000000000000000000000000000000000000005af1610c10611d6f565b50156103205761030691612005565b634e487b7160e01b875260119052602486fd5b8580fd5b90503461032057602036600319011261032057610cb68161037294610c59611dc2565b5084358152600a6020522092825193610c7185611a7d565b805460ff81161515865260081c6001600160a01b0316602086015260018101548486015260028101546060860152610cab60038201611df6565b608086015201611df6565b60a083015251918291602083526020830190611c44565b839034610309578160031936011261030957602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b83903461030957816003193601126103095760209051600a8152f35b83903461030957610d6b610d3736611ca0565b610d47610d42611f2c565b6123fb565b835191610d5383611a4c565b600683526572656465656d60d01b6020840152612452565b33825260096020528082205490610d8182612833565b610d8b82336127e1565b80516301e9a69560e41b60208201908152336024830152604482018490528491829190610dbb8160648101610bc0565b5190827f00000000000000000000000000000000000000000000000000000000000000005af1610de9611d6f565b5015610320575133815260208101919091527f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a69080604081016106e9565b8390346103095781600319360112610309576020905162030d408152f35b839034610309578160031936011261030957805161037291610e6682611a4c565b600382526210941560ea1b60208301525191829182611b12565b839034610309578160031936011261030957905490516001600160a01b039091168152602090f35b839034610309578160031936011261030957602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b8390346103095781600319360112610309576020906005549051908152f35b919050346103205781600319360112610320578035916024938435916001600160401b03908184116103205736602385011215610320578385013593610f4785611b59565b94610f5483519687611ab3565b808652602093898588019260051b8401019236841161075a578a8101925b8484106112b257506001600160a01b0396935050507f000000000000000000000000000000000000000000000000000000000000000085163303905061127f57809796975b855181101561127357885a1061127357610fd18187611f4d565b51519084610fdf8289611f4d565b5101519160019260079184835401809355808652600a808952878720938685015490831480159061126b575b611255578351928d8601908154850361124057508760ff19875416178655889389958a928b5b83811061115a575050509e9f9e60031461107a575b5050509050878161105e575b50505001969796610fb7565b828260026110729501555460081c1661276f565b388087611052565b60001985018581116111465785166110e35750505050858591146110a2575b80388080611046565b87825460081c166110c68160018060a01b0316600052600960205260406000205490565b806110d3575b5050611099565b6110dc916127e1565b38806110cc565b9091929360488114918261113d575b508115611132575b50611106575050611099565b9080925081029181830414901517156111205738806110cc565b634e487b7160e01b855260118a528b85fd5b6070915014386110fa565b159150386110f2565b5050634e487b7160e01b885260118d528e88fd5b60066111668285611f4d565b5106988c8a01998a811161122857908d809392600291829108156111ec575b5060038b14806111e4575b806111d7575b6111cd575b6111c790838c1b179a6111ae8386611ce9565b90919082549060031b91821b91600019901b1916179055565b01611031565b919550859161119b565b50828b1b80821614611196565b508615611190565b91928c6112008560039d949d809301611ce9565b9054911b1c80911b928184041490151715611228578d929161122191611d9f565b9838611185565b50505050508f8f60118c91634e487b7160e01b835252fd5b8f8f828d5191630b75137d60e41b8352820152fd5b885163e8302cbd60e01b8152808e018490528e90fd5b50801561100b565b50965050505050505080f35b815162461bcd60e51b8152808701849052600e818a01526d34b73b30b634b21031b0b63632b960911b6044820152606490fd5b833583811161130f57820186602319823603011261130f578651906112d682611a4c565b8d8101358252604481013585811161130b57916112fc8f928b9593869536920101611b70565b83820152815201930192610f72565b8a80fd5b8880fd5b9190503461032057826003193601126103205760209250549061133582612833565b519042108152f35b833461005b578060031936011261005b57611356611d17565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b839034610309576020366003190112610309576020906109166113b8611b3e565b6001600160a01b031660009081526009602052604090205490565b83903461030957816003193601126103095760209051620f42408152f35b505034610309576020366003190112610309573561140d611d17565b61141681612833565b620f424081116103095760015580f35b839034610309578160031936011261030957517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b83915061147636611ca0565b61148485546102a081612833565b6001600160a01b03907f000000000000000000000000000000000000000000000000000000000000000082163303610577578201916020928382820312610c325781356001600160401b03928382116117bd570181601f8201121561075a5780356114ee81611b59565b926114fb88519485611ab3565b818452868085019260051b840101928184116117b957878101925b84841061175557505050505080518015801561174b575b61173b5762030d40803a02903a8204143a151715611728578161155291999499611f99565b9160019061156a61156483543a611f99565b94612869565b606087895161157881611a4c565b8b815201528894899a5b848c106116565750989950899850508315905061164a576115ac906115a78434611f99565b611fac565b94868080806115bb8a34611e47565b997f00000000000000000000000000000000000000000000000000000000000000005af16115e7611d6f565b501561075a5786610bc0610bce6116339761160a84989785986003541697611f99565b945163040b850f60e31b9181019182523360248201526044810195909552939182906064820190565b8061163b5750f35b81808092335af1610537611d6f565b50505050505034611633565b6116608c84611f4d565b519b8c8a8a82511691015190303b15611724578d8d926116a0928451938492839263090594b360e01b84528a840152602496878401526044830190611c10565b038183305af19182611702575b50508b8a8e9f8d93156000146116f357519151911681528692917fe835ad64737fae407739c2bf764c9901751556ceb920e98995b44fa55ec87cca91a15b019b50611582565b505050509684809101976116eb565b84821161171357508c528b8a6116ad565b634e487b7160e01b8f52604186528efd5b8d80fd5b634e487b7160e01b885260118952602488fd5b855163251f56a160e21b81528890fd5b50601e811161152d565b83358781116117b55782018a601f1982860301126117b5578a519061177982611a4c565b8a8101358a811681036117245782528b8101359089821161172457916117a6868d80969481960101611b70565b83820152815201930192611516565b8b80fd5b8980fd5b8780fd5b8390346103095781600319360112610309576020905160038152f35b833461005b57602036600319011261005b57506103726118036117fe611b3e565b611e54565b83929192519384938452806020850152830190611c44565b9190503461032057826003193601126103205760209250549051908152f35b8390346103095781600319360112610309576020905160128152f35b839034610309578160031936011261030957602090611876610d42611f2c565b61187e611d17565b6002546001600160a01b0316906118c061189783612a16565b80937f000000000000000000000000000000000000000000000000000000000000000090612961565b51908152f35b839034610309578160031936011261030957517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b8390346103095781600319360112610309576020906008549051908152f35b83903461030957816003193601126103095760025490516001600160a01b039091168152602090f35b8390346103095781600319360112610309576020906007549051908152f35b83903461030957816003193601126103095760209051670de0b6b3a76400008152f35b505034610309576119b46119a736611bce565b919092546102a081612833565b6001600160a01b03917f000000000000000000000000000000000000000000000000000000000000000083163203611a04576119ff610306936001543a029060035416833091612891565b612005565b8380fd5b8491346103205782600319360112610320576103729250611a2882611a4c565b600d82526c42616e616e6120506f696e747360981b60208301525191829182611b12565b604081019081106001600160401b03821117611a6757604052565b634e487b7160e01b600052604160045260246000fd5b60c081019081106001600160401b03821117611a6757604052565b606081019081106001600160401b03821117611a6757604052565b90601f801991011681019081106001600160401b03821117611a6757604052565b6001600160401b038111611a6757601f01601f191660200190565b60005b838110611b025750506000910152565b8181015183820152602001611af2565b60409160208252611b328151809281602086015260208686019101611aef565b601f01601f1916010190565b600435906001600160a01b0382168203611b5457565b600080fd5b6001600160401b038111611a675760051b60200190565b81601f82011215611b5457803591611b8783611b59565b92611b956040519485611ab3565b808452602092838086019260051b820101928311611b54578301905b828210611bbf575050505090565b81358152908301908301611bb1565b906040600319830112611b54576004356001600160a01b0381168103611b545791602435906001600160401b038211611b5457611c0d91600401611b70565b90565b90815180825260208080930193019160005b828110611c30575050505090565b835185529381019392810192600101611c22565b611c0d9181511515815260018060a01b036020830151166020820152604082015160408201526060820151606082015260a0611c8f608084015160c0608085015260c0840190611c10565b9201519060a0818403910152611c10565b906020600319830112611b54576004356001600160401b0392838211611b545780602383011215611b54578160040135938411611b545760248483010111611b54576024019190565b8054821015611d015760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b6000546001600160a01b03163303611d2b57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b3d15611d9a573d90611d8082611ad4565b91611d8e6040519384611ab3565b82523d6000602084013e565b606090565b91908201809211611dac57565b634e487b7160e01b600052601160045260246000fd5b60405190611dcf82611a7d565b606060a0836000815260006020820152600060408201526000838201528260808201520152565b9060405191828154918282526020928383019160005283600020936000905b828210611e2d57505050611e2b92500383611ab3565b565b855484526001958601958895509381019390910190611e15565b91908203918211611dac57565b6000916000611e61611dc2565b6001600160a01b039384168252600b6020526040822080549194919081611e89575b50505050565b919394509194506000198201918211611f18576040611ead611f0993600493611ce9565b90549060031b1c95868152600a6020522060405193611ecb85611a7d565b815460ff81161515865260081c1660208501526001810154604085015260028101546060850152611efe60038201611df6565b608085015201611df6565b60a08201529038808080611e83565b634e487b7160e01b85526011600452602485fd5b600454611f3881612833565b421180611f425790565b506006546007541490565b8051821015611d015760209160051b010190565b15611f6857565b60405162461bcd60e51b815260206004820152600960248201526833b0b6b29037bb32b960b91b6044820152606490fd5b81810292918115918404141715611dac57565b8115611fb6570490565b634e487b7160e01b600052601260045260246000fd5b15611fd357565b60405162461bcd60e51b815260206004820152600a6024820152697769746864726177546f60b01b6044820152606490fd5b61200e81611e54565b511590811591612383575b501561233e5781519081151580612333575b156122fc5760009182905b8082106122c857505060018060a01b0381169182600052602091600983526040908160002054831161228c578261206c916127e1565b6001938460065401938460065586519661208588611b59565b976120928551998a611ab3565b8089526120a1601f1991611b59565b0136838a01378351976120b389611a7d565b60008952828901848152858a0187815260608b01916000835260808c0194855260a08c0193845289600052600a8652876000209b5115159060ff8d5491610100600160a81b03905160081b169216906affffffffffffffffffffff60a81b1617178b5551898b01555160028a01556003890191519889516001600160401b0393848211611a6757680100000000000000009b8c8311611a67578690825484845580851061225f575b500190600052856000208b60005b84811061224d57505050505060040190518051928311611a6757898311611a675783908254848455808510612220575b500190600052826000208860005b84811061220e57505050505081600052600b81528260002096875490811015611a6757856111ae827fca49f418dd97ad76b84ed6fb8e915ecccb519c5379cf6a4a455c2be7618fda2f9a60609a61220095018155611ce9565b8251948552840152820152a1565b858451940193818401550189906121a7565b836000528a858460002092830192015b82811061223e575050612199565b600081558794508c9101612230565b88845194019381840155018c90612169565b836000528d858460002092830192015b82811061227d57505061215b565b600081558a94508f910161226f565b815162461bcd60e51b81526004810185905260156024820152740e0ded2dce8e640c2e4ca40dcdee840cadcdeeaced605b1b6044820152606490fd5b90926122f46001916122e36122dd8789611f4d565b51612833565b6122ed8688611f4d565b5190611d9f565b930190612036565b60405162461bcd60e51b815260206004820152600f60248201526e696e76616c696420626574416d747360881b6044820152606490fd5b50600382111561202b565b60405162461bcd60e51b815260206004820152601860248201527f6c61737420726f756e64206e6f742066756c66696c6c656400000000000000006044820152606490fd5b90501538612019565b906005549182156123e957670de0b6b3a764000090818102918183041490151715611dac576123bb8382611fac565b9283159182156123dd575b50506123ce57565b9060018101809111611dac5790565b061515905038806123c6565b604051637c946ed760e01b8152600490fd5b1561240257565b60405162461bcd60e51b815260206004820152601060248201526f33b0b6b29034b9902727aa1037bb32b960811b6044820152606490fd5b90816020910312611b5457518015158103611b545790565b6040519260209361249a606882878101943360601b86524660348301523060601b605483015261248a815180928b8686019101611aef565b8101036048810184520182611ab3565b519020604051848101917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008352603c820152603c81526124d981611a98565b5190206124e583611ad4565b906124f36040519283611ab3565b8382523684840111611b545760008585612520966125189683870137840101526126a8565b91909161258e565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116036125555750565b6064906040519062461bcd60e51b825260048201526012602482015271696e76616c6964207369676e61747572652160701b6044820152fd5b6005811015612692578061259f5750565b600181036125ec5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036126395760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461264257565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b9060418151146000146126d6576126d2916020820151906060604084015193015160001a906126e0565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116127635791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa156127565781516001600160a01b03811615612750579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b907f6ff849a3868dd59429d6eeae1c7cd02119b80ab215230e999e9b927df85644709160018060a01b038116600052600960205260406000206127b3838254611d9f565b90556127c182600854611d9f565b600855604080516001600160a01b039290921682526020820192909252a1565b907fa813766a77a805e8fc44fa2d6436a1c6a84d38d443c1238f20ed0424bcd587859160018060a01b03811660005260096020526040600020612825838254611e47565b90556127c182600854611e47565b1561283a57565b60405162461bcd60e51b81526020600482015260076024820152666973207a65726f60c81b6044820152606490fd5b8034106128735750565b60449060405190633ce6d0ef60e21b82523460048301526024820152fd5b6040516323b872dd60e01b602082019081526001600160a01b03938416602483015292909316604484015260648084019490945292825260a0820192906001600160401b03841183851017611a67576000809493819460405251925af16128f6611d6f565b81612932575b501561290457565b60405162461bcd60e51b8152602060048201526006602482015265212816a9aa2360d11b6044820152606490fd5b8051801592508215612947575b5050386128fc565b61295a925060208091830101910161243a565b388061293f565b60405163a9059cbb60e01b602082019081526001600160a01b039093166024820152604481019390935260009283929083906129a08160648101610bc0565b51925af16129ac611d6f565b816129e7575b50156129ba57565b60405162461bcd60e51b815260206004820152600560248201526410940b54d560da1b6044820152606490fd5b80518015925082156129fc575b5050386129b2565b612a0f925060208091830101910161243a565b38806129f4565b60405160208101906370a0823160e01b825230602482015260248152612a3b81611a98565b6000928392839251915afa90612a4f611d6f565b9180612a70575b1561005b5760208280518101031261005b57506020015190565b50602082511015612a5656fea164736f6c6343000813000a00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000a63532878168c4d8df56a85b7f0f8a1f6abb792e000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c9015300000000000000000000000000000000000000000000000022b1c8c1227a0000
Deployed Bytecode
0x60806040908082526004908136101561005e575b505050361561002157600080fd5b600080808080347f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c5af1610053611d6f565b501561005b57005b80fd5b600092833560e01c91826306fdde0314611a0857508163090594b3146119945781630a68ed3e146119715781630cbf20141461195257816311df99951461192957816318160ddd1461190a57816325de6036146118c65781632fc9255414611856578163313ce5671461183a5781633197cbb61461181b5781633c56256b146117dd57816340d6bb82146117c1578163599eac8a1461146a5781635d88cb4f1461142657816362bf0b9f146113f15781636fcff4df146113d357816370a0823114611397578163715018a61461133d5781637708d837146113135781638538928514610f0257816388704c7514610ee35781638891cf0d14610ea85781638da5cb5b14610e8057816395d89b4114610e455781639779ea4614610e275781639945e3d314610d24578163995f567914610d08578163ae46631314610ccd578163b0a6330114610c36578163b4f4c1ec14610b00578163b548765f14610ab6578163b7d0628b14610943578163bdb337d11461091d578163c1e714fe146108f5578163c2884c0a146108bd578163c30cfda71461089e578163c75a010314610821578163cbf99dd1146107dd578163d3be4fe314610787578163d7c81b5514610768578163e09af4401461057b578163e41d15b014610463578163eb6d3a111461043a578163f2fde38b14610376578163f6b0692a14610324575063fecb03b1146102685780610013565b60203660031901126103095780356001600160401b038111610320576102919036908301611b70565b906102a781546102a081612833565b4210611f61565b62030d4090813a02913a8304143a15171561030d57506102c690612869565b81808080347f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c5af16102f6611d6f565b5015610309576103069033612005565b80f35b5080fd5b634e487b7160e01b845260119052602483fd5b8280fd5b839034610309576020366003190112610309576103729161035f9082906001600160a01b03610351611b3e565b168152600b60205220611df6565b9051918291602083526020830190611c10565b0390f35b9190503461032057602036600319011261032057610392611b3e565b9061039b611d17565b6001600160a01b039182169283156103e857505082546001600160a01b0319811683178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b83903461030957816003193601126103095760035490516001600160a01b039091168152602090f35b90506060366003190112610320576001600160a01b03906024358281169190829003610577576044359283168093036105775761049e611d17565b60055461054f578115610540575082356005556bffffffffffffffffffffffff60a01b9081600254161760025560035416176003556104fd7f000000000000000000000000000000000000000000000000000000000002a30042611d9f565b9055346105075780f35b80808080347f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c5af1610537611d6f565b501561005b5780f35b51637c946ed760e01b81528390fd5b5162461bcd60e51b815260208185015260036024820152626f2d6f60e81b6044820152606490fd5b8480fd5b9050346103205761058b36611ca0565b90825191858060209485810190634dffb8ed60e11b8252306024820152602481526105b581611a98565b51907f000000000000000000000000a63532878168c4d8df56a85b7f0f8a1f6abb792e5afa6105e2611d6f565b908061075e575b1561075a578084806106009351830101910161243a565b1561071f57906106339184519161061683611a4c565b600c83526b0636c61696d41697244726f760a41b85840152612452565b33845260098152670de0b6b3a76400006106848386205461065381612833565b61065d81336127e1565b7f00000000000000000000000000000000000000000000000022b1c8c1227a000090611f99565b049260018060a01b0360025416918461069c84612a16565b106106ef57857f154a25614f47446861b76a16524acf5871d8ca809bd3e9bdc00a66c759aece996106e987876106d382338a612961565b5133815260208101919091529081906040820190565b0390a180f35b835162461bcd60e51b815291820152600b60248201526a3a37b8103ab81031b7b4b760a91b604482015260649150fd5b835162461bcd60e51b815280860184905260156024820152743bb0b4ba103337b9103234b9ba3934b13aba34b7b760591b6044820152606490fd5b8680fd5b50838151146105e9565b8390346103095781600319360112610309576020906006549051908152f35b8390346103095780600319360112610309576107a1611b3e565b6001600160a01b03168252600b6020528082208054602435939084101561005b57506020926107cf91611ce9565b91905490519160031b1c8152f35b839034610309578160031936011261030957517f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c6001600160a01b03168152602090f35b90503461032057602036600319011261032057816106e99161086a7fb68479619550fd129cc13fd5926e396b807828988fd8d73efebc02c26a447186943592546102a081612833565b6106d36108768361238c565b9261088f8460018060a01b036002541630903390612891565b61089881612833565b3361276f565b8390346103095781600319360112610309576020906001549051908152f35b8390346103095760203660031901126103095760209181906001600160a01b036108e5611b3e565b168152600b845220549051908152f35b9050823461005b57602036600319011261005b57506109166020923561238c565b9051908152f35b83903461030957816003193601126103095760209061093a611f2c565b90519015158152f35b905034610320578260031936011261032057606091600654906007548083116109b7575b5050815160208082528451818301819052919586958686019590830194505b8382106109935786860387f35b84518051875283015186840152879650948501949382019360019190910190610986565b909193506109c88185969496611e47565b906109d282611b59565b916109df87519384611ab3565b8083526109ee601f1991611b59565b01845b818110610a9457505081845b86610a088285611d9f565b1015610a8557610a188184611d9f565b90600191828101809111610a725780610a318388611f4d565b515287526020600a815260038a8920015490610a4d8388611f4d565b5101526000198114610a5f57016109fd565b634e487b7160e01b875260118652602487fd5b634e487b7160e01b885260118752602488fd5b50945050505091388080610967565b6020908851610aa281611a4c565b8781528288818301528287010152016109f1565b9050823461005b57602036600319011261005b57506005548015610af257610aea670de0b6b3a76400009160209435611f99565b049051908152f35b5051637c946ed760e01b8152fd5b9050610b0b36611bce565b919092610b1c81546102a081612833565b6001600160a01b037f000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c9015381163303610c325762030d4091823a02923a8404143a151715610c1f5750610be0928692838093610b81610b7b6001543a611f99565b93612869565b610b928382600354168b3091612891565b600354935163040b850f60e31b602082019081523360248301526044820194909452931692610bce81606481015b03601f198101835282611ab3565b51925af1610bda611d6f565b50611fcc565b82808080347f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c5af1610c10611d6f565b50156103205761030691612005565b634e487b7160e01b875260119052602486fd5b8580fd5b90503461032057602036600319011261032057610cb68161037294610c59611dc2565b5084358152600a6020522092825193610c7185611a7d565b805460ff81161515865260081c6001600160a01b0316602086015260018101548486015260028101546060860152610cab60038201611df6565b608086015201611df6565b60a083015251918291602083526020830190611c44565b839034610309578160031936011261030957602090517f000000000000000000000000000000000000000000000000000000000002a3008152f35b83903461030957816003193601126103095760209051600a8152f35b83903461030957610d6b610d3736611ca0565b610d47610d42611f2c565b6123fb565b835191610d5383611a4c565b600683526572656465656d60d01b6020840152612452565b33825260096020528082205490610d8182612833565b610d8b82336127e1565b80516301e9a69560e41b60208201908152336024830152604482018490528491829190610dbb8160648101610bc0565b5190827f000000000000000000000000a63532878168c4d8df56a85b7f0f8a1f6abb792e5af1610de9611d6f565b5015610320575133815260208101919091527f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a69080604081016106e9565b8390346103095781600319360112610309576020905162030d408152f35b839034610309578160031936011261030957805161037291610e6682611a4c565b600382526210941560ea1b60208301525191829182611b12565b839034610309578160031936011261030957905490516001600160a01b039091168152602090f35b839034610309578160031936011261030957602090517f00000000000000000000000000000000000000000000000022b1c8c1227a00008152f35b8390346103095781600319360112610309576020906005549051908152f35b919050346103205781600319360112610320578035916024938435916001600160401b03908184116103205736602385011215610320578385013593610f4785611b59565b94610f5483519687611ab3565b808652602093898588019260051b8401019236841161075a578a8101925b8484106112b257506001600160a01b0396935050507f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c85163303905061127f57809796975b855181101561127357885a1061127357610fd18187611f4d565b51519084610fdf8289611f4d565b5101519160019260079184835401809355808652600a808952878720938685015490831480159061126b575b611255578351928d8601908154850361124057508760ff19875416178655889389958a928b5b83811061115a575050509e9f9e60031461107a575b5050509050878161105e575b50505001969796610fb7565b828260026110729501555460081c1661276f565b388087611052565b60001985018581116111465785166110e35750505050858591146110a2575b80388080611046565b87825460081c166110c68160018060a01b0316600052600960205260406000205490565b806110d3575b5050611099565b6110dc916127e1565b38806110cc565b9091929360488114918261113d575b508115611132575b50611106575050611099565b9080925081029181830414901517156111205738806110cc565b634e487b7160e01b855260118a528b85fd5b6070915014386110fa565b159150386110f2565b5050634e487b7160e01b885260118d528e88fd5b60066111668285611f4d565b5106988c8a01998a811161122857908d809392600291829108156111ec575b5060038b14806111e4575b806111d7575b6111cd575b6111c790838c1b179a6111ae8386611ce9565b90919082549060031b91821b91600019901b1916179055565b01611031565b919550859161119b565b50828b1b80821614611196565b508615611190565b91928c6112008560039d949d809301611ce9565b9054911b1c80911b928184041490151715611228578d929161122191611d9f565b9838611185565b50505050508f8f60118c91634e487b7160e01b835252fd5b8f8f828d5191630b75137d60e41b8352820152fd5b885163e8302cbd60e01b8152808e018490528e90fd5b50801561100b565b50965050505050505080f35b815162461bcd60e51b8152808701849052600e818a01526d34b73b30b634b21031b0b63632b960911b6044820152606490fd5b833583811161130f57820186602319823603011261130f578651906112d682611a4c565b8d8101358252604481013585811161130b57916112fc8f928b9593869536920101611b70565b83820152815201930192610f72565b8a80fd5b8880fd5b9190503461032057826003193601126103205760209250549061133582612833565b519042108152f35b833461005b578060031936011261005b57611356611d17565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b839034610309576020366003190112610309576020906109166113b8611b3e565b6001600160a01b031660009081526009602052604090205490565b83903461030957816003193601126103095760209051620f42408152f35b505034610309576020366003190112610309573561140d611d17565b61141681612833565b620f424081116103095760015580f35b839034610309578160031936011261030957517f000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c901536001600160a01b03168152602090f35b83915061147636611ca0565b61148485546102a081612833565b6001600160a01b03907f000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c9015382163303610577578201916020928382820312610c325781356001600160401b03928382116117bd570181601f8201121561075a5780356114ee81611b59565b926114fb88519485611ab3565b818452868085019260051b840101928184116117b957878101925b84841061175557505050505080518015801561174b575b61173b5762030d40803a02903a8204143a151715611728578161155291999499611f99565b9160019061156a61156483543a611f99565b94612869565b606087895161157881611a4c565b8b815201528894899a5b848c106116565750989950899850508315905061164a576115ac906115a78434611f99565b611fac565b94868080806115bb8a34611e47565b997f00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c5af16115e7611d6f565b501561075a5786610bc0610bce6116339761160a84989785986003541697611f99565b945163040b850f60e31b9181019182523360248201526044810195909552939182906064820190565b8061163b5750f35b81808092335af1610537611d6f565b50505050505034611633565b6116608c84611f4d565b519b8c8a8a82511691015190303b15611724578d8d926116a0928451938492839263090594b360e01b84528a840152602496878401526044830190611c10565b038183305af19182611702575b50508b8a8e9f8d93156000146116f357519151911681528692917fe835ad64737fae407739c2bf764c9901751556ceb920e98995b44fa55ec87cca91a15b019b50611582565b505050509684809101976116eb565b84821161171357508c528b8a6116ad565b634e487b7160e01b8f52604186528efd5b8d80fd5b634e487b7160e01b885260118952602488fd5b855163251f56a160e21b81528890fd5b50601e811161152d565b83358781116117b55782018a601f1982860301126117b5578a519061177982611a4c565b8a8101358a811681036117245782528b8101359089821161172457916117a6868d80969481960101611b70565b83820152815201930192611516565b8b80fd5b8980fd5b8780fd5b8390346103095781600319360112610309576020905160038152f35b833461005b57602036600319011261005b57506103726118036117fe611b3e565b611e54565b83929192519384938452806020850152830190611c44565b9190503461032057826003193601126103205760209250549051908152f35b8390346103095781600319360112610309576020905160128152f35b839034610309578160031936011261030957602090611876610d42611f2c565b61187e611d17565b6002546001600160a01b0316906118c061189783612a16565b80937f000000000000000000000000a63532878168c4d8df56a85b7f0f8a1f6abb792e90612961565b51908152f35b839034610309578160031936011261030957517f000000000000000000000000a63532878168c4d8df56a85b7f0f8a1f6abb792e6001600160a01b03168152602090f35b8390346103095781600319360112610309576020906008549051908152f35b83903461030957816003193601126103095760025490516001600160a01b039091168152602090f35b8390346103095781600319360112610309576020906007549051908152f35b83903461030957816003193601126103095760209051670de0b6b3a76400008152f35b505034610309576119b46119a736611bce565b919092546102a081612833565b6001600160a01b03917f000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c9015383163203611a04576119ff610306936001543a029060035416833091612891565b612005565b8380fd5b8491346103205782600319360112610320576103729250611a2882611a4c565b600d82526c42616e616e6120506f696e747360981b60208301525191829182611b12565b604081019081106001600160401b03821117611a6757604052565b634e487b7160e01b600052604160045260246000fd5b60c081019081106001600160401b03821117611a6757604052565b606081019081106001600160401b03821117611a6757604052565b90601f801991011681019081106001600160401b03821117611a6757604052565b6001600160401b038111611a6757601f01601f191660200190565b60005b838110611b025750506000910152565b8181015183820152602001611af2565b60409160208252611b328151809281602086015260208686019101611aef565b601f01601f1916010190565b600435906001600160a01b0382168203611b5457565b600080fd5b6001600160401b038111611a675760051b60200190565b81601f82011215611b5457803591611b8783611b59565b92611b956040519485611ab3565b808452602092838086019260051b820101928311611b54578301905b828210611bbf575050505090565b81358152908301908301611bb1565b906040600319830112611b54576004356001600160a01b0381168103611b545791602435906001600160401b038211611b5457611c0d91600401611b70565b90565b90815180825260208080930193019160005b828110611c30575050505090565b835185529381019392810192600101611c22565b611c0d9181511515815260018060a01b036020830151166020820152604082015160408201526060820151606082015260a0611c8f608084015160c0608085015260c0840190611c10565b9201519060a0818403910152611c10565b906020600319830112611b54576004356001600160401b0392838211611b545780602383011215611b54578160040135938411611b545760248483010111611b54576024019190565b8054821015611d015760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b6000546001600160a01b03163303611d2b57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b3d15611d9a573d90611d8082611ad4565b91611d8e6040519384611ab3565b82523d6000602084013e565b606090565b91908201809211611dac57565b634e487b7160e01b600052601160045260246000fd5b60405190611dcf82611a7d565b606060a0836000815260006020820152600060408201526000838201528260808201520152565b9060405191828154918282526020928383019160005283600020936000905b828210611e2d57505050611e2b92500383611ab3565b565b855484526001958601958895509381019390910190611e15565b91908203918211611dac57565b6000916000611e61611dc2565b6001600160a01b039384168252600b6020526040822080549194919081611e89575b50505050565b919394509194506000198201918211611f18576040611ead611f0993600493611ce9565b90549060031b1c95868152600a6020522060405193611ecb85611a7d565b815460ff81161515865260081c1660208501526001810154604085015260028101546060850152611efe60038201611df6565b608085015201611df6565b60a08201529038808080611e83565b634e487b7160e01b85526011600452602485fd5b600454611f3881612833565b421180611f425790565b506006546007541490565b8051821015611d015760209160051b010190565b15611f6857565b60405162461bcd60e51b815260206004820152600960248201526833b0b6b29037bb32b960b91b6044820152606490fd5b81810292918115918404141715611dac57565b8115611fb6570490565b634e487b7160e01b600052601260045260246000fd5b15611fd357565b60405162461bcd60e51b815260206004820152600a6024820152697769746864726177546f60b01b6044820152606490fd5b61200e81611e54565b511590811591612383575b501561233e5781519081151580612333575b156122fc5760009182905b8082106122c857505060018060a01b0381169182600052602091600983526040908160002054831161228c578261206c916127e1565b6001938460065401938460065586519661208588611b59565b976120928551998a611ab3565b8089526120a1601f1991611b59565b0136838a01378351976120b389611a7d565b60008952828901848152858a0187815260608b01916000835260808c0194855260a08c0193845289600052600a8652876000209b5115159060ff8d5491610100600160a81b03905160081b169216906affffffffffffffffffffff60a81b1617178b5551898b01555160028a01556003890191519889516001600160401b0393848211611a6757680100000000000000009b8c8311611a67578690825484845580851061225f575b500190600052856000208b60005b84811061224d57505050505060040190518051928311611a6757898311611a675783908254848455808510612220575b500190600052826000208860005b84811061220e57505050505081600052600b81528260002096875490811015611a6757856111ae827fca49f418dd97ad76b84ed6fb8e915ecccb519c5379cf6a4a455c2be7618fda2f9a60609a61220095018155611ce9565b8251948552840152820152a1565b858451940193818401550189906121a7565b836000528a858460002092830192015b82811061223e575050612199565b600081558794508c9101612230565b88845194019381840155018c90612169565b836000528d858460002092830192015b82811061227d57505061215b565b600081558a94508f910161226f565b815162461bcd60e51b81526004810185905260156024820152740e0ded2dce8e640c2e4ca40dcdee840cadcdeeaced605b1b6044820152606490fd5b90926122f46001916122e36122dd8789611f4d565b51612833565b6122ed8688611f4d565b5190611d9f565b930190612036565b60405162461bcd60e51b815260206004820152600f60248201526e696e76616c696420626574416d747360881b6044820152606490fd5b50600382111561202b565b60405162461bcd60e51b815260206004820152601860248201527f6c61737420726f756e64206e6f742066756c66696c6c656400000000000000006044820152606490fd5b90501538612019565b906005549182156123e957670de0b6b3a764000090818102918183041490151715611dac576123bb8382611fac565b9283159182156123dd575b50506123ce57565b9060018101809111611dac5790565b061515905038806123c6565b604051637c946ed760e01b8152600490fd5b1561240257565b60405162461bcd60e51b815260206004820152601060248201526f33b0b6b29034b9902727aa1037bb32b960811b6044820152606490fd5b90816020910312611b5457518015158103611b545790565b6040519260209361249a606882878101943360601b86524660348301523060601b605483015261248a815180928b8686019101611aef565b8101036048810184520182611ab3565b519020604051848101917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008352603c820152603c81526124d981611a98565b5190206124e583611ad4565b906124f36040519283611ab3565b8382523684840111611b545760008585612520966125189683870137840101526126a8565b91909161258e565b6001600160a01b037f000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c9015381169116036125555750565b6064906040519062461bcd60e51b825260048201526012602482015271696e76616c6964207369676e61747572652160701b6044820152fd5b6005811015612692578061259f5750565b600181036125ec5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036126395760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461264257565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b9060418151146000146126d6576126d2916020820151906060604084015193015160001a906126e0565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116127635791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa156127565781516001600160a01b03811615612750579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b907f6ff849a3868dd59429d6eeae1c7cd02119b80ab215230e999e9b927df85644709160018060a01b038116600052600960205260406000206127b3838254611d9f565b90556127c182600854611d9f565b600855604080516001600160a01b039290921682526020820192909252a1565b907fa813766a77a805e8fc44fa2d6436a1c6a84d38d443c1238f20ed0424bcd587859160018060a01b03811660005260096020526040600020612825838254611e47565b90556127c182600854611e47565b1561283a57565b60405162461bcd60e51b81526020600482015260076024820152666973207a65726f60c81b6044820152606490fd5b8034106128735750565b60449060405190633ce6d0ef60e21b82523460048301526024820152fd5b6040516323b872dd60e01b602082019081526001600160a01b03938416602483015292909316604484015260648084019490945292825260a0820192906001600160401b03841183851017611a67576000809493819460405251925af16128f6611d6f565b81612932575b501561290457565b60405162461bcd60e51b8152602060048201526006602482015265212816a9aa2360d11b6044820152606490fd5b8051801592508215612947575b5050386128fc565b61295a925060208091830101910161243a565b388061293f565b60405163a9059cbb60e01b602082019081526001600160a01b039093166024820152604481019390935260009283929083906129a08160648101610bc0565b51925af16129ac611d6f565b816129e7575b50156129ba57565b60405162461bcd60e51b815260206004820152600560248201526410940b54d560da1b6044820152606490fd5b80518015925082156129fc575b5050386129b2565b612a0f925060208091830101910161243a565b38806129f4565b60405160208101906370a0823160e01b825230602482015260248152612a3b81611a98565b6000928392839251915afa90612a4f611d6f565b9180612a70575b1561005b5760208280518101031261005b57506020015190565b50602082511015612a5656fea164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000a63532878168c4d8df56a85b7f0f8a1f6abb792e000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c9015300000000000000000000000000000000000000000000000022b1c8c1227a0000
-----Decoded View---------------
Arg [0] : _gameRngWalletAddress (address): 0x63795e0f9223Ec4BFeF5fBE3dbf9331F1C57cC5c
Arg [1] : _gamePeriod (uint256): 172800
Arg [2] : _V3Deployer (address): 0xA63532878168C4D8Df56A85b7F0f8a1F6ABB792E
Arg [3] : _rollOperator (address): 0xD7BCEE2EaA9579F39c2290d48e0fA3c706C90153
Arg [4] : _airdropRate (uint256): 2500000000000000000
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000063795e0f9223ec4bfef5fbe3dbf9331f1c57cc5c
Arg [1] : 000000000000000000000000000000000000000000000000000000000002a300
Arg [2] : 000000000000000000000000a63532878168c4d8df56a85b7f0f8a1f6abb792e
Arg [3] : 000000000000000000000000d7bcee2eaa9579f39c2290d48e0fa3c706c90153
Arg [4] : 00000000000000000000000000000000000000000000000022b1c8c1227a0000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.