Source Code
Overview
S Balance
More Info
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
QueueSystem
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; interface IChibbleNFT { function ownerOf(uint256 tokenId) external view returns (address); function getEffectivePowerScore(uint256 tokenId) external view returns (uint256); function getLevel(uint256 tokenId) external view returns (uint256); } interface IDuelEngine { function executeDuel(uint256 chibble1, uint256 chibble2) external; function queueSystem() external view returns (address); } contract QueueSystem is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable, UUPSUpgradeable { IChibbleNFT public chibbleNFT; IDuelEngine public duelEngine; struct Tournament { uint256 entryFee; uint256 minEPS; uint256 maxEPS; uint256 startTime; uint256 maxParticipants; uint256[] participants; bool isActive; bool isFinished; mapping(uint256 => bool) hasJoined; mapping(address => bool) hasClaimedReward; uint256 prizePool; uint256[] winners; // Ordered array of winners (1st to 8th place) } struct Challenge { uint256 challenger; uint256 defender; uint256 timestamp; bool isActive; bool isDenied; uint256 denyCount; } // State variables mapping(uint256 => Tournament) public tournaments; uint256 public tournamentCounter; // Battle Arena mapping(uint256 => bool) public isInArena; uint256[] public arenaQueue; mapping(uint256 => uint256) public arenaEntryTime; mapping(uint256 => Challenge[]) public pendingChallenges; // Constants uint256 public constant MIN_LEVEL_FOR_ARENA = 5; uint256 public constant CHALLENGE_EXPIRY = 3 hours; uint256 public constant MAX_DENY_COUNT = 2; uint256 public constant MAX_ARENA_TIME = 4 hours; // Tournament prize distribution (in basis points - 100 = 1%) uint256[] public prizeBps; // Events event TournamentCreated(uint256 indexed tournamentId, uint256 entryFee, uint256 minEPS, uint256 maxEPS); event TournamentJoined(uint256 indexed tournamentId, uint256 indexed chibbleId); event TournamentFinished(uint256 indexed tournamentId, uint256[] winners); event TournamentRewardClaimed(uint256 indexed tournamentId, address indexed player, uint256 amount); event EnteredArena(uint256 indexed chibbleId); event LeftArena(uint256 indexed chibbleId); event ArenaMatch(uint256 indexed chibble1, uint256 indexed chibble2); event ChallengeIssued(uint256 indexed challenger, uint256 indexed defender); event ChallengeDenied(uint256 indexed challenger, uint256 indexed defender); event ChallengeAccepted(uint256 indexed challenger, uint256 indexed defender); event ChallengeExpired(uint256 indexed challenger, uint256 indexed defender); event DuelEngineUpdated(address indexed duelEngine); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize( address _chibbleNFT, address _duelEngine ) public initializer { // Change the order of initializations __Ownable_init(msg.sender); __ReentrancyGuard_init(); __UUPSUpgradeable_init(); require(_chibbleNFT != address(0), "Invalid Chibble address"); require(_duelEngine != address(0), "Invalid DuelEngine address"); chibbleNFT = IChibbleNFT(_chibbleNFT); duelEngine = IDuelEngine(_duelEngine); // Initialize prizeBps in the initializer prizeBps = [4500, 2000, 1000, 500, 500, 500, 500, 500]; // 45%, 20%, 10%, 5% x 5 } // Tournament Functions function createTournament( uint256 _entryFee, uint256 _minEPS, uint256 _maxEPS, uint256 _startTime, uint256 _maxParticipants ) external onlyOwner { require(_startTime > block.timestamp, "Invalid start time"); require(_maxParticipants > 0 && _maxParticipants % 2 == 0, "Invalid participant count"); require(_maxParticipants <= 128, "Too many participants"); uint256 tournamentId = tournamentCounter++; Tournament storage tournament = tournaments[tournamentId]; tournament.entryFee = _entryFee; tournament.minEPS = _minEPS; tournament.maxEPS = _maxEPS; tournament.startTime = _startTime; tournament.maxParticipants = _maxParticipants; tournament.isActive = true; tournament.isFinished = false; emit TournamentCreated(tournamentId, _entryFee, _minEPS, _maxEPS); } function joinTournament(uint256 tournamentId, uint256 chibbleId) external payable nonReentrant { Tournament storage tournament = tournaments[tournamentId]; require(tournament.isActive && !tournament.isFinished, "Tournament not active"); require(block.timestamp < tournament.startTime, "Tournament already started"); require(msg.value >= tournament.entryFee, "Insufficient entry fee"); require(!tournament.hasJoined[chibbleId], "Already joined"); require(tournament.participants.length < tournament.maxParticipants, "Tournament full"); require(chibbleNFT.ownerOf(chibbleId) == msg.sender, "Not owner"); uint256 eps = chibbleNFT.getEffectivePowerScore(chibbleId); require(eps >= tournament.minEPS && eps <= tournament.maxEPS, "EPS out of range"); tournament.participants.push(chibbleId); tournament.hasJoined[chibbleId] = true; tournament.prizePool += tournament.entryFee; emit TournamentJoined(tournamentId, chibbleId); } function finishTournament(uint256 tournamentId, uint256[] calldata winners) external onlyOwner { Tournament storage tournament = tournaments[tournamentId]; require(tournament.isActive && !tournament.isFinished, "Invalid tournament state"); require(block.timestamp >= tournament.startTime, "Tournament not started"); require(winners.length == 8, "Invalid winners count"); // Verify all winners were participants for (uint256 i = 0; i < winners.length; i++) { require(tournament.hasJoined[winners[i]], "Invalid winner"); } tournament.winners = winners; tournament.isFinished = true; tournament.isActive = false; emit TournamentFinished(tournamentId, winners); } function claimTournamentReward(uint256 tournamentId) external nonReentrant { Tournament storage tournament = tournaments[tournamentId]; require(tournament.isFinished, "Tournament not finished"); require(!tournament.hasClaimedReward[msg.sender], "Already claimed"); uint256 position = _findWinnerPosition(tournament.winners, msg.sender); require(position < prizeBps.length, "No prize to claim"); uint256 reward = (tournament.prizePool * prizeBps[position]) / 10000; tournament.hasClaimedReward[msg.sender] = true; payable(msg.sender).transfer(reward); emit TournamentRewardClaimed(tournamentId, msg.sender, reward); } function setDuelEngine(address _duelEngine) external onlyOwner { require(IDuelEngine(_duelEngine).queueSystem() == address(0) || IDuelEngine(_duelEngine).queueSystem() == address(this), "Invalid duel engine"); duelEngine = IDuelEngine(_duelEngine); emit DuelEngineUpdated(_duelEngine); } // Arena Functions function enterArena(uint256 chibbleId) external { require(chibbleNFT.ownerOf(chibbleId) == msg.sender, "Not owner"); require(!isInArena[chibbleId], "Already in arena"); require(chibbleNFT.getLevel(chibbleId) >= MIN_LEVEL_FOR_ARENA, "Level too low"); _cleanExpiredFromArena(); isInArena[chibbleId] = true; arenaQueue.push(chibbleId); arenaEntryTime[chibbleId] = block.timestamp; emit EnteredArena(chibbleId); if(arenaQueue.length >= 2) { _matchArenaPlayers(); } } function leaveArena(uint256 chibbleId) external { require(chibbleNFT.ownerOf(chibbleId) == msg.sender, "Not owner"); require(isInArena[chibbleId], "Not in arena"); _removeFromArena(chibbleId); emit LeftArena(chibbleId); } function issueChallengeInArena(uint256 challengerId, uint256 defenderId) external { require(chibbleNFT.ownerOf(challengerId) == msg.sender, "Not challenger owner"); require(isInArena[challengerId] && isInArena[defenderId], "Not in arena"); require(challengerId != defenderId, "Cannot challenge self"); Challenge memory newChallenge = Challenge({ challenger: challengerId, defender: defenderId, timestamp: block.timestamp, isActive: true, isDenied: false, denyCount: 0 }); pendingChallenges[defenderId].push(newChallenge); emit ChallengeIssued(challengerId, defenderId); } function acceptChallenge(uint256 defenderId, uint256 challengeIndex) external { require(chibbleNFT.ownerOf(defenderId) == msg.sender, "Not defender owner"); Challenge storage challenge = pendingChallenges[defenderId][challengeIndex]; require(challenge.isActive && !challenge.isDenied, "Invalid challenge"); require(block.timestamp <= challenge.timestamp + CHALLENGE_EXPIRY, "Challenge expired"); require(isInArena[challenge.challenger] && isInArena[defenderId], "Not in arena"); // Execute the duel duelEngine.executeDuel(challenge.challenger, defenderId); // Remove both from arena _removeFromArena(challenge.challenger); _removeFromArena(defenderId); challenge.isActive = false; emit ChallengeAccepted(challenge.challenger, defenderId); } function denyChallenge(uint256 defenderId, uint256 challengeIndex) external { require(chibbleNFT.ownerOf(defenderId) == msg.sender, "Not defender owner"); Challenge storage challenge = pendingChallenges[defenderId][challengeIndex]; require(challenge.isActive && !challenge.isDenied, "Invalid challenge"); require(block.timestamp <= challenge.timestamp + CHALLENGE_EXPIRY, "Challenge expired"); challenge.denyCount++; if (challenge.denyCount > MAX_DENY_COUNT) { // Auto-accept after max denies duelEngine.executeDuel(challenge.challenger, defenderId); _removeFromArena(challenge.challenger); _removeFromArena(defenderId); challenge.isActive = false; emit ChallengeAccepted(challenge.challenger, defenderId); } else { challenge.isDenied = true; emit ChallengeDenied(challenge.challenger, defenderId); } } // Internal functions function _matchArenaPlayers() internal { require(address(duelEngine) != address(0), "Duel engine not set"); if(arenaQueue.length < 2) return; uint256 rand = uint256(keccak256(abi.encodePacked(block.prevrandao, block.timestamp))); uint256 index1 = rand % arenaQueue.length; uint256 index2; do { index2 = uint256(keccak256(abi.encodePacked(block.prevrandao, block.timestamp, "second"))) % arenaQueue.length; } while(index2 == index1); uint256 chibble1 = arenaQueue[index1]; uint256 chibble2 = arenaQueue[index2]; // Execute the duel through DuelEngine duelEngine.executeDuel(chibble1, chibble2); // Remove both from arena _removeFromArena(chibble1); _removeFromArena(chibble2); emit ArenaMatch(chibble1, chibble2); } function _removeFromArena(uint256 chibbleId) internal { isInArena[chibbleId] = false; delete arenaEntryTime[chibbleId]; for(uint i = 0; i < arenaQueue.length; i++) { if(arenaQueue[i] == chibbleId) { arenaQueue[i] = arenaQueue[arenaQueue.length - 1]; arenaQueue.pop(); break; } } } function _cleanExpiredFromArena() internal { for(uint i = 0; i < arenaQueue.length; i++) { if(block.timestamp >= arenaEntryTime[arenaQueue[i]] + MAX_ARENA_TIME) { uint256 chibbleId = arenaQueue[i]; _removeFromArena(chibbleId); emit LeftArena(chibbleId); i--; } } } function _findWinnerPosition(uint256[] storage winners, address player) internal view returns (uint256) { for (uint256 i = 0; i < winners.length; i++) { if (chibbleNFT.ownerOf(winners[i]) == player) { return i; } } return type(uint256).max; } // View functions function getPendingChallenges(uint256 defenderId) external view returns ( uint256[] memory challengers, uint256[] memory timestamps, bool[] memory isActive, bool[] memory isDenied, uint256[] memory denyCounts ) { Challenge[] storage challenges = pendingChallenges[defenderId]; challengers = new uint256[](challenges.length); timestamps = new uint256[](challenges.length); isActive = new bool[](challenges.length); isDenied = new bool[](challenges.length); denyCounts = new uint256[](challenges.length); for (uint256 i = 0; i < challenges.length; i++) { challengers[i] = challenges[i].challenger; timestamps[i] = challenges[i].timestamp; isActive[i] = challenges[i].isActive; isDenied[i] = challenges[i].isDenied; denyCounts[i] = challenges[i].denyCount; } } function getArenaQueue() external view returns (uint256[] memory) { return arenaQueue; } function getTournamentStatus(uint256 tournamentId) external view returns ( uint256 entryFee, uint256 minEPS, uint256 maxEPS, uint256 startTime, uint256 maxParticipants, uint256[] memory participants, bool isActive, bool isFinished, uint256 prizePool, uint256[] memory winners ) { Tournament storage tournament = tournaments[tournamentId]; return ( tournament.entryFee, tournament.minEPS, tournament.maxEPS, tournament.startTime, tournament.maxParticipants, tournament.participants, tournament.isActive, tournament.isFinished, tournament.prizePool, tournament.winners ); } function calculatePrize(uint256 tournamentId, uint256 position) external view returns (uint256) { require(position < prizeBps.length, "Invalid position"); Tournament storage tournament = tournaments[tournamentId]; return (tournament.prizePool * prizeBps[position]) / 10000; } function getChallengeCount(uint256 defenderId) external view returns (uint256) { return pendingChallenges[defenderId].length; } function isInArenaQueue(uint256 chibbleId) external view returns (bool) { for(uint256 i = 0; i < arenaQueue.length; i++) { if(arenaQueue[i] == chibbleId) return true; } return false; } function getRemainingArenaTime(uint256 chibbleId) external view returns (uint256) { if (!isInArena[chibbleId]) return 0; uint256 entryTime = arenaEntryTime[chibbleId]; if (block.timestamp >= entryTime + MAX_ARENA_TIME) return 0; return entryTime + MAX_ARENA_TIME - block.timestamp; } function hasJoinedTournament(uint256 tournamentId, uint256 chibbleId) external view returns (bool) { return tournaments[tournamentId].hasJoined[chibbleId]; } function hasClaimedReward(uint256 tournamentId, address player) external view returns (bool) { return tournaments[tournamentId].hasClaimedReward[player]; } // Admin functions function updatePrizeBps(uint256[] calldata newPrizeBps) external onlyOwner { uint256 total = 0; for (uint256 i = 0; i < newPrizeBps.length; i++) { total += newPrizeBps[i]; } require(total == 10000, "Invalid prize distribution"); require(newPrizeBps.length == 8, "Invalid number of prize positions"); prizeBps = newPrizeBps; } function withdrawUnclaimed(uint256 tournamentId) external onlyOwner { Tournament storage tournament = tournaments[tournamentId]; require(tournament.isFinished, "Tournament not finished"); require(block.timestamp > tournament.startTime + 30 days, "Too early"); uint256 remainingPrizePool = tournament.prizePool; tournament.prizePool = 0; payable(owner()).transfer(remainingPrizePool); } function emergencyPause(uint256 tournamentId) external onlyOwner { Tournament storage tournament = tournaments[tournamentId]; require(!tournament.isFinished, "Tournament already finished"); tournament.isActive = false; } function emergencyResume(uint256 tournamentId) external onlyOwner { Tournament storage tournament = tournaments[tournamentId]; require(!tournament.isFinished, "Tournament already finished"); tournament.isActive = true; } function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} receive() external payable {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.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. * * The initial owner is set to the address provided by the deployer. 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 OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @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) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @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 { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.22; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC-1967 compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC-1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.20; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.22; import {IBeacon} from "../beacon/IBeacon.sol"; import {IERC1967} from "../../interfaces/IERC1967.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This library provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. */ library ERC1967Utils { /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit IERC1967.Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit IERC1967.AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the ERC-1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit IERC1967.BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, bytes memory returndata) = recipient.call{value: amount}(""); if (!success) { _revert(returndata); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev Returns a `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "viaIR": true, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chibble1","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"chibble2","type":"uint256"}],"name":"ArenaMatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"challenger","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"defender","type":"uint256"}],"name":"ChallengeAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"challenger","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"defender","type":"uint256"}],"name":"ChallengeDenied","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"challenger","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"defender","type":"uint256"}],"name":"ChallengeExpired","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"challenger","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"defender","type":"uint256"}],"name":"ChallengeIssued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"duelEngine","type":"address"}],"name":"DuelEngineUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chibbleId","type":"uint256"}],"name":"EnteredArena","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chibbleId","type":"uint256"}],"name":"LeftArena","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":true,"internalType":"uint256","name":"tournamentId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"entryFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minEPS","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxEPS","type":"uint256"}],"name":"TournamentCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tournamentId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"winners","type":"uint256[]"}],"name":"TournamentFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tournamentId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"chibbleId","type":"uint256"}],"name":"TournamentJoined","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tournamentId","type":"uint256"},{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TournamentRewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"CHALLENGE_EXPIRY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ARENA_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DENY_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LEVEL_FOR_ARENA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"defenderId","type":"uint256"},{"internalType":"uint256","name":"challengeIndex","type":"uint256"}],"name":"acceptChallenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"arenaEntryTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"arenaQueue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"uint256","name":"position","type":"uint256"}],"name":"calculatePrize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chibbleNFT","outputs":[{"internalType":"contract IChibbleNFT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"}],"name":"claimTournamentReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_entryFee","type":"uint256"},{"internalType":"uint256","name":"_minEPS","type":"uint256"},{"internalType":"uint256","name":"_maxEPS","type":"uint256"},{"internalType":"uint256","name":"_startTime","type":"uint256"},{"internalType":"uint256","name":"_maxParticipants","type":"uint256"}],"name":"createTournament","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"defenderId","type":"uint256"},{"internalType":"uint256","name":"challengeIndex","type":"uint256"}],"name":"denyChallenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"duelEngine","outputs":[{"internalType":"contract IDuelEngine","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"}],"name":"emergencyPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"}],"name":"emergencyResume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chibbleId","type":"uint256"}],"name":"enterArena","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"uint256[]","name":"winners","type":"uint256[]"}],"name":"finishTournament","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getArenaQueue","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"defenderId","type":"uint256"}],"name":"getChallengeCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"defenderId","type":"uint256"}],"name":"getPendingChallenges","outputs":[{"internalType":"uint256[]","name":"challengers","type":"uint256[]"},{"internalType":"uint256[]","name":"timestamps","type":"uint256[]"},{"internalType":"bool[]","name":"isActive","type":"bool[]"},{"internalType":"bool[]","name":"isDenied","type":"bool[]"},{"internalType":"uint256[]","name":"denyCounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chibbleId","type":"uint256"}],"name":"getRemainingArenaTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"}],"name":"getTournamentStatus","outputs":[{"internalType":"uint256","name":"entryFee","type":"uint256"},{"internalType":"uint256","name":"minEPS","type":"uint256"},{"internalType":"uint256","name":"maxEPS","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"maxParticipants","type":"uint256"},{"internalType":"uint256[]","name":"participants","type":"uint256[]"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isFinished","type":"bool"},{"internalType":"uint256","name":"prizePool","type":"uint256"},{"internalType":"uint256[]","name":"winners","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"address","name":"player","type":"address"}],"name":"hasClaimedReward","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"uint256","name":"chibbleId","type":"uint256"}],"name":"hasJoinedTournament","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_chibbleNFT","type":"address"},{"internalType":"address","name":"_duelEngine","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isInArena","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chibbleId","type":"uint256"}],"name":"isInArenaQueue","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"challengerId","type":"uint256"},{"internalType":"uint256","name":"defenderId","type":"uint256"}],"name":"issueChallengeInArena","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"},{"internalType":"uint256","name":"chibbleId","type":"uint256"}],"name":"joinTournament","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chibbleId","type":"uint256"}],"name":"leaveArena","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingChallenges","outputs":[{"internalType":"uint256","name":"challenger","type":"uint256"},{"internalType":"uint256","name":"defender","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isDenied","type":"bool"},{"internalType":"uint256","name":"denyCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"prizeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_duelEngine","type":"address"}],"name":"setDuelEngine","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tournamentCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tournaments","outputs":[{"internalType":"uint256","name":"entryFee","type":"uint256"},{"internalType":"uint256","name":"minEPS","type":"uint256"},{"internalType":"uint256","name":"maxEPS","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"maxParticipants","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isFinished","type":"bool"},{"internalType":"uint256","name":"prizePool","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"newPrizeBps","type":"uint256[]"}],"name":"updatePrizeBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tournamentId","type":"uint256"}],"name":"withdrawUnclaimed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a080604052346100ea57306080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c166100d9576002600160401b03196001600160401b03821601610073575b60405161315a90816100f082396080518181816119dd0152611ad90152f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a13880610054565b63f92ee8a960e01b60005260046000fd5b600080fdfe608080604052600436101561001d575b50361561001b57600080fd5b005b600090813560e01c908163131178ac146125745750806318690466146124eb5780632f8cbdb71461235f578063314f3c44146123355780633a7b06bb146122bb5780633b97f893146122725780633e85cd741461224357806340e97393146120ed57806346feb24a14612043578063485cc95514611cf357806348a6a54e14611cd75780634afe5e7714611cae5780634f1ef28614611a5d57806351ae40e814611a3257806352d1902d146119ca578063571d7c6d146119ad5780635875c61c1461163557806368ebd69714611600578063694dead1146114805780636e4bc6d3146114595780636f7d1a9e146112bf578063715018a61461125557806373ed5c1c146112375780637503e1b7146111b85780637759cbc014610f675780637b092e8714610d7a57806386bc4e9314610cf15780638da5cb5b14610cbb5780639ec3529814610c94578063ad3cb1cc14610c1a578063ad3fbe3014610bd4578063c305fc6c14610baa578063c8b727a114610b5b578063c91cdee214610883578063ce0da4d814610867578063d83d3d1b146105c1578063d959eebe14610598578063e12fc1d71461057b578063e6634c6714610497578063e96d5c0f146103d5578063eb6dcd4014610268578063f2fde38b1461023b5763f4fcbfe00361000f5734610238576020366003190112610238576004359060085482101561023857602061022983612820565b90549060031b1c604051908152f35b80fd5b503461023857602036600319011261023857610265610258612785565b610260612d5a565b612c23565b80f35b503461023857602036600319011261023857610282612785565b61028a612d5a565b6040516329eecf6760e01b81526001600160a01b039190911690602081600481855afa9081156103ab5783916103b6575b506001600160a01b0316158015610346575b1561030b57600180546001600160a01b031916821790557fbaaa7754c80972a8023e248f07cf93b17e0d6660c86e8f990285e7c6b18b26d78280a280f35b60405162461bcd60e51b8152602060048201526013602482015272496e76616c6964206475656c20656e67696e6560681b6044820152606490fd5b506040516329eecf6760e01b8152602081600481855afa9081156103ab57839161037c575b506001600160a01b031630146102cd565b61039e915060203d6020116103a4575b61039681836127b1565b810190612884565b3861036b565b503d61038c565b6040513d85823e3d90fd5b6103cf915060203d6020116103a45761039681836127b1565b386102bb565b503461023857602036600319011261023857604090600435815260026020522080546104936001830154926002810154600382015460ff610469600485015494600681015495600982015494610439600a610432600586016129c2565b94016129c2565b966040519b8c9b8c5260208c015260408b015260608a0152608089015261014060a08901526101408801906126e9565b93818116151560c088015260081c16151560e08601526101008501528382036101208501526126e9565b0390f35b5034610238576020366003190112610238576104b1612d5a565b60043581526002602052604081206104d260ff600683015460081c16612b33565b600381015462278d00810180911161056757421115610536578180806009819401818154915560018060a01b03600080516020613085833981519152541682821561052d575bf1156105215780f35b604051903d90823e3d90fd5b506108fc610518565b60405162461bcd60e51b8152602060048201526009602482015268546f6f206561726c7960b81b6044820152606490fd5b634e487b7160e01b83526011600452602483fd5b50346102385780600319360112610238576020604051612a308152f35b50346102385760203660031901126102385760206105b7600435612be7565b6040519015158152f35b50346102385760403660031901126102385760043560243567ffffffffffffffff8111610863576105f6903690600401612853565b906105ff612d5a565b8284526002602052604084206006810190815460ff81169081610854575b501561080f57600381015442106107d157600884036107945760078101865b858110610737575050600a0167ffffffffffffffff841161072357600160401b84116107235780548482558085106106fd575b5085526020852082865b8581106106e9575050815461ffff1916610100179091555060405160208082528101839052906001600160fb1b0383116106e557816040917fee83527b62fe7aef01444622c23519326ccc97dd899553547a1654ececd7af539460051b8091848401378101030190a280f35b8480fd5b600190602083359301928185015501610679565b818752846020882091820191015b818110610718575061066f565b87815560010161070b565b634e487b7160e01b86526041600452602486fd5b610742818787612bd7565b3588528160205260ff6040892054161561075e5760010161063c565b60405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b2103bb4b73732b960911b6044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081dda5b9b995c9cc818dbdd5b9d605a1b6044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275151bdd5c9b985b595b9d081b9bdd081cdd185c9d195960521b6044820152606490fd5b60405162461bcd60e51b815260206004820152601860248201527f496e76616c696420746f75726e616d656e7420737461746500000000000000006044820152606490fd5b60ff915060081c16153861061d565b8280fd5b5034610238578060031936011261023857602060405160028152f35b50346102385760203660031901126102385780546040516331a9108f60e11b81526004803590820181905292916001600160a01b031690602081602481855afa9081156103ab57906108e7918491610b3c575b506001600160a01b03163314612ae8565b828252600460205260ff604083205416610b0457602060249160405192838092630219207560e61b82528760048301525afa8015610af9578290610ac1575b6005915010610a8c57805b6005548110156109d95761094481612805565b90549060031b1c825260066020526040822054613840810180911161056757421015610979575b61097490612a2f565b610931565b61098281612805565b90549060031b1c61099281612c99565b7f0e3f44d41a1c5490673830be9c13e193fc8a37b0984a5b4b395cae879c1149188380a280156109c5576000190161096b565b634e487b7160e01b82526011600452602482fd5b5090808252600460205260408220600160ff19825416179055600554600160401b811015610a785781610a17826001610a309401600555600561283b565b90919082549060031b91821b91600019901b1916179055565b80825260066020524260408320557f166b7a3201bc44b7e364c65c111d350b06fccbd4c039a9a121be0097abfdea3d8280a260026005541015610a705780f35b610265612e78565b634e487b7160e01b83526041600452602483fd5b60405162461bcd60e51b815260206004820152600d60248201526c4c6576656c20746f6f206c6f7760981b6044820152606490fd5b506020813d602011610af1575b81610adb602093836127b1565b81010312610aec5760059051610926565b600080fd5b3d9150610ace565b6040513d84823e3d90fd5b60405162461bcd60e51b815260206004820152601060248201526f416c726561647920696e206172656e6160801b6044820152606490fd5b610b55915060203d6020116103a45761039681836127b1565b386108d6565b50346102385760403660031901126102385760086040610b7961279b565b926004358152600260205220019060018060a01b0316600052602052602060ff604060002054166040519015158152f35b50346102385760203660031901126102385760406020916004358152600683522054604051908152f35b503461023857602036600319011261023857610bee612d5a565b60043581526002602052600660408220018054610c1160ff8260081c1615612a3e565b60ff1916905580f35b50346102385780600319360112610238576040805191610c3a82846127b1565b60058352640352e302e360dc1b6020840152815192839160208352815191826020850152815b838110610c7d575050828201840152601f01601f19168101030190f35b602082820181015188830188015287955001610c60565b5034610238578060031936011261023857546040516001600160a01b039091168152602090f35b5034610238578060031936011261023857600080516020613085833981519152546040516001600160a01b039091168152602090f35b503461023857610d00366126d3565b91600854831015610d4257602092610d2c600960408461271096610d3996526002885220015491612820565b90549060031b1c90612b20565b04604051908152f35b60405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b2103837b9b4ba34b7b760811b6044820152606490fd5b5034610238576024610d8b366126d3565b83546040516331a9108f60e11b815260048101849052929360209184919082906001600160a01b03165afa918215610f5c57610dee92610ddd918691610f3d575b506001600160a01b031633146128a3565b82845260076020526040842061271d565b5060038101805460ff811680610f2e575b610e08906128e4565b6002830154612a308101809111610f1a57610e2590421115612947565b600260048401610e358154612a2f565b80915511600014610ee75750600154825485916001600160a01b031690813b156108635782916044839260405194859384926371c63cbf60e11b845260048401528a60248401525af18015610af957610ece575b5050610e958254612c99565b610e9e83612c99565b805460ff19169055547f0e3e71918165b205241b092b9121bb9b847e17f66b161239b21639fa61237ed98380a380f35b81610ed8916127b1565b610ee3578338610e89565b8380fd5b61ff001916610100179055547faeb2ade5648b71fe2d5c04434ea112c889919a48565e956b59adbabd83b38f608380a380f35b634e487b7160e01b86526011600452602486fd5b50600881901c60ff1615610dff565b610f56915060203d6020116103a45761039681836127b1565b38610dcc565b6040513d86823e3d90fd5b503461023857610f76366126d3565b82546040516331a9108f60e11b81526004810184905292939290602090829060249082906001600160a01b03165afa9081156103ab578391611199575b50336001600160a01b039091160361115d57828252600460205260ff60408320541680611147575b610fe490612987565b80831461110a576040519260c0840184811067ffffffffffffffff8211176110f657604052808452602084018281526040850142815260608601600181526080870186815260a0880192878452868852600760205260408820805490600160401b8210156110e2579061105c9160018201815561271d565b9590956110ce5760049596979899518755516001870155516002860155600385019151151560ff8019845416911617825551151561ff0082549160081b169061ff001916179055519101557fcfb443608da4b48dec5b2503a2fee6cf8abbbb068c89aaf0d55c489c6897b4e58380a380f35b634e487b7160e01b89526004899052602489fd5b634e487b7160e01b8a52604160045260248afd5b634e487b7160e01b84526041600452602484fd5b60405162461bcd60e51b815260206004820152601560248201527421b0b73737ba1031b430b63632b733b29039b2b63360591b6044820152606490fd5b508082526004602052604082205460ff16610fdb565b60405162461bcd60e51b81526020600482015260146024820152732737ba1031b430b63632b733b2b91037bbb732b960611b6044820152606490fd5b6111b2915060203d6020116103a45761039681836127b1565b38610fb3565b503461023857602036600319011261023857604061010091600435815260026020522080549060ff6001820154916002810154600382015460048301549160096006850154940154956040519788526020880152604087015260608601526080850152818116151560a085015260081c16151560c083015260e0820152f35b50346102385780600319360112610238576020600354604051908152f35b503461023857806003193601126102385761126e612d5a565b60008051602061308583398151915280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346102385760203660031901126102385760043567ffffffffffffffff8111611455576112f1903690600401612853565b906112fa612d5a565b82805b838210611435576127109150036113f057600882036113a15767ffffffffffffffff8211610a7857600160401b8211610a78576008548260085580831061136f575b50825b82811061134d578380f35b60019060208335930192816000805160206130c5833981519152015501611342565b600884526000805160206130c58339815191529081019083015b818110611396575061133f565b848155600101611389565b60405162461bcd60e51b815260206004820152602160248201527f496e76616c6964206e756d626572206f66207072697a6520706f736974696f6e6044820152607360f81b6064820152608490fd5b60405162461bcd60e51b815260206004820152601a60248201527f496e76616c6964207072697a6520646973747269627574696f6e0000000000006044820152606490fd5b61144d600191611446848787612bd7565b3590612924565b9101906112fd565b5080fd5b5034610238576020366003190112610238576020611478600435612b7f565b604051908152f35b50346102385760203660031901126102385760043561149d612d90565b808252600260205260408220906114bd60ff600684015460081c16612b33565b600882019160018060a01b0333166000528260205260ff604060002054166115c9576114ec33600a8301612dcc565b906008548210156115905761271091610d2c600961150c93015491612820565b049160018060a01b0333166000526020526040600020600160ff198254161790558280838015611586575b8280929181923390f115610af9576040519182527f1507bcd8039f159f75ccfac8f653ba14b24f79bfebb0d3c4b948432f1bc9443460203393a360016000805160206130e58339815191525580f35b6108fc9150611537565b60405162461bcd60e51b81526020600482015260116024820152704e6f207072697a6520746f20636c61696d60781b6044820152606490fd5b60405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606490fd5b50346102385760ff6040602092611616366126d3565b9082526002855260078383200190825284522054166040519015158152f35b5061163f366126d3565b90611648612d90565b808352600260205260408320600681015460ff8116908161199e575b501561196157600381015442101561191c57805434106118de57600781018385528060205260ff6040862054166118a857600582018054600484015411156118715785546040516331a9108f60e11b815260048101879052906001600160a01b0316602082602481845afa908115611866576116f66020926024948b9161184f57506001600160a01b03163314612ae8565b6040519283809263186e325160e11b82528a60048301525afa908115611844578791611812575b5060018401548110159081611803575b50156117cb57805490600160401b8210156117b757610a1782879260016117569501815561283b565b83855260205260408420600160ff1982541617905561177c600982549201918254612924565b90557fef32d94f53347b0be2b796f934a5e70b7ad9006fc563f43c2ea81871284698bf8380a360016000805160206130e58339815191525580f35b634e487b7160e01b87526041600452602487fd5b60405162461bcd60e51b815260206004820152601060248201526f455053206f7574206f662072616e676560801b6044820152606490fd5b9050600284015410153861172d565b90506020813d60201161183c575b8161182d602093836127b1565b81010312610aec57513861171d565b3d9150611820565b6040513d89823e3d90fd5b610b559150843d86116103a45761039681836127b1565b6040513d8a823e3d90fd5b60405162461bcd60e51b815260206004820152600f60248201526e151bdd5c9b985b595b9d08199d5b1b608a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d105b1c9958591e481a9bda5b995960921b6044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420656e7472792066656560501b6044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f546f75726e616d656e7420616c726561647920737461727465640000000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274546f75726e616d656e74206e6f742061637469766560581b6044820152606490fd5b60ff915060081c161538611664565b503461023857806003193601126102385760206040516138408152f35b50346102385780600319360112610238577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003611a235760206040516000805160206130a58339815191528152f35b63703e46dd60e11b8152600490fd5b5034610238576020366003190112610238576004359060055482101561023857602061022983612805565b50604036600319011261023857611a72612785565b6024359067ffffffffffffffff821161086357366023830112156108635781600401359083611aa0836127e9565b93611aae60405195866127b1565b8385526020850193366024828401011161086357806024602093018637850101526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016308114908115611c8b575b50611c7c57611b11612d5a565b6040516352d1902d60e01b81526001600160a01b0382169390602081600481885afa869181611c44575b50611b5457634c9c8ce360e01b86526004859052602486fd5b93846000805160206130a5833981519152879603611c325750823b15611c20576000805160206130a583398151915280546001600160a01b031916821790558491907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2805115611c0557611bf99382915190845af43d15611bfd573d91611bdd836127e9565b92611beb60405194856127b1565b83523d85602085013e613023565b5080f35b606091613023565b5050505034611c115780f35b63b398979f60e01b8152600490fd5b634c9c8ce360e01b8552600452602484fd5b632a87526960e21b8652600452602485fd5b9091506020813d602011611c74575b81611c60602093836127b1565b81010312611c7057519038611b3b565b8680fd5b3d9150611c53565b63703e46dd60e11b8452600484fd5b6000805160206130a5833981519152546001600160a01b03161415905038611b04565b50346102385780600319360112610238576001546040516001600160a01b039091168152602090f35b5034610238578060031936011261023857602060405160058152f35b503461023857604036600319011261023857611d0d612785565b611d1561279b565b600080516020613105833981519152549160ff8360401c16159267ffffffffffffffff81168015908161203b575b6001149081612031575b159081612028575b506120195767ffffffffffffffff1981166001176000805160206131058339815191525583611fec575b50611d88612ff5565b611d90612ff5565b611d9933612c23565b611da1612ff5565b611da9612ff5565b60016000805160206130e583398151915255611dc3612ff5565b6001600160a01b0316908115611fa7576001600160a01b0316908115611f62576bffffffffffffffffffffffff60a01b8454161783556bffffffffffffffffffffffff60a01b6001541617600155604051610100810181811067ffffffffffffffff8211176110f65760405261119481526107d060208201526103e860408201526101f460608201526101f460808201526101f460a08201526101f460c08201526101f460e08201526008546008805580600810611f14575b5060088352825b60088110611eee575050611e945780f35b68ff0000000000000000196000805160206131058339815191525416600080516020613105833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b600190602061ffff845116930192816000805160206130c5833981519152015501611e83565b600884526000805160206130c5833981519152017ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636eeb5b818110611f575750611e7c565b848155600101611f4a565b60405162461bcd60e51b815260206004820152601a60248201527f496e76616c6964204475656c456e67696e6520616464726573730000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f496e76616c69642043686962626c6520616464726573730000000000000000006044820152606490fd5b68ffffffffffffffffff191668010000000000000001176000805160206131058339815191525538611d7f565b63f92ee8a960e01b8552600485fd5b90501538611d55565b303b159150611d4d565b859150611d43565b50346102385760203660031901126102385780546040516331a9108f60e11b81526004803590820181905291602090829060249082906001600160a01b03165afa80156103ab576120a5918491610b3c57506001600160a01b03163314612ae8565b80825260046020526120bd60ff604084205416612987565b6120c681612c99565b7f0e3f44d41a1c5490673830be9c13e193fc8a37b0984a5b4b395cae879c1149188280a280f35b50346102385760203660031901126102385760043581526007602052604081209081549061211a82612aa2565b9161212481612aa2565b61212d82612aa2565b9161213781612aa2565b9561214182612aa2565b945b8281106121aa57612172876104938861219c8c61218e8b6121808c604051998a9960a08b5260a08b01906126e9565b9089820360208b01526126e9565b90878203604089015261274f565b90858203606087015261274f565b9083820360808501526126e9565b806121b76001928461271d565b50546121c3828a612ad4565b5260026121d0828561271d565b5001546121dd8287612ad4565b5260ff60036121ec838661271d565b500154166121fa8288612ad4565b901515905260ff600361220d838661271d565b50015460081c1661221e828b612ad4565b9015159052600461222f828561271d565b50015461223c8289612ad4565b5201612143565b50346102385760203660031901126102385760ff60406020926004358152600484522054166040519015158152f35b50346102385760203660031901126102385761228c612d5a565b6004358152600260205260066040822001600181546122b160ff8260081c1615612a3e565b60ff191617905580f35b5034610238576122ca366126d3565b919081526007602052604081209081548310156102385760c06122ed848461271d565b5080549060ff60018201549160028101546004600383015492015493604051958652602086015260408501528181161515606085015260081c161515608083015260a0820152f35b50346102385760203660031901126102385760406020916004358152600783522054604051908152f35b50346102385760a036600319011261023857608435602435606435600435604435612388612d5a565b428311156124b157841515806124a6575b156124615760808511612424577f2ab53a33686f9d42069c5153cbe91fbf11f24ef392adc3048d7189e8878af0f3936006606094600354976123da89612a2f565b600355888a52600260205260408a20918683558460018401558560028401556003830155600482015501600161ffff1982541617905560405192835260208301526040820152a280f35b60405162461bcd60e51b8152602060048201526015602482015274546f6f206d616e79207061727469636970616e747360581b6044820152606490fd5b60405162461bcd60e51b815260206004820152601960248201527f496e76616c6964207061727469636970616e7420636f756e74000000000000006044820152606490fd5b506001851615612399565b60405162461bcd60e51b8152602060048201526012602482015271496e76616c69642073746172742074696d6560701b6044820152606490fd5b503461023857806003193601126102385760405160058054808352908352909160208301917f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0915b81811061255e576104938561254a818703826127b1565b6040519182916020835260208301906126e9565b8254845260209093019260019283019201612533565b90503461145557612584366126d3565b83546331a9108f60e11b845260048401839052919291602090839060249082906001600160a01b03165afa918215610f5c576125d592610ddd918691610f3d57506001600160a01b031633146128a3565b50600381016125f0815460ff811690816126c4575b506128e4565b6002820154612a3081018091116126b05761260d90421115612947565b838254808252600460205260ff6040832054168061269a575b61262f90612987565b6001546001600160a01b0316803b15610863576044839260405194859384926371c63cbf60e11b845260048401528960248401525af1801561268f5761267b575b50610e958254612c99565b84612688919592956127b1565b9238612670565b6040513d87823e3d90fd5b508482526004602052604082205460ff16612626565b634e487b7160e01b85526011600452602485fd5b60ff915060081c1615386125ea565b6040906003190112610aec576004359060243590565b906020808351928381520192019060005b8181106127075750505090565b82518452602093840193909201916001016126fa565b8054821015612739576000526005602060002091020190600090565b634e487b7160e01b600052603260045260246000fd5b906020808351928381520192019060005b81811061276d5750505090565b82511515845260209384019390920191600101612760565b600435906001600160a01b0382168203610aec57565b602435906001600160a01b0382168203610aec57565b90601f8019910116810190811067ffffffffffffffff8211176127d357604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff81116127d357601f01601f191660200190565b60055481101561273957600560005260206000200190600090565b60085481101561273957600860005260206000200190600090565b80548210156127395760005260206000200190600090565b9181601f84011215610aec5782359167ffffffffffffffff8311610aec576020808501948460051b010111610aec57565b90816020910312610aec57516001600160a01b0381168103610aec5790565b156128aa57565b60405162461bcd60e51b81526020600482015260126024820152712737ba103232b332b73232b91037bbb732b960711b6044820152606490fd5b156128eb57565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964206368616c6c656e676560781b6044820152606490fd5b9190820180921161293157565b634e487b7160e01b600052601160045260246000fd5b1561294e57565b60405162461bcd60e51b815260206004820152601160248201527010da185b1b195b99d948195e1c1a5c9959607a1b6044820152606490fd5b1561298e57565b60405162461bcd60e51b815260206004820152600c60248201526b4e6f7420696e206172656e6160a01b6044820152606490fd5b906040519182815491828252602082019060005260206000209260005b8181106129f65750506129f4925003836127b1565b565b84548352600194850194879450602090930192016129df565b8115612a19570690565b634e487b7160e01b600052601260045260246000fd5b60001981146129315760010190565b15612a4557565b60405162461bcd60e51b815260206004820152601b60248201527f546f75726e616d656e7420616c72656164792066696e697368656400000000006044820152606490fd5b67ffffffffffffffff81116127d35760051b60200190565b90612aac82612a8a565b612ab960405191826127b1565b8281528092612aca601f1991612a8a565b0190602036910137565b80518210156127395760209160051b010190565b15612aef57565b60405162461bcd60e51b81526020600482015260096024820152682737ba1037bbb732b960b91b6044820152606490fd5b8181029291811591840414171561293157565b15612b3a57565b60405162461bcd60e51b815260206004820152601760248201527f546f75726e616d656e74206e6f742066696e69736865640000000000000000006044820152606490fd5b80600052600460205260ff6040600020541615612bd15760005260066020526040600020546138408101908181116129315781421015612bca57429003613840019081116129315790565b5050600090565b50600090565b91908110156127395760051b0190565b6005549060005b828110612bfd57505050600090565b81612c0782612805565b90549060031b1c14612c1b57600101612bee565b505050600190565b6001600160a01b03168015612c835760008051602061308583398151915280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b806000526004602052604060002060ff1981541690558060005260066020526000604081205560005b60055480821015612d555782612cd783612805565b90549060031b1c14612cec5750600101612cc2565b60001981019250821161293157610a17612d08612d1593612805565b90549060031b1c91612805565b6005548015612d3f5760001901612d2b81612805565b8154906000199060031b1b19169055600555565b634e487b7160e01b600052603160045260246000fd5b505050565b600080516020613085833981519152546001600160a01b03163303612d7b57565b63118cdaa760e01b6000523360045260246000fd5b60026000805160206130e58339815191525414612dbb5760026000805160206130e583398151915255565b633ee5aeb560e01b60005260046000fd5b9060009060018060a01b03825416915b8354811015612e6e57612def818561283b565b90546040516331a9108f60e11b815260039290921b1c6004820152602081602481875afa908115612e6257600091612e44575b506001600160a01b03838116911614612e3d57600101612ddc565b9250505090565b612e5c915060203d81116103a45761039681836127b1565b38612e22565b6040513d6000823e3d90fd5b5050505060001990565b6001546001600160a01b031660008115612fba576005549160028310612d5557612ec483604051602081019044825242604082015260408152612ebc6060826127b1565b519020612a0f565b8260015b15612f0b575b508290612f04856040516020810190448252426040820152651cd958dbdb9960d21b606082015260468152612ebc6066826127b1565b9091612ec8565b808214612ece5792919350612f22612f2f91612805565b90549060031b1c92612805565b90549060031b1c92803b15611455578180916044604051809481936371c63cbf60e11b83528860048401528960248401525af18015610af95790827f6cf12ff3e180c4019f4109de045a6fc7eb3a37155c8fbeb0da3b2768fc35f7a29392612faa575b5050612f9d83612c99565b612fa684612c99565b80a3565b612fb3916127b1565b3881612f92565b60405162461bcd60e51b8152602060048201526013602482015272111d595b08195b99da5b99481b9bdd081cd95d606a1b6044820152606490fd5b60ff6000805160206131058339815191525460401c161561301257565b631afcd79f60e31b60005260046000fd5b90613049575080511561303857805190602001fd5b63d6bda27560e01b60005260046000fd5b8151158061307b575b61305a575090565b639996b31560e01b60009081526001600160a01b0391909116600452602490fd5b50803b1561305256fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee39b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a26469706673582212200484ce16c9891f2e6ae2abdf51df4ce990d051290648b3405fe18855148d8e7864736f6c634300081c0033
Deployed Bytecode
0x608080604052600436101561001d575b50361561001b57600080fd5b005b600090813560e01c908163131178ac146125745750806318690466146124eb5780632f8cbdb71461235f578063314f3c44146123355780633a7b06bb146122bb5780633b97f893146122725780633e85cd741461224357806340e97393146120ed57806346feb24a14612043578063485cc95514611cf357806348a6a54e14611cd75780634afe5e7714611cae5780634f1ef28614611a5d57806351ae40e814611a3257806352d1902d146119ca578063571d7c6d146119ad5780635875c61c1461163557806368ebd69714611600578063694dead1146114805780636e4bc6d3146114595780636f7d1a9e146112bf578063715018a61461125557806373ed5c1c146112375780637503e1b7146111b85780637759cbc014610f675780637b092e8714610d7a57806386bc4e9314610cf15780638da5cb5b14610cbb5780639ec3529814610c94578063ad3cb1cc14610c1a578063ad3fbe3014610bd4578063c305fc6c14610baa578063c8b727a114610b5b578063c91cdee214610883578063ce0da4d814610867578063d83d3d1b146105c1578063d959eebe14610598578063e12fc1d71461057b578063e6634c6714610497578063e96d5c0f146103d5578063eb6dcd4014610268578063f2fde38b1461023b5763f4fcbfe00361000f5734610238576020366003190112610238576004359060085482101561023857602061022983612820565b90549060031b1c604051908152f35b80fd5b503461023857602036600319011261023857610265610258612785565b610260612d5a565b612c23565b80f35b503461023857602036600319011261023857610282612785565b61028a612d5a565b6040516329eecf6760e01b81526001600160a01b039190911690602081600481855afa9081156103ab5783916103b6575b506001600160a01b0316158015610346575b1561030b57600180546001600160a01b031916821790557fbaaa7754c80972a8023e248f07cf93b17e0d6660c86e8f990285e7c6b18b26d78280a280f35b60405162461bcd60e51b8152602060048201526013602482015272496e76616c6964206475656c20656e67696e6560681b6044820152606490fd5b506040516329eecf6760e01b8152602081600481855afa9081156103ab57839161037c575b506001600160a01b031630146102cd565b61039e915060203d6020116103a4575b61039681836127b1565b810190612884565b3861036b565b503d61038c565b6040513d85823e3d90fd5b6103cf915060203d6020116103a45761039681836127b1565b386102bb565b503461023857602036600319011261023857604090600435815260026020522080546104936001830154926002810154600382015460ff610469600485015494600681015495600982015494610439600a610432600586016129c2565b94016129c2565b966040519b8c9b8c5260208c015260408b015260608a0152608089015261014060a08901526101408801906126e9565b93818116151560c088015260081c16151560e08601526101008501528382036101208501526126e9565b0390f35b5034610238576020366003190112610238576104b1612d5a565b60043581526002602052604081206104d260ff600683015460081c16612b33565b600381015462278d00810180911161056757421115610536578180806009819401818154915560018060a01b03600080516020613085833981519152541682821561052d575bf1156105215780f35b604051903d90823e3d90fd5b506108fc610518565b60405162461bcd60e51b8152602060048201526009602482015268546f6f206561726c7960b81b6044820152606490fd5b634e487b7160e01b83526011600452602483fd5b50346102385780600319360112610238576020604051612a308152f35b50346102385760203660031901126102385760206105b7600435612be7565b6040519015158152f35b50346102385760403660031901126102385760043560243567ffffffffffffffff8111610863576105f6903690600401612853565b906105ff612d5a565b8284526002602052604084206006810190815460ff81169081610854575b501561080f57600381015442106107d157600884036107945760078101865b858110610737575050600a0167ffffffffffffffff841161072357600160401b84116107235780548482558085106106fd575b5085526020852082865b8581106106e9575050815461ffff1916610100179091555060405160208082528101839052906001600160fb1b0383116106e557816040917fee83527b62fe7aef01444622c23519326ccc97dd899553547a1654ececd7af539460051b8091848401378101030190a280f35b8480fd5b600190602083359301928185015501610679565b818752846020882091820191015b818110610718575061066f565b87815560010161070b565b634e487b7160e01b86526041600452602486fd5b610742818787612bd7565b3588528160205260ff6040892054161561075e5760010161063c565b60405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b2103bb4b73732b960911b6044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081dda5b9b995c9cc818dbdd5b9d605a1b6044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275151bdd5c9b985b595b9d081b9bdd081cdd185c9d195960521b6044820152606490fd5b60405162461bcd60e51b815260206004820152601860248201527f496e76616c696420746f75726e616d656e7420737461746500000000000000006044820152606490fd5b60ff915060081c16153861061d565b8280fd5b5034610238578060031936011261023857602060405160028152f35b50346102385760203660031901126102385780546040516331a9108f60e11b81526004803590820181905292916001600160a01b031690602081602481855afa9081156103ab57906108e7918491610b3c575b506001600160a01b03163314612ae8565b828252600460205260ff604083205416610b0457602060249160405192838092630219207560e61b82528760048301525afa8015610af9578290610ac1575b6005915010610a8c57805b6005548110156109d95761094481612805565b90549060031b1c825260066020526040822054613840810180911161056757421015610979575b61097490612a2f565b610931565b61098281612805565b90549060031b1c61099281612c99565b7f0e3f44d41a1c5490673830be9c13e193fc8a37b0984a5b4b395cae879c1149188380a280156109c5576000190161096b565b634e487b7160e01b82526011600452602482fd5b5090808252600460205260408220600160ff19825416179055600554600160401b811015610a785781610a17826001610a309401600555600561283b565b90919082549060031b91821b91600019901b1916179055565b80825260066020524260408320557f166b7a3201bc44b7e364c65c111d350b06fccbd4c039a9a121be0097abfdea3d8280a260026005541015610a705780f35b610265612e78565b634e487b7160e01b83526041600452602483fd5b60405162461bcd60e51b815260206004820152600d60248201526c4c6576656c20746f6f206c6f7760981b6044820152606490fd5b506020813d602011610af1575b81610adb602093836127b1565b81010312610aec5760059051610926565b600080fd5b3d9150610ace565b6040513d84823e3d90fd5b60405162461bcd60e51b815260206004820152601060248201526f416c726561647920696e206172656e6160801b6044820152606490fd5b610b55915060203d6020116103a45761039681836127b1565b386108d6565b50346102385760403660031901126102385760086040610b7961279b565b926004358152600260205220019060018060a01b0316600052602052602060ff604060002054166040519015158152f35b50346102385760203660031901126102385760406020916004358152600683522054604051908152f35b503461023857602036600319011261023857610bee612d5a565b60043581526002602052600660408220018054610c1160ff8260081c1615612a3e565b60ff1916905580f35b50346102385780600319360112610238576040805191610c3a82846127b1565b60058352640352e302e360dc1b6020840152815192839160208352815191826020850152815b838110610c7d575050828201840152601f01601f19168101030190f35b602082820181015188830188015287955001610c60565b5034610238578060031936011261023857546040516001600160a01b039091168152602090f35b5034610238578060031936011261023857600080516020613085833981519152546040516001600160a01b039091168152602090f35b503461023857610d00366126d3565b91600854831015610d4257602092610d2c600960408461271096610d3996526002885220015491612820565b90549060031b1c90612b20565b04604051908152f35b60405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b2103837b9b4ba34b7b760811b6044820152606490fd5b5034610238576024610d8b366126d3565b83546040516331a9108f60e11b815260048101849052929360209184919082906001600160a01b03165afa918215610f5c57610dee92610ddd918691610f3d575b506001600160a01b031633146128a3565b82845260076020526040842061271d565b5060038101805460ff811680610f2e575b610e08906128e4565b6002830154612a308101809111610f1a57610e2590421115612947565b600260048401610e358154612a2f565b80915511600014610ee75750600154825485916001600160a01b031690813b156108635782916044839260405194859384926371c63cbf60e11b845260048401528a60248401525af18015610af957610ece575b5050610e958254612c99565b610e9e83612c99565b805460ff19169055547f0e3e71918165b205241b092b9121bb9b847e17f66b161239b21639fa61237ed98380a380f35b81610ed8916127b1565b610ee3578338610e89565b8380fd5b61ff001916610100179055547faeb2ade5648b71fe2d5c04434ea112c889919a48565e956b59adbabd83b38f608380a380f35b634e487b7160e01b86526011600452602486fd5b50600881901c60ff1615610dff565b610f56915060203d6020116103a45761039681836127b1565b38610dcc565b6040513d86823e3d90fd5b503461023857610f76366126d3565b82546040516331a9108f60e11b81526004810184905292939290602090829060249082906001600160a01b03165afa9081156103ab578391611199575b50336001600160a01b039091160361115d57828252600460205260ff60408320541680611147575b610fe490612987565b80831461110a576040519260c0840184811067ffffffffffffffff8211176110f657604052808452602084018281526040850142815260608601600181526080870186815260a0880192878452868852600760205260408820805490600160401b8210156110e2579061105c9160018201815561271d565b9590956110ce5760049596979899518755516001870155516002860155600385019151151560ff8019845416911617825551151561ff0082549160081b169061ff001916179055519101557fcfb443608da4b48dec5b2503a2fee6cf8abbbb068c89aaf0d55c489c6897b4e58380a380f35b634e487b7160e01b89526004899052602489fd5b634e487b7160e01b8a52604160045260248afd5b634e487b7160e01b84526041600452602484fd5b60405162461bcd60e51b815260206004820152601560248201527421b0b73737ba1031b430b63632b733b29039b2b63360591b6044820152606490fd5b508082526004602052604082205460ff16610fdb565b60405162461bcd60e51b81526020600482015260146024820152732737ba1031b430b63632b733b2b91037bbb732b960611b6044820152606490fd5b6111b2915060203d6020116103a45761039681836127b1565b38610fb3565b503461023857602036600319011261023857604061010091600435815260026020522080549060ff6001820154916002810154600382015460048301549160096006850154940154956040519788526020880152604087015260608601526080850152818116151560a085015260081c16151560c083015260e0820152f35b50346102385780600319360112610238576020600354604051908152f35b503461023857806003193601126102385761126e612d5a565b60008051602061308583398151915280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346102385760203660031901126102385760043567ffffffffffffffff8111611455576112f1903690600401612853565b906112fa612d5a565b82805b838210611435576127109150036113f057600882036113a15767ffffffffffffffff8211610a7857600160401b8211610a78576008548260085580831061136f575b50825b82811061134d578380f35b60019060208335930192816000805160206130c5833981519152015501611342565b600884526000805160206130c58339815191529081019083015b818110611396575061133f565b848155600101611389565b60405162461bcd60e51b815260206004820152602160248201527f496e76616c6964206e756d626572206f66207072697a6520706f736974696f6e6044820152607360f81b6064820152608490fd5b60405162461bcd60e51b815260206004820152601a60248201527f496e76616c6964207072697a6520646973747269627574696f6e0000000000006044820152606490fd5b61144d600191611446848787612bd7565b3590612924565b9101906112fd565b5080fd5b5034610238576020366003190112610238576020611478600435612b7f565b604051908152f35b50346102385760203660031901126102385760043561149d612d90565b808252600260205260408220906114bd60ff600684015460081c16612b33565b600882019160018060a01b0333166000528260205260ff604060002054166115c9576114ec33600a8301612dcc565b906008548210156115905761271091610d2c600961150c93015491612820565b049160018060a01b0333166000526020526040600020600160ff198254161790558280838015611586575b8280929181923390f115610af9576040519182527f1507bcd8039f159f75ccfac8f653ba14b24f79bfebb0d3c4b948432f1bc9443460203393a360016000805160206130e58339815191525580f35b6108fc9150611537565b60405162461bcd60e51b81526020600482015260116024820152704e6f207072697a6520746f20636c61696d60781b6044820152606490fd5b60405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b6044820152606490fd5b50346102385760ff6040602092611616366126d3565b9082526002855260078383200190825284522054166040519015158152f35b5061163f366126d3565b90611648612d90565b808352600260205260408320600681015460ff8116908161199e575b501561196157600381015442101561191c57805434106118de57600781018385528060205260ff6040862054166118a857600582018054600484015411156118715785546040516331a9108f60e11b815260048101879052906001600160a01b0316602082602481845afa908115611866576116f66020926024948b9161184f57506001600160a01b03163314612ae8565b6040519283809263186e325160e11b82528a60048301525afa908115611844578791611812575b5060018401548110159081611803575b50156117cb57805490600160401b8210156117b757610a1782879260016117569501815561283b565b83855260205260408420600160ff1982541617905561177c600982549201918254612924565b90557fef32d94f53347b0be2b796f934a5e70b7ad9006fc563f43c2ea81871284698bf8380a360016000805160206130e58339815191525580f35b634e487b7160e01b87526041600452602487fd5b60405162461bcd60e51b815260206004820152601060248201526f455053206f7574206f662072616e676560801b6044820152606490fd5b9050600284015410153861172d565b90506020813d60201161183c575b8161182d602093836127b1565b81010312610aec57513861171d565b3d9150611820565b6040513d89823e3d90fd5b610b559150843d86116103a45761039681836127b1565b6040513d8a823e3d90fd5b60405162461bcd60e51b815260206004820152600f60248201526e151bdd5c9b985b595b9d08199d5b1b608a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d105b1c9958591e481a9bda5b995960921b6044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420656e7472792066656560501b6044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f546f75726e616d656e7420616c726561647920737461727465640000000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274546f75726e616d656e74206e6f742061637469766560581b6044820152606490fd5b60ff915060081c161538611664565b503461023857806003193601126102385760206040516138408152f35b50346102385780600319360112610238577f0000000000000000000000006e75eb2eae14a32207be8a4c7ffc19ea127922816001600160a01b03163003611a235760206040516000805160206130a58339815191528152f35b63703e46dd60e11b8152600490fd5b5034610238576020366003190112610238576004359060055482101561023857602061022983612805565b50604036600319011261023857611a72612785565b6024359067ffffffffffffffff821161086357366023830112156108635781600401359083611aa0836127e9565b93611aae60405195866127b1565b8385526020850193366024828401011161086357806024602093018637850101526001600160a01b037f0000000000000000000000006e75eb2eae14a32207be8a4c7ffc19ea1279228116308114908115611c8b575b50611c7c57611b11612d5a565b6040516352d1902d60e01b81526001600160a01b0382169390602081600481885afa869181611c44575b50611b5457634c9c8ce360e01b86526004859052602486fd5b93846000805160206130a5833981519152879603611c325750823b15611c20576000805160206130a583398151915280546001600160a01b031916821790558491907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2805115611c0557611bf99382915190845af43d15611bfd573d91611bdd836127e9565b92611beb60405194856127b1565b83523d85602085013e613023565b5080f35b606091613023565b5050505034611c115780f35b63b398979f60e01b8152600490fd5b634c9c8ce360e01b8552600452602484fd5b632a87526960e21b8652600452602485fd5b9091506020813d602011611c74575b81611c60602093836127b1565b81010312611c7057519038611b3b565b8680fd5b3d9150611c53565b63703e46dd60e11b8452600484fd5b6000805160206130a5833981519152546001600160a01b03161415905038611b04565b50346102385780600319360112610238576001546040516001600160a01b039091168152602090f35b5034610238578060031936011261023857602060405160058152f35b503461023857604036600319011261023857611d0d612785565b611d1561279b565b600080516020613105833981519152549160ff8360401c16159267ffffffffffffffff81168015908161203b575b6001149081612031575b159081612028575b506120195767ffffffffffffffff1981166001176000805160206131058339815191525583611fec575b50611d88612ff5565b611d90612ff5565b611d9933612c23565b611da1612ff5565b611da9612ff5565b60016000805160206130e583398151915255611dc3612ff5565b6001600160a01b0316908115611fa7576001600160a01b0316908115611f62576bffffffffffffffffffffffff60a01b8454161783556bffffffffffffffffffffffff60a01b6001541617600155604051610100810181811067ffffffffffffffff8211176110f65760405261119481526107d060208201526103e860408201526101f460608201526101f460808201526101f460a08201526101f460c08201526101f460e08201526008546008805580600810611f14575b5060088352825b60088110611eee575050611e945780f35b68ff0000000000000000196000805160206131058339815191525416600080516020613105833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b600190602061ffff845116930192816000805160206130c5833981519152015501611e83565b600884526000805160206130c5833981519152017ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636eeb5b818110611f575750611e7c565b848155600101611f4a565b60405162461bcd60e51b815260206004820152601a60248201527f496e76616c6964204475656c456e67696e6520616464726573730000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f496e76616c69642043686962626c6520616464726573730000000000000000006044820152606490fd5b68ffffffffffffffffff191668010000000000000001176000805160206131058339815191525538611d7f565b63f92ee8a960e01b8552600485fd5b90501538611d55565b303b159150611d4d565b859150611d43565b50346102385760203660031901126102385780546040516331a9108f60e11b81526004803590820181905291602090829060249082906001600160a01b03165afa80156103ab576120a5918491610b3c57506001600160a01b03163314612ae8565b80825260046020526120bd60ff604084205416612987565b6120c681612c99565b7f0e3f44d41a1c5490673830be9c13e193fc8a37b0984a5b4b395cae879c1149188280a280f35b50346102385760203660031901126102385760043581526007602052604081209081549061211a82612aa2565b9161212481612aa2565b61212d82612aa2565b9161213781612aa2565b9561214182612aa2565b945b8281106121aa57612172876104938861219c8c61218e8b6121808c604051998a9960a08b5260a08b01906126e9565b9089820360208b01526126e9565b90878203604089015261274f565b90858203606087015261274f565b9083820360808501526126e9565b806121b76001928461271d565b50546121c3828a612ad4565b5260026121d0828561271d565b5001546121dd8287612ad4565b5260ff60036121ec838661271d565b500154166121fa8288612ad4565b901515905260ff600361220d838661271d565b50015460081c1661221e828b612ad4565b9015159052600461222f828561271d565b50015461223c8289612ad4565b5201612143565b50346102385760203660031901126102385760ff60406020926004358152600484522054166040519015158152f35b50346102385760203660031901126102385761228c612d5a565b6004358152600260205260066040822001600181546122b160ff8260081c1615612a3e565b60ff191617905580f35b5034610238576122ca366126d3565b919081526007602052604081209081548310156102385760c06122ed848461271d565b5080549060ff60018201549160028101546004600383015492015493604051958652602086015260408501528181161515606085015260081c161515608083015260a0820152f35b50346102385760203660031901126102385760406020916004358152600783522054604051908152f35b50346102385760a036600319011261023857608435602435606435600435604435612388612d5a565b428311156124b157841515806124a6575b156124615760808511612424577f2ab53a33686f9d42069c5153cbe91fbf11f24ef392adc3048d7189e8878af0f3936006606094600354976123da89612a2f565b600355888a52600260205260408a20918683558460018401558560028401556003830155600482015501600161ffff1982541617905560405192835260208301526040820152a280f35b60405162461bcd60e51b8152602060048201526015602482015274546f6f206d616e79207061727469636970616e747360581b6044820152606490fd5b60405162461bcd60e51b815260206004820152601960248201527f496e76616c6964207061727469636970616e7420636f756e74000000000000006044820152606490fd5b506001851615612399565b60405162461bcd60e51b8152602060048201526012602482015271496e76616c69642073746172742074696d6560701b6044820152606490fd5b503461023857806003193601126102385760405160058054808352908352909160208301917f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0915b81811061255e576104938561254a818703826127b1565b6040519182916020835260208301906126e9565b8254845260209093019260019283019201612533565b90503461145557612584366126d3565b83546331a9108f60e11b845260048401839052919291602090839060249082906001600160a01b03165afa918215610f5c576125d592610ddd918691610f3d57506001600160a01b031633146128a3565b50600381016125f0815460ff811690816126c4575b506128e4565b6002820154612a3081018091116126b05761260d90421115612947565b838254808252600460205260ff6040832054168061269a575b61262f90612987565b6001546001600160a01b0316803b15610863576044839260405194859384926371c63cbf60e11b845260048401528960248401525af1801561268f5761267b575b50610e958254612c99565b84612688919592956127b1565b9238612670565b6040513d87823e3d90fd5b508482526004602052604082205460ff16612626565b634e487b7160e01b85526011600452602485fd5b60ff915060081c1615386125ea565b6040906003190112610aec576004359060243590565b906020808351928381520192019060005b8181106127075750505090565b82518452602093840193909201916001016126fa565b8054821015612739576000526005602060002091020190600090565b634e487b7160e01b600052603260045260246000fd5b906020808351928381520192019060005b81811061276d5750505090565b82511515845260209384019390920191600101612760565b600435906001600160a01b0382168203610aec57565b602435906001600160a01b0382168203610aec57565b90601f8019910116810190811067ffffffffffffffff8211176127d357604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff81116127d357601f01601f191660200190565b60055481101561273957600560005260206000200190600090565b60085481101561273957600860005260206000200190600090565b80548210156127395760005260206000200190600090565b9181601f84011215610aec5782359167ffffffffffffffff8311610aec576020808501948460051b010111610aec57565b90816020910312610aec57516001600160a01b0381168103610aec5790565b156128aa57565b60405162461bcd60e51b81526020600482015260126024820152712737ba103232b332b73232b91037bbb732b960711b6044820152606490fd5b156128eb57565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964206368616c6c656e676560781b6044820152606490fd5b9190820180921161293157565b634e487b7160e01b600052601160045260246000fd5b1561294e57565b60405162461bcd60e51b815260206004820152601160248201527010da185b1b195b99d948195e1c1a5c9959607a1b6044820152606490fd5b1561298e57565b60405162461bcd60e51b815260206004820152600c60248201526b4e6f7420696e206172656e6160a01b6044820152606490fd5b906040519182815491828252602082019060005260206000209260005b8181106129f65750506129f4925003836127b1565b565b84548352600194850194879450602090930192016129df565b8115612a19570690565b634e487b7160e01b600052601260045260246000fd5b60001981146129315760010190565b15612a4557565b60405162461bcd60e51b815260206004820152601b60248201527f546f75726e616d656e7420616c72656164792066696e697368656400000000006044820152606490fd5b67ffffffffffffffff81116127d35760051b60200190565b90612aac82612a8a565b612ab960405191826127b1565b8281528092612aca601f1991612a8a565b0190602036910137565b80518210156127395760209160051b010190565b15612aef57565b60405162461bcd60e51b81526020600482015260096024820152682737ba1037bbb732b960b91b6044820152606490fd5b8181029291811591840414171561293157565b15612b3a57565b60405162461bcd60e51b815260206004820152601760248201527f546f75726e616d656e74206e6f742066696e69736865640000000000000000006044820152606490fd5b80600052600460205260ff6040600020541615612bd15760005260066020526040600020546138408101908181116129315781421015612bca57429003613840019081116129315790565b5050600090565b50600090565b91908110156127395760051b0190565b6005549060005b828110612bfd57505050600090565b81612c0782612805565b90549060031b1c14612c1b57600101612bee565b505050600190565b6001600160a01b03168015612c835760008051602061308583398151915280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b631e4fbdf760e01b600052600060045260246000fd5b806000526004602052604060002060ff1981541690558060005260066020526000604081205560005b60055480821015612d555782612cd783612805565b90549060031b1c14612cec5750600101612cc2565b60001981019250821161293157610a17612d08612d1593612805565b90549060031b1c91612805565b6005548015612d3f5760001901612d2b81612805565b8154906000199060031b1b19169055600555565b634e487b7160e01b600052603160045260246000fd5b505050565b600080516020613085833981519152546001600160a01b03163303612d7b57565b63118cdaa760e01b6000523360045260246000fd5b60026000805160206130e58339815191525414612dbb5760026000805160206130e583398151915255565b633ee5aeb560e01b60005260046000fd5b9060009060018060a01b03825416915b8354811015612e6e57612def818561283b565b90546040516331a9108f60e11b815260039290921b1c6004820152602081602481875afa908115612e6257600091612e44575b506001600160a01b03838116911614612e3d57600101612ddc565b9250505090565b612e5c915060203d81116103a45761039681836127b1565b38612e22565b6040513d6000823e3d90fd5b5050505060001990565b6001546001600160a01b031660008115612fba576005549160028310612d5557612ec483604051602081019044825242604082015260408152612ebc6060826127b1565b519020612a0f565b8260015b15612f0b575b508290612f04856040516020810190448252426040820152651cd958dbdb9960d21b606082015260468152612ebc6066826127b1565b9091612ec8565b808214612ece5792919350612f22612f2f91612805565b90549060031b1c92612805565b90549060031b1c92803b15611455578180916044604051809481936371c63cbf60e11b83528860048401528960248401525af18015610af95790827f6cf12ff3e180c4019f4109de045a6fc7eb3a37155c8fbeb0da3b2768fc35f7a29392612faa575b5050612f9d83612c99565b612fa684612c99565b80a3565b612fb3916127b1565b3881612f92565b60405162461bcd60e51b8152602060048201526013602482015272111d595b08195b99da5b99481b9bdd081cd95d606a1b6044820152606490fd5b60ff6000805160206131058339815191525460401c161561301257565b631afcd79f60e31b60005260046000fd5b90613049575080511561303857805190602001fd5b63d6bda27560e01b60005260046000fd5b8151158061307b575b61305a575090565b639996b31560e01b60009081526001600160a01b0391909116600452602490fd5b50803b1561305256fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee39b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a26469706673582212200484ce16c9891f2e6ae2abdf51df4ce990d051290648b3405fe18855148d8e7864736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.