Overview
APE Balance
APE Value
Less Than $0.01 (@ $0.50/APE)More Info
Private Name Tags
ContractCreator
Latest 20 from a total of 20 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Roll Stats | 11447973 | 23 hrs ago | IN | 0 APE | 0.00526833 | ||||
Roll Stats | 11447972 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447972 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447972 | 23 hrs ago | IN | 0 APE | 0.00526833 | ||||
Roll Stats | 11447972 | 23 hrs ago | IN | 0 APE | 0.00526833 | ||||
Roll Stats | 11447971 | 23 hrs ago | IN | 0 APE | 0.00526833 | ||||
Roll Stats | 11447971 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447971 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447970 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447970 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447970 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447970 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447969 | 23 hrs ago | IN | 0 APE | 0.00526833 | ||||
Roll Stats | 11447969 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447969 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447968 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Roll Stats | 11447968 | 23 hrs ago | IN | 0 APE | 0.0035957 | ||||
Transfer | 11447968 | 23 hrs ago | IN | 0.33 APE | 0.00053556 | ||||
Set Contract Aut... | 11447968 | 23 hrs ago | IN | 0 APE | 0.00118185 | ||||
Set Contract Aut... | 11447967 | 23 hrs ago | IN | 0 APE | 0.00118155 |
Latest 17 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
11447973 | 23 hrs ago | 0.01830289 APE | ||||
11447972 | 23 hrs ago | 0.01830289 APE | ||||
11447972 | 23 hrs ago | 0.01830289 APE | ||||
11447972 | 23 hrs ago | 0.01830289 APE | ||||
11447972 | 23 hrs ago | 0.01830289 APE | ||||
11447971 | 23 hrs ago | 0.01830289 APE | ||||
11447971 | 23 hrs ago | 0.01830289 APE | ||||
11447971 | 23 hrs ago | 0.01830289 APE | ||||
11447970 | 23 hrs ago | 0.01830289 APE | ||||
11447970 | 23 hrs ago | 0.01830289 APE | ||||
11447970 | 23 hrs ago | 0.01830289 APE | ||||
11447970 | 23 hrs ago | 0.01830289 APE | ||||
11447969 | 23 hrs ago | 0.01830289 APE | ||||
11447969 | 23 hrs ago | 0.01830289 APE | ||||
11447969 | 23 hrs ago | 0.01830289 APE | ||||
11447968 | 23 hrs ago | 0.01830289 APE | ||||
11447968 | 23 hrs ago | 0.01830289 APE |
Loading...
Loading
This contract contains unverified libraries: StatValidation, StatsCalculator
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
NFTStats
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "./interfaces/INFTStats.sol"; import "./interfaces/ICollectionRegistry.sol"; import "./libraries/StatsCalculator.sol"; import "./libraries/StatValidation.sol"; import "@pythnetwork/entropy-sdk-solidity/IEntropy.sol"; import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol"; /// @title NFTStats /// @notice Manages individual NFT stats, experience, and leveling contract NFTStats is INFTStats, Ownable, IEntropyConsumer { // ------------------------- Immutable state variables ------------------------- ICollectionRegistry public immutable collectionRegistry; IEntropy public constant entropy = IEntropy(0x36825bf3Fbdf5a29E2d5148bfe7Dcf7B5639e320); address public constant provider = 0x52DeaA1c84233F7bb8C8A45baeDE41091c616506; bytes5 public constant STAT_VARIATION_BY_RARITY = bytes5( abi.encodePacked( uint8(10), uint8(20), uint8(30), uint8(50), uint8(100) ) ); // ------------------------- Constants for XP and leveling ------------------------- uint96 private constant BASE_XP_PER_LEVEL = 100; uint96 private constant XP_MULTIPLIER = 150; // 150% increase per level uint96 private constant BASE_STAT_INCREASE_PERCENT = 5; // 5% increase per level uint32 private constant STARTING_LEVEL = 1; // ------------------------- State variables ------------------------- mapping(address => mapping(uint256 => NFTStatsData)) private nftStats; mapping(uint64 => PendingRoll) private pendingRolls; mapping(address => bool) private authorizedContracts; // ------------------------- Structs ------------------------- struct PendingRoll { address collection; uint256 tokenId; } // ------------------------- Modifiers ------------------------- modifier onlyAuthorized() { require( msg.sender == owner() || authorizedContracts[msg.sender], "Not authorized" ); _; } // ------------------------- Constructor ------------------------- constructor(address _collectionRegistry) Ownable(msg.sender) { require(_collectionRegistry != address(0), "Invalid registry address"); collectionRegistry = ICollectionRegistry(_collectionRegistry); } // ------------------------- External functions - Admin ------------------------- /// @notice Set authorization for a contract to modify stats /// @param contract_ Address of the contract /// @param authorized Whether the contract should be authorized function setContractAuthorization( address contract_, bool authorized ) external onlyOwner { require(contract_ != address(0), "Invalid contract address"); authorizedContracts[contract_] = authorized; } // ------------------------- External functions - Core game mechanics ------------------------- /// @notice Initialize stats for an NFT based on its collection's base stats and a random number /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT function rollStats(address collection, uint256 tokenId) external { require( !nftStats[collection][tokenId].initialized, "Already initialized" ); require( collectionRegistry.isWhitelisted(collection), "Collection not whitelisted" ); // Verify NFT ownership try IERC721(collection).ownerOf(tokenId) returns (address) { // NFT exists, proceed with initialization } catch { revert("NFT does not exist"); } // Store pending roll using sequence number bytes32 pseudoRandomNumber = keccak256( abi.encode(block.timestamp, block.number, collection, tokenId) ); // Get the required fee uint128 requestFee = entropy.getFee(provider); // Request entropy and trigger callback uint64 sequenceNumber = entropy.requestWithCallback{value: requestFee}( provider, pseudoRandomNumber ); // Store pending roll pendingRolls[sequenceNumber] = PendingRoll({ collection: collection, tokenId: tokenId }); } /// @notice Award XP for dungeon progress /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT /// @param xpAmount Amount of XP to award /// @param roomsCleared Number of rooms cleared in this run function awardXP( address collection, uint256 tokenId, uint256 xpAmount, uint256 roomsCleared ) external onlyAuthorized { require( nftStats[collection][tokenId].initialized, "Stats not initialized" ); NFTStatsData storage stats = nftStats[collection][tokenId]; // Single storage update for XP uint256 newXP = stats.currentXP + xpAmount; stats.currentXP = uint96(newXP); stats.roomsCleared = uint32(stats.roomsCleared + roomsCleared); emit XPGained(collection, tokenId, xpAmount, newXP); } /// @notice Process pending level ups for a character /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT function levelUp(address collection, uint256 tokenId) external { require( nftStats[collection][tokenId].initialized, "Stats not initialized" ); NFTStatsData storage stats = nftStats[collection][tokenId]; uint96 currentXP = stats.currentXP; uint96 xpToNextLevel = stats.xpToNextLevel; uint32 currentLevel = stats.level; require(currentXP >= xpToNextLevel, "Insufficient XP"); // Calculate all level ups at once uint256 statMultiplier = 0; while (currentXP >= xpToNextLevel) { currentXP -= xpToNextLevel; currentLevel++; statMultiplier++; xpToNextLevel = getXPForNextLevel(currentLevel); } // Get base stats and calculate increases ( uint64 vitalityIncrease, uint64 strengthIncrease, uint64 agilityIncrease, uint64 defenseIncrease ) = getLevelUpStats(collection, tokenId); // Apply multiplier for multiple level ups vitalityIncrease = uint64(uint256(vitalityIncrease) * statMultiplier); strengthIncrease = uint64(uint256(strengthIncrease) * statMultiplier); agilityIncrease = uint64(uint256(agilityIncrease) * statMultiplier); defenseIncrease = uint64(uint256(defenseIncrease) * statMultiplier); // Calculate new stats uint64[4] memory newStats = [ stats.vitality + vitalityIncrease, stats.strength + strengthIncrease, stats.agility + agilityIncrease, stats.defense + defenseIncrease ]; // Validate new stats StatValidation.validateClassStats( collectionRegistry.getCollectionStats(collection).classType, newStats ); // Apply all updates in one SSTORE each stats.vitality = newStats[0]; stats.strength = newStats[1]; stats.agility = newStats[2]; stats.defense = newStats[3]; stats.level = uint32(currentLevel); stats.xpToNextLevel = uint96(xpToNextLevel); stats.currentXP = uint96(currentXP); emit LevelUp(collection, tokenId, currentLevel); emit StatsBoosted( collection, tokenId, newStats[0], newStats[1], newStats[2], newStats[3] ); } /// @notice Record a dungeon run attempt /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT /// @param success Whether the run was successful function recordRun( address collection, uint256 tokenId, bool success ) external onlyAuthorized { require( nftStats[collection][tokenId].initialized, "Stats not initialized" ); NFTStatsData storage stats = nftStats[collection][tokenId]; stats.dungeonRuns += 1; if (success) { stats.successfulRuns += 1; } emit RunRecorded( collection, tokenId, success, stats.roomsCleared, stats.currentXP ); } // ------------------------- External view functions ------------------------- /// @notice Get current stats for an NFT /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT /// @return NFTStatsData struct containing current stats function getStats( address collection, uint256 tokenId ) external view returns (NFTStatsData memory) { return nftStats[collection][tokenId]; } /// @notice Check if an NFT has been initialized /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT /// @return bool True if NFT has been initialized function isInitialized( address collection, uint256 tokenId ) external view returns (bool) { return nftStats[collection][tokenId].initialized; } /// @notice Get secondary stats derived from core stats /// @param vitality Character's vitality stat /// @param strength Character's strength stat /// @param agility Character's agility stat /// @param defense Character's defense stat /// @return criticalRate Chance to land critical hits (0-15) /// @return dodgeChance Chance to dodge attacks (0-10) /// @return blockRate Chance to block attacks (0-10) /// @return initiative Determines turn order in combat (0-100) function getSecondaryStats( uint64 vitality, uint64 strength, uint64 agility, uint64 defense ) external pure returns ( uint8 criticalRate, uint8 dodgeChance, uint8 blockRate, uint8 initiative ) { return StatsCalculator.calculateSecondaryStats( vitality, strength, agility, defense ); } /// @notice Get the stat increases for a level up /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT /// @return vitalityIncrease Amount vitality increases /// @return strengthIncrease Amount strength increases /// @return agilityIncrease Amount agility increases /// @return defenseIncrease Amount defense increases function getLevelUpStats( address collection, uint256 tokenId ) public view returns ( uint64 vitalityIncrease, uint64 strengthIncrease, uint64 agilityIncrease, uint64 defenseIncrease ) { require( nftStats[collection][tokenId].initialized, "Stats not initialized" ); NFTStatsData memory stats = nftStats[collection][tokenId]; vitalityIncrease = uint64( (uint256(stats.vitality) * BASE_STAT_INCREASE_PERCENT) / 100 ); strengthIncrease = uint64( (uint256(stats.strength) * BASE_STAT_INCREASE_PERCENT) / 100 ); agilityIncrease = uint64( (uint256(stats.agility) * BASE_STAT_INCREASE_PERCENT) / 100 ); defenseIncrease = uint64( (uint256(stats.defense) * BASE_STAT_INCREASE_PERCENT) / 100 ); } // ------------------------- Public view functions ------------------------- /// @notice Calculate XP required for next level /// @param currentLevel Current level of the NFT /// @return uint256 XP required for next level function getXPForNextLevel( uint32 currentLevel ) public pure returns (uint96) { return BASE_XP_PER_LEVEL * ((currentLevel * XP_MULTIPLIER) / 100); } // ------------------------- Internal functions ------------------------- /// @notice Required by IEntropyConsumer interface function getEntropy() internal pure override returns (address) { return address(entropy); } /// @notice Callback function for entropy service function entropyCallback( uint64 sequenceNumber, address /* provider */, bytes32 randomNumber ) internal override { PendingRoll memory pendingRoll = pendingRolls[sequenceNumber]; // Get base stats from collection registry ICollectionRegistry.CollectionStats memory baseStats = collectionRegistry.getCollectionStats( pendingRoll.collection ); // Generate random variations using entropy uint256 seed = uint256(randomNumber); uint256 rarityRoll = uint256(seed & 0xFF) % 100; uint8 rarityIndex; if (rarityRoll < 2) { rarityIndex = 4; // Legendary } else if (rarityRoll < 10) { rarityIndex = 3; // Epic } else if (rarityRoll < 30) { rarityIndex = 2; // Rare } else if (rarityRoll < 50) { rarityIndex = 1; // Uncommon } else { rarityIndex = 0; // Common } uint8 statVariation = uint8(STAT_VARIATION_BY_RARITY[rarityIndex]); // Calculate randomized stats within variation range uint64 vitalityVariation = uint64( (uint256(baseStats.baseVitality) * statVariation * uint256(seed & 0xFF)) / (255 * 100) ); uint64 strengthVariation = uint64( (uint256(baseStats.baseStrength) * statVariation * uint256((seed >> 8) & 0xFF)) / (255 * 100) ); uint64 agilityVariation = uint64( (uint256(baseStats.baseAgility) * statVariation * uint256((seed >> 16) & 0xFF)) / (255 * 100) ); uint64 defenseVariation = uint64( (uint256(baseStats.baseDefense) * statVariation * uint256((seed >> 24) & 0xFF)) / (255 * 100) ); // Calculate final stats uint64[4] memory stats = [ baseStats.baseVitality + vitalityVariation, baseStats.baseStrength + strengthVariation, baseStats.baseAgility + agilityVariation, baseStats.baseDefense + defenseVariation ]; // Validate stats for class type StatValidation.validateClassStats(baseStats.classType, stats); // Initialize NFT stats with randomized values nftStats[pendingRoll.collection][pendingRoll.tokenId] = NFTStatsData({ vitality: stats[0], strength: stats[1], agility: stats[2], defense: stats[3], level: uint32(STARTING_LEVEL), currentXP: 0, xpToNextLevel: getXPForNextLevel(STARTING_LEVEL), dungeonRuns: 0, successfulRuns: 0, roomsCleared: 0, initialized: true, rarity: Rarity(rarityIndex) }); // Clean up pending roll delete pendingRolls[sequenceNumber]; emit StatsInitialized( pendingRoll.collection, pendingRoll.tokenId, stats[0], stats[1], stats[2], stats[3] ); } // ------------------------- Fallback functions ------------------------- receive() external payable {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * 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 Ownable is Context { address private _owner; /** * @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. */ constructor(address initialOwner) { 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) { 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 { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC-721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC-721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /// @title INFTStats /// @notice Interface for managing individual NFT stats and progression interface INFTStats { // ------------------------- Type definitions ------------------------- /// @notice Enum representing different rarity levels /// affects the stat variation of the NFT enum Rarity { Common, Uncommon, Rare, Epic, Legendary } /// @notice Structure for NFT permanent stats struct NFTStatsData { // Core Stats (256 bits) uint64 vitality; // Replaces HP uint64 strength; // Replaces attack uint64 agility; // Replaces speed uint64 defense; // New stat // Progression data (256 bits) uint32 level; uint96 currentXP; uint96 xpToNextLevel; uint32 dungeonRuns; uint32 successfulRuns; uint32 roomsCleared; bool initialized; Rarity rarity; } // ------------------------- Events - Stats ------------------------- /// @notice Event emitted when an NFT's stats are initialized event StatsInitialized( address indexed collection, uint256 indexed tokenId, uint64 vitality, uint64 strength, uint64 agility, uint64 defense ); /// @notice Event emitted when an NFT's stats are boosted event StatsBoosted( address indexed collection, uint256 indexed tokenId, uint64 newVitality, uint64 newStrength, uint64 newAgility, uint64 newDefense ); // ------------------------- Events - Progression ------------------------- /// @notice Event emitted when XP is gained event XPGained( address indexed collection, uint256 indexed tokenId, uint256 xpGained, uint256 newTotalXP ); /// @notice Event emitted when a level up occurs event LevelUp( address indexed collection, uint256 indexed tokenId, uint256 newLevel ); /// @notice Event emitted when a run is recorded event RunRecorded( address indexed collection, uint256 indexed tokenId, bool success, uint256 roomsCleared, uint256 xpGained ); // ------------------------- View/Pure Functions ------------------------- /// @notice Get current stats for an NFT /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT /// @return NFTStatsData struct containing current stats function getStats( address collection, uint256 tokenId ) external view returns (NFTStatsData memory); /// @notice Check if an NFT has been initialized /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT /// @return bool True if NFT has been initialized function isInitialized( address collection, uint256 tokenId ) external view returns (bool); /// @notice Calculate XP required for next level /// @param currentLevel Current level of the NFT /// @return uint256 XP required for next level function getXPForNextLevel( uint32 currentLevel ) external pure returns (uint96); /// @notice Get secondary stats derived from core stats /// @param vitality Character's vitality stat /// @param strength Character's strength stat /// @param agility Character's agility stat /// @param defense Character's defense stat /// @return criticalRate Chance to land critical hits (0-15) /// @return dodgeChance Chance to dodge attacks (0-10) /// @return blockRate Chance to block attacks (0-10) /// @return initiative Determines turn order in combat (0-100) function getSecondaryStats( uint64 vitality, uint64 strength, uint64 agility, uint64 defense ) external pure returns ( uint8 criticalRate, uint8 dodgeChance, uint8 blockRate, uint8 initiative ); /// @notice Get the stat increases for a level up /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT /// @return vitalityIncrease Amount vitality increases /// @return strengthIncrease Amount strength increases /// @return agilityIncrease Amount agility increases /// @return defenseIncrease Amount defense increases function getLevelUpStats( address collection, uint256 tokenId ) external view returns ( uint64 vitalityIncrease, uint64 strengthIncrease, uint64 agilityIncrease, uint64 defenseIncrease ); // ------------------------- State-Changing Functions ------------------------- /// @notice Initialize stats for an NFT based on its collection's base stats /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT function rollStats(address collection, uint256 tokenId) external; /// @notice Award XP for dungeon progress /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT /// @param xpAmount Amount of XP to award /// @param roomsCleared Number of rooms cleared in this run function awardXP( address collection, uint256 tokenId, uint256 xpAmount, uint256 roomsCleared ) external; /// @notice Record a dungeon run attempt /// @param collection Address of the NFT collection /// @param tokenId Token ID of the NFT /// @param success Whether the run was successful function recordRun( address collection, uint256 tokenId, bool success ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /// @title ICollectionRegistry /// @notice Interface for managing whitelisted NFT collections and their base stats interface ICollectionRegistry { // ------------------------- Type definitions ------------------------- /// @notice Enum for different class archetypes enum ClassArchetype { WARRIOR, // High strength/defense ROGUE, // High agility/critical PALADIN, // Balanced with healing BERSERKER // High damage/risk } /// @notice Stats structure for NFT collections struct CollectionStats { uint64 baseVitality; uint64 baseStrength; uint64 baseAgility; uint64 baseDefense; uint8 classType; // ClassArchetype uint8 complexity; // For gas limit determination bool isWhitelisted; } // ------------------------- Events ------------------------- /// @notice Event emitted when a collection is whitelisted event CollectionWhitelisted( address indexed collection, uint64 baseVitality, uint64 baseStrength, uint64 baseAgility, uint64 baseDefense, ClassArchetype classType, uint8 complexity ); /// @notice Event emitted when a collection's stats are updated event CollectionStatsUpdated( address indexed collection, uint64 baseVitality, uint64 baseStrength, uint64 baseAgility, uint64 baseDefense, ClassArchetype classType, uint8 complexity ); /// @notice Event emitted when a collection is removed from whitelist event CollectionRemoved(address indexed collection); // ------------------------- Admin functions ------------------------- /// @notice Whitelist a new NFT collection with base stats /// @param collection Address of the NFT collection /// @param baseVitality Initial vitality for NFTs from this collection /// @param baseStrength Initial strength for NFTs from this collection /// @param baseAgility Initial agility for NFTs from this collection /// @param baseDefense Initial defense for NFTs from this collection /// @param classType Class archetype for this collection /// @param complexity Gas complexity tier (1-3) function whitelistCollection( address collection, uint64 baseVitality, uint64 baseStrength, uint64 baseAgility, uint64 baseDefense, ClassArchetype classType, uint8 complexity ) external; /// @notice Update base stats for a whitelisted collection /// @param collection Address of the NFT collection /// @param baseVitality New base vitality /// @param baseStrength New base strength /// @param baseAgility New base agility /// @param baseDefense New base defense /// @param classType New class archetype /// @param complexity New complexity tier function updateCollectionStats( address collection, uint64 baseVitality, uint64 baseStrength, uint64 baseAgility, uint64 baseDefense, ClassArchetype classType, uint8 complexity ) external; /// @notice Remove a collection from the whitelist /// @param collection Address of the NFT collection to remove function removeCollection(address collection) external; // ------------------------- View functions ------------------------- /// @notice Check if a collection is whitelisted /// @param collection Address of the NFT collection to check /// @return bool True if collection is whitelisted function isWhitelisted(address collection) external view returns (bool); /// @notice Get base stats for a collection /// @param collection Address of the NFT collection /// @return CollectionStats struct containing base stats function getCollectionStats( address collection ) external view returns (CollectionStats memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /// @title StatsCalculator /// @notice Library for calculating derived stats and combat values library StatsCalculator { // ------------------------- Constants ------------------------- uint8 private constant BASE_CRITICAL_RATE = 5; uint8 private constant MAX_CRITICAL_RATE = 15; uint8 private constant MAX_DODGE_CHANCE = 10; uint8 private constant MAX_BLOCK_RATE = 10; uint8 private constant CRITICAL_DAMAGE_PERCENT = 150; uint8 private constant BLOCK_REDUCTION_PERCENT = 50; uint256 private constant HP_PER_VITALITY = 5; // ------------------------- Core stat calculations ------------------------- /// @notice Calculate max HP from vitality /// @param vitality Character's vitality stat /// @return uint256 Maximum HP value function calculateHp(uint64 vitality) public pure returns (uint256) { return uint256(vitality) * HP_PER_VITALITY; } /// @notice Calculate damage considering strength and enemy defense /// @param strength Attacker's strength stat /// @param enemyDefense Defender's defense stat /// @return uint256 Base damage value function calculateDamage( uint64 strength, uint64 enemyDefense ) public pure returns (uint256) { return (uint256(strength) * 100) / (100 + uint256(enemyDefense)); } // ------------------------- Secondary stat calculations ------------------------- /// @notice Calculate all secondary stats /// @param vitality Character's vitality stat /// @param strength Character's strength stat /// @param agility Character's agility stat /// @param defense Character's defense stat /// @return criticalRate Chance to land critical hits (0-15) /// @return dodgeChance Chance to dodge attacks (0-10) /// @return blockRate Chance to block attacks (0-10) /// @return initiative Determines turn order in combat (0-100) function calculateSecondaryStats( uint64 vitality, uint64 strength, uint64 agility, uint64 defense ) public pure returns ( uint8 criticalRate, uint8 dodgeChance, uint8 blockRate, uint8 initiative ) { criticalRate = calculateCriticalRate(agility); dodgeChance = calculateDodgeChance(agility); blockRate = calculateBlockRate(defense); initiative = calculateInitiative(agility, strength); } /// @notice Calculate critical hit rate from agility /// @param agility Character's agility stat /// @return uint8 Critical hit chance (0-15) function calculateCriticalRate(uint64 agility) public pure returns (uint8) { uint8 critRate = BASE_CRITICAL_RATE + uint8(agility / 40); return critRate > MAX_CRITICAL_RATE ? MAX_CRITICAL_RATE : critRate; } /// @notice Calculate dodge chance from agility /// @param agility Character's agility stat /// @return uint8 Dodge chance (0-10) function calculateDodgeChance(uint64 agility) public pure returns (uint8) { uint8 dodgeChance = uint8(agility / 50); return dodgeChance > MAX_DODGE_CHANCE ? MAX_DODGE_CHANCE : dodgeChance; } /// @notice Calculate block rate from defense /// @param defense Character's defense stat /// @return uint8 Block chance (0-10) function calculateBlockRate(uint64 defense) public pure returns (uint8) { uint8 blockRate = uint8(defense / 50); return blockRate > MAX_BLOCK_RATE ? MAX_BLOCK_RATE : blockRate; } /// @notice Calculate initiative for combat order /// @param agility Character's agility stat /// @param strength Character's strength stat /// @return uint8 Initiative value (0-100) function calculateInitiative( uint64 agility, uint64 strength ) public pure returns (uint8) { return uint8(((uint256(agility) * 2) + uint256(strength)) / 3); } // ------------------------- Combat calculations ------------------------- /// @notice Calculate final damage including critical hits /// @param baseDamage Base damage amount /// @param criticalRate Critical hit chance /// @param entropy Random value for critical determination /// @return uint256 Final damage amount function calculateDamageWithCrit( uint256 baseDamage, uint8 criticalRate, bytes32 entropy ) public pure returns (uint256) { bool isCritical = uint8(uint256(entropy) & 0xFF) < criticalRate; return isCritical ? (baseDamage * CRITICAL_DAMAGE_PERCENT) / 100 : baseDamage; } /// @notice Calculate damage reduction from blocking /// @param incomingDamage Original damage amount /// @param blockRate Block chance /// @param entropy Random value for block determination /// @return uint256 Final damage after potential block function calculateDamageReduction( uint256 incomingDamage, uint8 blockRate, bytes32 entropy ) public pure returns (uint256) { bool isBlocked = uint8(uint256(entropy >> 8) & 0xFF) < blockRate; return isBlocked ? (incomingDamage * BLOCK_REDUCTION_PERCENT) / 100 : incomingDamage; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "../interfaces/ICollectionRegistry.sol"; /// @title StatValidation /// @notice Library for validating stat ranges and class-specific requirements library StatValidation { // ------------------------- Constants ------------------------- uint64 private constant MIN_STAT_VALUE = 50; uint64 private constant MAX_STAT_VALUE = 200; uint64 private constant MAX_STAT_INCREASE = 50; uint8 private constant MAX_COMPLEXITY = 3; // Gas limits by complexity tier uint256 private constant TIER1_GAS_LIMIT = 30000; uint256 private constant TIER2_GAS_LIMIT = 50000; uint256 private constant TIER3_GAS_LIMIT = 80000; // ------------------------- Errors ------------------------- error InvalidStatRange(uint64 value, uint64 min, uint64 max); error InvalidStatIncrease( uint64 oldValue, uint64 newValue, uint64 maxIncrease ); error InvalidClassStats(uint8 classType, string reason); error InvalidComplexity(uint8 complexity, uint256 gasUsed); // ------------------------- Core validation ------------------------- /// @notice Validate a stat value is within acceptable range /// @param value Stat value to check /// @param min Minimum allowed value /// @param max Maximum allowed value function validateStatRange( uint64 value, uint64 min, uint64 max ) public pure { if (value < min || value > max) { revert InvalidStatRange(value, min, max); } } /// @notice Validate a stat increase is within acceptable range /// @param oldValue Previous stat value /// @param newValue New stat value /// @param maxIncrease Maximum allowed increase function validateStatIncrease( uint64 oldValue, uint64 newValue, uint64 maxIncrease ) public pure { if (newValue < oldValue || newValue > oldValue + maxIncrease) { revert InvalidStatIncrease(oldValue, newValue, maxIncrease); } } // ------------------------- Class validation ------------------------- /// @notice Validate stats are appropriate for class type /// @param classType The class archetype /// @param stats Array of stats [vitality, strength, agility, defense] function validateClassStats( uint8 classType, uint64[4] memory stats ) public pure { ICollectionRegistry.ClassArchetype archetype = ICollectionRegistry .ClassArchetype(classType); // Validate base requirements for each class if (archetype == ICollectionRegistry.ClassArchetype.WARRIOR) { if (stats[1] < 80 || stats[3] < 80) { // strength and defense revert InvalidClassStats( classType, "Warrior requires high strength and defense" ); } } else if (archetype == ICollectionRegistry.ClassArchetype.ROGUE) { if (stats[2] < 80) { // agility revert InvalidClassStats( classType, "Rogue requires high agility" ); } } else if (archetype == ICollectionRegistry.ClassArchetype.PALADIN) { if (stats[0] < 80 || stats[3] < 70) { // vitality and defense revert InvalidClassStats( classType, "Paladin requires high vitality and defense" ); } } else if (archetype == ICollectionRegistry.ClassArchetype.BERSERKER) { if (stats[1] < 90) { // strength revert InvalidClassStats( classType, "Berserker requires very high strength" ); } } // Validate all stats are within global range for (uint256 i = 0; i < 4; i++) { validateStatRange(stats[i], MIN_STAT_VALUE, MAX_STAT_VALUE); } } // ------------------------- Complexity validation ------------------------- /// @notice Validate gas usage against complexity tier /// @param complexity Complexity tier (1-3) /// @param gasUsed Amount of gas used function validateComplexityRequirements( uint8 complexity, uint256 gasUsed ) public pure { if (complexity == 0 || complexity > MAX_COMPLEXITY) { revert InvalidComplexity(complexity, gasUsed); } uint256 gasLimit = complexity == 1 ? TIER1_GAS_LIMIT : complexity == 2 ? TIER2_GAS_LIMIT : TIER3_GAS_LIMIT; if (gasUsed > gasLimit) { revert InvalidComplexity(complexity, gasUsed); } } // ------------------------- Utility functions ------------------------- /// @notice Get the gas limit for a complexity tier /// @param complexity Complexity tier (1-3) /// @return uint256 Gas limit for the tier function getGasLimitForComplexity( uint8 complexity ) public pure returns (uint256) { return complexity == 1 ? TIER1_GAS_LIMIT : complexity == 2 ? TIER2_GAS_LIMIT : complexity == 3 ? TIER3_GAS_LIMIT : 0; } }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "./EntropyEvents.sol"; interface IEntropy is EntropyEvents { // Register msg.sender as a randomness provider. The arguments are the provider's configuration parameters // and initial commitment. Re-registering the same provider rotates the provider's commitment (and updates // the feeInWei). // // chainLength is the number of values in the hash chain *including* the commitment, that is, chainLength >= 1. function register( uint128 feeInWei, bytes32 commitment, bytes calldata commitmentMetadata, uint64 chainLength, bytes calldata uri ) external; // Withdraw a portion of the accumulated fees for the provider msg.sender. // Calling this function will transfer `amount` wei to the caller (provided that they have accrued a sufficient // balance of fees in the contract). function withdraw(uint128 amount) external; // Withdraw a portion of the accumulated fees for provider. The msg.sender must be the fee manager for this provider. // Calling this function will transfer `amount` wei to the caller (provided that they have accrued a sufficient // balance of fees in the contract). function withdrawAsFeeManager(address provider, uint128 amount) external; // As a user, request a random number from `provider`. Prior to calling this method, the user should // generate a random number x and keep it secret. The user should then compute hash(x) and pass that // as the userCommitment argument. (You may call the constructUserCommitment method to compute the hash.) // // This method returns a sequence number. The user should pass this sequence number to // their chosen provider (the exact method for doing so will depend on the provider) to retrieve the provider's // number. The user should then call fulfillRequest to construct the final random number. // // This method will revert unless the caller provides a sufficient fee (at least getFee(provider)) as msg.value. // Note that excess value is *not* refunded to the caller. function request( address provider, bytes32 userCommitment, bool useBlockHash ) external payable returns (uint64 assignedSequenceNumber); // Request a random number. The method expects the provider address and a secret random number // in the arguments. It returns a sequence number. // // The address calling this function should be a contract that inherits from the IEntropyConsumer interface. // The `entropyCallback` method on that interface will receive a callback with the generated random number. // // This method will revert unless the caller provides a sufficient fee (at least getFee(provider)) as msg.value. // Note that excess value is *not* refunded to the caller. function requestWithCallback( address provider, bytes32 userRandomNumber ) external payable returns (uint64 assignedSequenceNumber); // Fulfill a request for a random number. This method validates the provided userRandomness and provider's proof // against the corresponding commitments in the in-flight request. If both values are validated, this function returns // the corresponding random number. // // Note that this function can only be called once per in-flight request. Calling this function deletes the stored // request information (so that the contract doesn't use a linear amount of storage in the number of requests). // If you need to use the returned random number more than once, you are responsible for storing it. function reveal( address provider, uint64 sequenceNumber, bytes32 userRevelation, bytes32 providerRevelation ) external returns (bytes32 randomNumber); // Fulfill a request for a random number. This method validates the provided userRandomness // and provider's revelation against the corresponding commitment in the in-flight request. If both values are validated // and the requestor address is a contract address, this function calls the requester's entropyCallback method with the // sequence number, provider address and the random number as arguments. Else if the requestor is an EOA, it won't call it. // // Note that this function can only be called once per in-flight request. Calling this function deletes the stored // request information (so that the contract doesn't use a linear amount of storage in the number of requests). // If you need to use the returned random number more than once, you are responsible for storing it. // // Anyone can call this method to fulfill a request, but the callback will only be made to the original requester. function revealWithCallback( address provider, uint64 sequenceNumber, bytes32 userRandomNumber, bytes32 providerRevelation ) external; function getProviderInfo( address provider ) external view returns (EntropyStructs.ProviderInfo memory info); function getDefaultProvider() external view returns (address provider); function getRequest( address provider, uint64 sequenceNumber ) external view returns (EntropyStructs.Request memory req); function getFee(address provider) external view returns (uint128 feeAmount); function getAccruedPythFees() external view returns (uint128 accruedPythFeesInWei); function setProviderFee(uint128 newFeeInWei) external; function setProviderFeeAsFeeManager( address provider, uint128 newFeeInWei ) external; function setProviderUri(bytes calldata newUri) external; // Set manager as the fee manager for the provider msg.sender. // After calling this function, manager will be able to set the provider's fees and withdraw them. // Only one address can be the fee manager for a provider at a time -- calling this function again with a new value // will override the previous value. Call this function with the all-zero address to disable the fee manager role. function setFeeManager(address manager) external; function constructUserCommitment( bytes32 userRandomness ) external pure returns (bytes32 userCommitment); function combineRandomValues( bytes32 userRandomness, bytes32 providerRandomness, bytes32 blockHash ) external pure returns (bytes32 combinedRandomness); }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; abstract contract IEntropyConsumer { // This method is called by Entropy to provide the random number to the consumer. // It asserts that the msg.sender is the Entropy contract. It is not meant to be // override by the consumer. function _entropyCallback( uint64 sequence, address provider, bytes32 randomNumber ) external { address entropy = getEntropy(); require(entropy != address(0), "Entropy address not set"); require(msg.sender == entropy, "Only Entropy can call this function"); entropyCallback(sequence, provider, randomNumber); } // getEntropy returns Entropy contract address. The method is being used to check that the // callback is indeed from Entropy contract. The consumer is expected to implement this method. // Entropy address can be found here - https://docs.pyth.network/entropy/contract-addresses function getEntropy() internal view virtual returns (address); // This method is expected to be implemented by the consumer to handle the random number. // It will be called by _entropyCallback after _entropyCallback ensures that the call is // indeed from Entropy contract. function entropyCallback( uint64 sequence, address provider, bytes32 randomNumber ) internal virtual; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; import "./EntropyStructs.sol"; interface EntropyEvents { event Registered(EntropyStructs.ProviderInfo provider); event Requested(EntropyStructs.Request request); event RequestedWithCallback( address indexed provider, address indexed requestor, uint64 indexed sequenceNumber, bytes32 userRandomNumber, EntropyStructs.Request request ); event Revealed( EntropyStructs.Request request, bytes32 userRevelation, bytes32 providerRevelation, bytes32 blockHash, bytes32 randomNumber ); event RevealedWithCallback( EntropyStructs.Request request, bytes32 userRandomNumber, bytes32 providerRevelation, bytes32 randomNumber ); event ProviderFeeUpdated(address provider, uint128 oldFee, uint128 newFee); event ProviderUriUpdated(address provider, bytes oldUri, bytes newUri); event ProviderFeeManagerUpdated( address provider, address oldFeeManager, address newFeeManager ); event Withdrawal( address provider, address recipient, uint128 withdrawnAmount ); }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; contract EntropyStructs { struct ProviderInfo { uint128 feeInWei; uint128 accruedFeesInWei; // The commitment that the provider posted to the blockchain, and the sequence number // where they committed to this. This value is not advanced after the provider commits, // and instead is stored to help providers track where they are in the hash chain. bytes32 originalCommitment; uint64 originalCommitmentSequenceNumber; // Metadata for the current commitment. Providers may optionally use this field to help // manage rotations (i.e., to pick the sequence number from the correct hash chain). bytes commitmentMetadata; // Optional URI where clients can retrieve revelations for the provider. // Client SDKs can use this field to automatically determine how to retrieve random values for each provider. // TODO: specify the API that must be implemented at this URI bytes uri; // The first sequence number that is *not* included in the current commitment (i.e., an exclusive end index). // The contract maintains the invariant that sequenceNumber <= endSequenceNumber. // If sequenceNumber == endSequenceNumber, the provider must rotate their commitment to add additional random values. uint64 endSequenceNumber; // The sequence number that will be assigned to the next inbound user request. uint64 sequenceNumber; // The current commitment represents an index/value in the provider's hash chain. // These values are used to verify requests for future sequence numbers. Note that // currentCommitmentSequenceNumber < sequenceNumber. // // The currentCommitment advances forward through the provider's hash chain as values // are revealed on-chain. bytes32 currentCommitment; uint64 currentCommitmentSequenceNumber; // An address that is authorized to set / withdraw fees on behalf of this provider. address feeManager; } struct Request { // Storage slot 1 // address provider; uint64 sequenceNumber; // The number of hashes required to verify the provider revelation. uint32 numHashes; // Storage slot 2 // // The commitment is keccak256(userCommitment, providerCommitment). Storing the hash instead of both saves 20k gas by // eliminating 1 store. bytes32 commitment; // Storage slot 3 // // The number of the block where this request was created. // Note that we're using a uint64 such that we have an additional space for an address and other fields in // this storage slot. Although block.number returns a uint256, 64 bits should be plenty to index all of the // blocks ever generated. uint64 blockNumber; // The address that requested this random number. address requester; // If true, incorporate the blockhash of blockNumber into the generated random value. bool useBlockhash; // If true, the requester will be called back with the generated random value. bool isRequestWithCallback; // There are 2 remaining bytes of free space in this slot. } }
{ "remappings": [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@pythnetwork/entropy-sdk-solidity/=../node_modules/@pythnetwork/entropy-sdk-solidity/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "pyth-sdk-solidity/=lib/pyth-sdk-solidity/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "shanghai", "viaIR": false, "libraries": { "src/libraries/StatValidation.sol": { "StatValidation": "0x6E9a7a68Ae6B4B27D9D5494c034939C52a49b650" }, "src/libraries/StatsCalculator.sol": { "StatsCalculator": "0x40bc4D559834F72951a83a8e098A6b969F1c79a8" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_collectionRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLevel","type":"uint256"}],"name":"LevelUp","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":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint256","name":"roomsCleared","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"xpGained","type":"uint256"}],"name":"RunRecorded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"newVitality","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newStrength","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newAgility","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newDefense","type":"uint64"}],"name":"StatsBoosted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"vitality","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"strength","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"agility","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"defense","type":"uint64"}],"name":"StatsInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"xpGained","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalXP","type":"uint256"}],"name":"XPGained","type":"event"},{"inputs":[],"name":"STAT_VARIATION_BY_RARITY","outputs":[{"internalType":"bytes5","name":"","type":"bytes5"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"sequence","type":"uint64"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"bytes32","name":"randomNumber","type":"bytes32"}],"name":"_entropyCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"xpAmount","type":"uint256"},{"internalType":"uint256","name":"roomsCleared","type":"uint256"}],"name":"awardXP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectionRegistry","outputs":[{"internalType":"contract ICollectionRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"entropy","outputs":[{"internalType":"contract IEntropy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getLevelUpStats","outputs":[{"internalType":"uint64","name":"vitalityIncrease","type":"uint64"},{"internalType":"uint64","name":"strengthIncrease","type":"uint64"},{"internalType":"uint64","name":"agilityIncrease","type":"uint64"},{"internalType":"uint64","name":"defenseIncrease","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"vitality","type":"uint64"},{"internalType":"uint64","name":"strength","type":"uint64"},{"internalType":"uint64","name":"agility","type":"uint64"},{"internalType":"uint64","name":"defense","type":"uint64"}],"name":"getSecondaryStats","outputs":[{"internalType":"uint8","name":"criticalRate","type":"uint8"},{"internalType":"uint8","name":"dodgeChance","type":"uint8"},{"internalType":"uint8","name":"blockRate","type":"uint8"},{"internalType":"uint8","name":"initiative","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getStats","outputs":[{"components":[{"internalType":"uint64","name":"vitality","type":"uint64"},{"internalType":"uint64","name":"strength","type":"uint64"},{"internalType":"uint64","name":"agility","type":"uint64"},{"internalType":"uint64","name":"defense","type":"uint64"},{"internalType":"uint32","name":"level","type":"uint32"},{"internalType":"uint96","name":"currentXP","type":"uint96"},{"internalType":"uint96","name":"xpToNextLevel","type":"uint96"},{"internalType":"uint32","name":"dungeonRuns","type":"uint32"},{"internalType":"uint32","name":"successfulRuns","type":"uint32"},{"internalType":"uint32","name":"roomsCleared","type":"uint32"},{"internalType":"bool","name":"initialized","type":"bool"},{"internalType":"enum INFTStats.Rarity","name":"rarity","type":"uint8"}],"internalType":"struct INFTStats.NFTStatsData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"currentLevel","type":"uint32"}],"name":"getXPForNextLevel","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"levelUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"provider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bool","name":"success","type":"bool"}],"name":"recordRun","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"rollStats","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contract_","type":"address"},{"internalType":"bool","name":"authorized","type":"bool"}],"name":"setContractAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a060405234801562000010575f80fd5b506040516200277f3803806200277f83398101604081905262000033916200011f565b33806200005a57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b6200006581620000d0565b506001600160a01b038116620000be5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420726567697374727920616464726573730000000000000000604482015260640162000051565b6001600160a01b03166080526200014e565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f6020828403121562000130575f80fd5b81516001600160a01b038116811462000147575f80fd5b9392505050565b6080516126036200017c5f395f818161026901528181610a790152818161139e015261171201526126035ff3fe608060405260043610610108575f3560e01c80638da5cb5b11610092578063b339311511610062578063b339311514610351578063e8328503146103a3578063f2fde38b146103ef578063f60ccc861461040e578063f626052e1461042d575f80fd5b80638da5cb5b1461028b57806391f6c658146102a7578063994e4a19146102c6578063996acc9414610324575f80fd5b806352a5f1f8116100d857806352a5f1f8146101cf578063546ef395146101ee5780635ad2dda41461020d578063715018a6146102445780638c7cc5e314610258575f80fd5b80630368516914610113578063085d4883146101485780630954c4781461018757806347ce07cc146101a8575f80fd5b3661010f57005b5f80fd5b34801561011e575f80fd5b5061013261012d366004611ea9565b61044c565b60405161013f9190611f07565b60405180910390f35b348015610153575f80fd5b5061016f7352deaa1c84233f7bb8c8a45baede41091c61650681565b6040516001600160a01b03909116815260200161013f565b348015610192575f80fd5b506101a66101a136600461201c565b6105c1565b005b3480156101b3575f80fd5b5061016f7336825bf3fbdf5a29e2d5148bfe7dcf7b5639e32081565b3480156101da575f80fd5b506101a66101e9366004612068565b61077b565b3480156101f9575f80fd5b506101a6610208366004611ea9565b6107fc565b348015610218575f80fd5b5061022c6102273660046120a6565b610d3c565b6040516001600160601b03909116815260200161013f565b34801561024f575f80fd5b506101a6610d65565b348015610263575f80fd5b5061016f7f000000000000000000000000000000000000000000000000000000000000000081565b348015610296575f80fd5b505f546001600160a01b031661016f565b3480156102b2575f80fd5b506101a66102c13660046120dd565b610d78565b3480156102d1575f80fd5b506103146102e0366004611ea9565b6001600160a01b03919091165f9081526001602090815260408083209383529290522060020154600160401b900460ff1690565b604051901515815260200161013f565b34801561032f575f80fd5b50610338610f45565b6040516001600160d81b0319909116815260200161013f565b34801561035c575f80fd5b5061037061036b366004611ea9565b610f7e565b604080516001600160401b039586168152938516602085015291841691830191909152909116606082015260800161013f565b3480156103ae575f80fd5b506103c26103bd36600461211c565b61119b565b6040805160ff9586168152938516602085015291841691830191909152909116606082015260800161013f565b3480156103fa575f80fd5b506101a6610409366004612175565b611247565b348015610419575f80fd5b506101a6610428366004612190565b611284565b348015610438575f80fd5b506101a6610447366004611ea9565b61130c565b6104b060408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290529061016082015290565b6001600160a01b0383165f90815260016020818152604080842086855282529283902083516101808101855281546001600160401b038082168352600160401b808304821695840195909552600160801b808304821697840197909752600160c01b9091041660608201529281015463ffffffff80821660808601526001600160601b03600160201b808404821660a08801529683041660c0860152600160e01b909104811660e085015260028201548082166101008601529485041661012084015260ff918404821615156101408401529192610160840191600160481b9091041660048111156105a4576105a4611ed3565b60048111156105b5576105b5611ed3565b90525090505b92915050565b5f546001600160a01b03163314806105e75750335f9081526003602052604090205460ff165b6106295760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b60448201526064015b60405180910390fd5b6001600160a01b0384165f908152600160209081526040808320868452909152902060020154600160401b900460ff166106755760405162461bcd60e51b8152600401610620906121c7565b6001600160a01b0384165f9081526001602081815260408084208785529091528220908101549091906106b9908590600160201b90046001600160601b031661220a565b6001830180546fffffffffffffffffffffffff000000001916600160201b6001600160601b0384168102919091179091556002840154919250610705918591900463ffffffff1661220a565b60028301805463ffffffff92909216600160201b0267ffffffff0000000019909216919091179055604080518581526020810183905286916001600160a01b038916917f1cfcc60a52168386067c020abab02289b7dee02c9a7e9690aeff3c3aa53e24a8910160405180910390a3505050505050565b7336825bf3fbdf5a29e2d5148bfe7dcf7b5639e3203381146107eb5760405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920456e74726f70792063616e2063616c6c20746869732066756e637460448201526234b7b760e91b6064820152608401610620565b6107f68484846116bb565b50505050565b6001600160a01b0382165f908152600160209081526040808320848452909152902060020154600160401b900460ff166108485760405162461bcd60e51b8152600401610620906121c7565b6001600160a01b0382165f908152600160208181526040808420858552909152909120908101546001600160601b03600160201b8204811691600160801b81049091169063ffffffff16818310156108d45760405162461bcd60e51b815260206004820152600f60248201526e0496e73756666696369656e7420585608c1b6044820152606401610620565b5f5b826001600160601b0316846001600160601b031610610926576108f9838561221d565b93508161090581612244565b925050808061091390612266565b91505061091f82610d3c565b92506108d6565b5f805f806109348b8b610f7e565b935093509350935084846001600160401b0316610951919061227e565b9350610966856001600160401b03851661227e565b925061097b856001600160401b03841661227e565b9150610990856001600160401b03831661227e565b60408051608081019091528a549192505f9181906109b89088906001600160401b0316612295565b6001600160401b0390811682528c546020909201916109e0918891600160401b900416612295565b6001600160401b0390811682528c54602090920191610a08918791600160801b900416612295565b6001600160401b0390811682528c54602090920191610a30918691600160c01b900416612295565b6001600160401b03169052604051631cc6f28360e31b81526001600160a01b038e81166004830152919250736e9a7a68ae6b4b27d9d5494c034939c52a49b6509163baae97e5917f00000000000000000000000000000000000000000000000000000000000000009091169063e63794189060240160e060405180830381865afa158015610ac0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ae491906122e0565b60800151836040518363ffffffff1660e01b8152600401610b06929190612399565b5f6040518083038186803b158015610b1c575f80fd5b505af4158015610b2e573d5f803e3d5ffd5b50505050805f60048110610b4457610b446123dc565b60200201518a5467ffffffffffffffff19166001600160401b03909116178a5580600160200201518a546001600160401b03909116600160401b026fffffffffffffffff000000000000000019909116178a5580600260200201518a546001600160401b03909116600160801b0267ffffffffffffffff60801b19909116178a5580600360200201518a546001600160401b03909116600160c01b026001600160c01b03909116178a5560018a0180546001600160601b038b8116600160201b026fffffffffffffffffffffffff0000000019918c16600160801b027fffffffff000000000000000000000000ffffffffffffffffffffffff0000000090931663ffffffff8c161792909217161790556040518b906001600160a01b038e16907feec61667dd6eeecdccfef3c906e0fd047cca672804901ac4254d8545e9a426d490610c9d908b9063ffffffff91909116815260200190565b60405180910390a38a6001600160a01b038d167f8def189a8e735301f41e5cb70b3fa998ce66011c168203e4039996309d49237c835f6020020151846001602002015185600260200201518660036020020151604051610d2694939291906001600160401b03948516815292841660208401529083166040830152909116606082015260800190565b60405180910390a3505050505050505050505050565b5f6064610d50609663ffffffff85166123f0565b610d5a9190612427565b6105bb9060646123f0565b610d6d611e1a565b610d765f611e46565b565b5f546001600160a01b0316331480610d9e5750335f9081526003602052604090205460ff165b610ddb5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610620565b6001600160a01b0383165f908152600160209081526040808320858452909152902060020154600160401b900460ff16610e275760405162461bcd60e51b8152600401610620906121c7565b6001600160a01b0383165f9081526001602081815260408084208685529091529091208082018054919291601c90610e6d908490600160e01b900463ffffffff1661244c565b92506101000a81548163ffffffff021916908363ffffffff1602179055508115610ecd57600281018054600191905f90610eae90849063ffffffff1661244c565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b60028101546001820154604080518515158152600160201b9384900463ffffffff166020820152929091046001600160601b03169082015283906001600160a01b038616907fe6ce2da96a964985bd161cb1f6b383b07d1f2fed13aef14028de4503dfeb81d29060600160405180910390a350505050565b600a6014601e60326064604051602001610f63959493929190612469565b604051602081830303815290604052610f7b906124a8565b81565b6001600160a01b0382165f908152600160209081526040808320848452909152812060020154819081908190600160401b900460ff16610fd05760405162461bcd60e51b8152600401610620906121c7565b6001600160a01b0386165f908152600160208181526040808420898552825280842081516101808101835281546001600160401b038082168352600160401b808304821696840196909652600160801b808304821695840195909552600160c01b9091041660608201529381015463ffffffff80821660808701526001600160601b03600160201b808404821660a08901529483041660c0870152600160e01b909104811660e086015260028201548082166101008701529283041661012085015260ff9282048316151561014085015291610160840191600160481b90041660048111156110c1576110c1611ed3565b60048111156110d2576110d2611ed3565b90525080519091506064906110f2906005906001600160401b031661227e565b6110fc91906124df565b9450606460056001600160601b031682602001516001600160401b0316611123919061227e565b61112d91906124df565b9350606460056001600160601b031682604001516001600160401b0316611154919061227e565b61115e91906124df565b9250606460056001600160601b031682606001516001600160401b0316611185919061227e565b61118f91906124df565b91505092959194509250565b604051636007a06360e01b81526001600160401b03808616600483015280851660248301528084166044830152821660648201525f908190819081907340bc4d559834f72951a83a8e098a6b969f1c79a890636007a06390608401608060405180830381865af4158015611211573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061123591906124f2565b929b919a509850909650945050505050565b61124f611e1a565b6001600160a01b03811661127857604051631e4fbdf760e01b81525f6004820152602401610620565b61128181611e46565b50565b61128c611e1a565b6001600160a01b0382166112e25760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420636f6e7472616374206164647265737300000000000000006044820152606401610620565b6001600160a01b03919091165f908152600360205260409020805460ff1916911515919091179055565b6001600160a01b0382165f908152600160209081526040808320848452909152902060020154600160401b900460ff161561137f5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606401610620565b604051633af32abf60e01b81526001600160a01b0383811660048301527f00000000000000000000000000000000000000000000000000000000000000001690633af32abf90602401602060405180830381865afa1580156113e3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114079190612543565b6114535760405162461bcd60e51b815260206004820152601a60248201527f436f6c6c656374696f6e206e6f742077686974656c69737465640000000000006044820152606401610620565b6040516331a9108f60e11b8152600481018290526001600160a01b03831690636352211e90602401602060405180830381865afa9250505080156114b4575060408051601f3d908101601f191682019092526114b19181019061255e565b60015b6114f55760405162461bcd60e51b815260206004820152601260248201527113919508191bd95cc81b9bdd08195e1a5cdd60721b6044820152606401610620565b506040805142602082015243918101919091526001600160a01b0383166060820152608081018290525f9060a00160408051808303601f19018152908290528051602090910120631711922960e31b82527352deaa1c84233f7bb8c8a45baede41091c616506600483015291505f907336825bf3fbdf5a29e2d5148bfe7dcf7b5639e3209063b88c914890602401602060405180830381865afa15801561159e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c29190612579565b6040516319cb825f60e01b81527352deaa1c84233f7bb8c8a45baede41091c6165066004820152602481018490529091505f907336825bf3fbdf5a29e2d5148bfe7dcf7b5639e320906319cb825f906001600160801b0385169060440160206040518083038185885af115801561163b573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190611660919061259f565b6040805180820182526001600160a01b03978816815260208082019788526001600160401b03939093165f90815260029093529120905181546001600160a01b03191696169590951785555050905160019092019190915550565b6001600160401b0383165f9081526002602090815260408083208151808301835281546001600160a01b03908116808352600190930154948201949094529151631cc6f28360e31b815260048101919091529092917f0000000000000000000000000000000000000000000000000000000000000000169063e63794189060240160e060405180830381865afa158015611757573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061177b91906122e0565b9050825f61178d606460ff84166125ba565b90505f60028210156117a1575060046117d7565b600a8210156117b2575060036117d7565b601e8210156117c3575060026117d7565b60328210156117d4575060016117d7565b505f5b5f600a6014601e603260646040516020016117f6959493929190612469565b60405160208183030381529060405261180e906124a8565b8260ff1660058110611822576118226123dc565b865191901a91505f9061639c9060ff8716906118489085906001600160401b031661227e565b611852919061227e565b61185c91906124df565b90505f61639c600887901c60ff168460ff1689602001516001600160401b0316611886919061227e565b611890919061227e565b61189a91906124df565b90505f61639c601088901c60ff168560ff168a604001516001600160401b03166118c4919061227e565b6118ce919061227e565b6118d891906124df565b90505f61639c601889901c60ff168660ff168b606001516001600160401b0316611902919061227e565b61190c919061227e565b61191691906124df565b90505f6040518060800160405280868c5f01516119339190612295565b6001600160401b03166001600160401b03168152602001858c6020015161195a9190612295565b6001600160401b03166001600160401b03168152602001848c604001516119819190612295565b6001600160401b03166001600160401b03168152602001838c606001516119a89190612295565b6001600160401b0316905260808b015160405163baae97e560e01b8152919250736e9a7a68ae6b4b27d9d5494c034939c52a49b6509163baae97e5916119f2918590600401612399565b5f6040518083038186803b158015611a08575f80fd5b505af4158015611a1a573d5f803e3d5ffd5b50505050604051806101800160405280825f60048110611a3c57611a3c6123dc565b60200201516001600160401b0316815260200182600160048110611a6257611a626123dc565b60200201516001600160401b0316815260200182600260048110611a8857611a886123dc565b60200201516001600160401b0316815260200182600360048110611aae57611aae6123dc565b60200201516001600160401b03168152602001600163ffffffff1681526020015f6001600160601b03168152602001611ae76001610d3c565b6001600160601b031681525f602082018190526040820181905260608201526001608082015260a00160ff89166004811115611b2557611b25611ed3565b6004811115611b3657611b36611ed3565b81525060015f8d5f01516001600160a01b03166001600160a01b031681526020019081526020015f205f8d6020015181526020019081526020015f205f820151815f015f6101000a8154816001600160401b0302191690836001600160401b031602179055506020820151815f0160086101000a8154816001600160401b0302191690836001600160401b031602179055506040820151815f0160106101000a8154816001600160401b0302191690836001600160401b031602179055506060820151815f0160186101000a8154816001600160401b0302191690836001600160401b031602179055506080820151816001015f6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160046101000a8154816001600160601b0302191690836001600160601b0316021790555060c08201518160010160106101000a8154816001600160601b0302191690836001600160601b0316021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff160217905550610100820151816002015f6101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548160ff0219169083151502179055506101608201518160020160096101000a81548160ff02191690836004811115611d6257611d62611ed3565b021790555050506001600160401b038e81165f90815260026020908152604080832080546001600160a01b0319168155600101929092558d8101518e51855186840151878601516060808a01518851948a1685529289169684019690965287168287015290951692850192909252915191926001600160a01b03909116917ffa7633a3a86c17bb543f34ff921690948c9be90209d81eb0fe6af9e0ac51b0709181900360800190a35050505050505050505050505050565b5f546001600160a01b03163314610d765760405163118cdaa760e01b8152336004820152602401610620565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381168114611281575f80fd5b5f8060408385031215611eba575f80fd5b8235611ec581611e95565b946020939093013593505050565b634e487b7160e01b5f52602160045260245ffd5b60058110611f0357634e487b7160e01b5f52602160045260245ffd5b9052565b81516001600160401b0316815261018081016020830151611f3360208401826001600160401b03169052565b506040830151611f4e60408401826001600160401b03169052565b506060830151611f6960608401826001600160401b03169052565b506080830151611f81608084018263ffffffff169052565b5060a0830151611f9c60a08401826001600160601b03169052565b5060c0830151611fb760c08401826001600160601b03169052565b5060e0830151611fcf60e084018263ffffffff169052565b506101008381015163ffffffff908116918401919091526101208085015190911690830152610140808401511515908301526101608084015161201482850182611ee7565b505092915050565b5f805f806080858703121561202f575f80fd5b843561203a81611e95565b966020860135965060408601359560600135945092505050565b6001600160401b0381168114611281575f80fd5b5f805f6060848603121561207a575f80fd5b833561208581612054565b9250602084013561209581611e95565b929592945050506040919091013590565b5f602082840312156120b6575f80fd5b813563ffffffff811681146120c9575f80fd5b9392505050565b8015158114611281575f80fd5b5f805f606084860312156120ef575f80fd5b83356120fa81611e95565b9250602084013591506040840135612111816120d0565b809150509250925092565b5f805f806080858703121561212f575f80fd5b843561213a81612054565b9350602085013561214a81612054565b9250604085013561215a81612054565b9150606085013561216a81612054565b939692955090935050565b5f60208284031215612185575f80fd5b81356120c981611e95565b5f80604083850312156121a1575f80fd5b82356121ac81611e95565b915060208301356121bc816120d0565b809150509250929050565b60208082526015908201527414dd185d1cc81b9bdd081a5b9a5d1a585b1a5e9959605a1b604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b808201808211156105bb576105bb6121f6565b6001600160601b0382811682821603908082111561223d5761223d6121f6565b5092915050565b5f63ffffffff80831681810361225c5761225c6121f6565b6001019392505050565b5f60018201612277576122776121f6565b5060010190565b80820281158282048414176105bb576105bb6121f6565b6001600160401b0381811683821601908082111561223d5761223d6121f6565b80516122c081612054565b919050565b805160ff811681146122c0575f80fd5b80516122c0816120d0565b5f60e082840312156122f0575f80fd5b60405160e081018181106001600160401b038211171561231e57634e487b7160e01b5f52604160045260245ffd5b60405261232a836122b5565b8152612338602084016122b5565b6020820152612349604084016122b5565b604082015261235a606084016122b5565b606082015261236b608084016122c5565b608082015261237c60a084016122c5565b60a082015261238d60c084016122d5565b60c08201529392505050565b60ff8316815260a081016020808301845f5b60048110156123d15781516001600160401b0316835291830191908301906001016123ab565b505050509392505050565b634e487b7160e01b5f52603260045260245ffd5b6001600160601b03818116838216028082169190828114612014576120146121f6565b634e487b7160e01b5f52601260045260245ffd5b5f6001600160601b038084168061244057612440612413565b92169190910492915050565b63ffffffff81811683821601908082111561223d5761223d6121f6565b6001600160f81b031960f896871b8116825294861b8516600182015292851b8416600284015290841b8316600383015290921b16600482015260050190565b805160208201516001600160d81b031980821692919060058310156124d75780818460050360031b1b83161693505b505050919050565b5f826124ed576124ed612413565b500490565b5f805f8060808587031215612505575f80fd5b61250e856122c5565b935061251c602086016122c5565b925061252a604086016122c5565b9150612538606086016122c5565b905092959194509250565b5f60208284031215612553575f80fd5b81516120c9816120d0565b5f6020828403121561256e575f80fd5b81516120c981611e95565b5f60208284031215612589575f80fd5b81516001600160801b03811681146120c9575f80fd5b5f602082840312156125af575f80fd5b81516120c981612054565b5f826125c8576125c8612413565b50069056fea2646970667358221220a504fcbe3e625e8ab219f74c968e6d1d5a0de433160b3e91abd61d5ae67f034b64736f6c63430008140033000000000000000000000000d7fe5c4b54a62d96689138af1348e3af2d9ffb9e
Deployed Bytecode
0x608060405260043610610108575f3560e01c80638da5cb5b11610092578063b339311511610062578063b339311514610351578063e8328503146103a3578063f2fde38b146103ef578063f60ccc861461040e578063f626052e1461042d575f80fd5b80638da5cb5b1461028b57806391f6c658146102a7578063994e4a19146102c6578063996acc9414610324575f80fd5b806352a5f1f8116100d857806352a5f1f8146101cf578063546ef395146101ee5780635ad2dda41461020d578063715018a6146102445780638c7cc5e314610258575f80fd5b80630368516914610113578063085d4883146101485780630954c4781461018757806347ce07cc146101a8575f80fd5b3661010f57005b5f80fd5b34801561011e575f80fd5b5061013261012d366004611ea9565b61044c565b60405161013f9190611f07565b60405180910390f35b348015610153575f80fd5b5061016f7352deaa1c84233f7bb8c8a45baede41091c61650681565b6040516001600160a01b03909116815260200161013f565b348015610192575f80fd5b506101a66101a136600461201c565b6105c1565b005b3480156101b3575f80fd5b5061016f7336825bf3fbdf5a29e2d5148bfe7dcf7b5639e32081565b3480156101da575f80fd5b506101a66101e9366004612068565b61077b565b3480156101f9575f80fd5b506101a6610208366004611ea9565b6107fc565b348015610218575f80fd5b5061022c6102273660046120a6565b610d3c565b6040516001600160601b03909116815260200161013f565b34801561024f575f80fd5b506101a6610d65565b348015610263575f80fd5b5061016f7f000000000000000000000000d7fe5c4b54a62d96689138af1348e3af2d9ffb9e81565b348015610296575f80fd5b505f546001600160a01b031661016f565b3480156102b2575f80fd5b506101a66102c13660046120dd565b610d78565b3480156102d1575f80fd5b506103146102e0366004611ea9565b6001600160a01b03919091165f9081526001602090815260408083209383529290522060020154600160401b900460ff1690565b604051901515815260200161013f565b34801561032f575f80fd5b50610338610f45565b6040516001600160d81b0319909116815260200161013f565b34801561035c575f80fd5b5061037061036b366004611ea9565b610f7e565b604080516001600160401b039586168152938516602085015291841691830191909152909116606082015260800161013f565b3480156103ae575f80fd5b506103c26103bd36600461211c565b61119b565b6040805160ff9586168152938516602085015291841691830191909152909116606082015260800161013f565b3480156103fa575f80fd5b506101a6610409366004612175565b611247565b348015610419575f80fd5b506101a6610428366004612190565b611284565b348015610438575f80fd5b506101a6610447366004611ea9565b61130c565b6104b060408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290529061016082015290565b6001600160a01b0383165f90815260016020818152604080842086855282529283902083516101808101855281546001600160401b038082168352600160401b808304821695840195909552600160801b808304821697840197909752600160c01b9091041660608201529281015463ffffffff80821660808601526001600160601b03600160201b808404821660a08801529683041660c0860152600160e01b909104811660e085015260028201548082166101008601529485041661012084015260ff918404821615156101408401529192610160840191600160481b9091041660048111156105a4576105a4611ed3565b60048111156105b5576105b5611ed3565b90525090505b92915050565b5f546001600160a01b03163314806105e75750335f9081526003602052604090205460ff165b6106295760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b60448201526064015b60405180910390fd5b6001600160a01b0384165f908152600160209081526040808320868452909152902060020154600160401b900460ff166106755760405162461bcd60e51b8152600401610620906121c7565b6001600160a01b0384165f9081526001602081815260408084208785529091528220908101549091906106b9908590600160201b90046001600160601b031661220a565b6001830180546fffffffffffffffffffffffff000000001916600160201b6001600160601b0384168102919091179091556002840154919250610705918591900463ffffffff1661220a565b60028301805463ffffffff92909216600160201b0267ffffffff0000000019909216919091179055604080518581526020810183905286916001600160a01b038916917f1cfcc60a52168386067c020abab02289b7dee02c9a7e9690aeff3c3aa53e24a8910160405180910390a3505050505050565b7336825bf3fbdf5a29e2d5148bfe7dcf7b5639e3203381146107eb5760405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920456e74726f70792063616e2063616c6c20746869732066756e637460448201526234b7b760e91b6064820152608401610620565b6107f68484846116bb565b50505050565b6001600160a01b0382165f908152600160209081526040808320848452909152902060020154600160401b900460ff166108485760405162461bcd60e51b8152600401610620906121c7565b6001600160a01b0382165f908152600160208181526040808420858552909152909120908101546001600160601b03600160201b8204811691600160801b81049091169063ffffffff16818310156108d45760405162461bcd60e51b815260206004820152600f60248201526e0496e73756666696369656e7420585608c1b6044820152606401610620565b5f5b826001600160601b0316846001600160601b031610610926576108f9838561221d565b93508161090581612244565b925050808061091390612266565b91505061091f82610d3c565b92506108d6565b5f805f806109348b8b610f7e565b935093509350935084846001600160401b0316610951919061227e565b9350610966856001600160401b03851661227e565b925061097b856001600160401b03841661227e565b9150610990856001600160401b03831661227e565b60408051608081019091528a549192505f9181906109b89088906001600160401b0316612295565b6001600160401b0390811682528c546020909201916109e0918891600160401b900416612295565b6001600160401b0390811682528c54602090920191610a08918791600160801b900416612295565b6001600160401b0390811682528c54602090920191610a30918691600160c01b900416612295565b6001600160401b03169052604051631cc6f28360e31b81526001600160a01b038e81166004830152919250736e9a7a68ae6b4b27d9d5494c034939c52a49b6509163baae97e5917f000000000000000000000000d7fe5c4b54a62d96689138af1348e3af2d9ffb9e9091169063e63794189060240160e060405180830381865afa158015610ac0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ae491906122e0565b60800151836040518363ffffffff1660e01b8152600401610b06929190612399565b5f6040518083038186803b158015610b1c575f80fd5b505af4158015610b2e573d5f803e3d5ffd5b50505050805f60048110610b4457610b446123dc565b60200201518a5467ffffffffffffffff19166001600160401b03909116178a5580600160200201518a546001600160401b03909116600160401b026fffffffffffffffff000000000000000019909116178a5580600260200201518a546001600160401b03909116600160801b0267ffffffffffffffff60801b19909116178a5580600360200201518a546001600160401b03909116600160c01b026001600160c01b03909116178a5560018a0180546001600160601b038b8116600160201b026fffffffffffffffffffffffff0000000019918c16600160801b027fffffffff000000000000000000000000ffffffffffffffffffffffff0000000090931663ffffffff8c161792909217161790556040518b906001600160a01b038e16907feec61667dd6eeecdccfef3c906e0fd047cca672804901ac4254d8545e9a426d490610c9d908b9063ffffffff91909116815260200190565b60405180910390a38a6001600160a01b038d167f8def189a8e735301f41e5cb70b3fa998ce66011c168203e4039996309d49237c835f6020020151846001602002015185600260200201518660036020020151604051610d2694939291906001600160401b03948516815292841660208401529083166040830152909116606082015260800190565b60405180910390a3505050505050505050505050565b5f6064610d50609663ffffffff85166123f0565b610d5a9190612427565b6105bb9060646123f0565b610d6d611e1a565b610d765f611e46565b565b5f546001600160a01b0316331480610d9e5750335f9081526003602052604090205460ff165b610ddb5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606401610620565b6001600160a01b0383165f908152600160209081526040808320858452909152902060020154600160401b900460ff16610e275760405162461bcd60e51b8152600401610620906121c7565b6001600160a01b0383165f9081526001602081815260408084208685529091529091208082018054919291601c90610e6d908490600160e01b900463ffffffff1661244c565b92506101000a81548163ffffffff021916908363ffffffff1602179055508115610ecd57600281018054600191905f90610eae90849063ffffffff1661244c565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b60028101546001820154604080518515158152600160201b9384900463ffffffff166020820152929091046001600160601b03169082015283906001600160a01b038616907fe6ce2da96a964985bd161cb1f6b383b07d1f2fed13aef14028de4503dfeb81d29060600160405180910390a350505050565b600a6014601e60326064604051602001610f63959493929190612469565b604051602081830303815290604052610f7b906124a8565b81565b6001600160a01b0382165f908152600160209081526040808320848452909152812060020154819081908190600160401b900460ff16610fd05760405162461bcd60e51b8152600401610620906121c7565b6001600160a01b0386165f908152600160208181526040808420898552825280842081516101808101835281546001600160401b038082168352600160401b808304821696840196909652600160801b808304821695840195909552600160c01b9091041660608201529381015463ffffffff80821660808701526001600160601b03600160201b808404821660a08901529483041660c0870152600160e01b909104811660e086015260028201548082166101008701529283041661012085015260ff9282048316151561014085015291610160840191600160481b90041660048111156110c1576110c1611ed3565b60048111156110d2576110d2611ed3565b90525080519091506064906110f2906005906001600160401b031661227e565b6110fc91906124df565b9450606460056001600160601b031682602001516001600160401b0316611123919061227e565b61112d91906124df565b9350606460056001600160601b031682604001516001600160401b0316611154919061227e565b61115e91906124df565b9250606460056001600160601b031682606001516001600160401b0316611185919061227e565b61118f91906124df565b91505092959194509250565b604051636007a06360e01b81526001600160401b03808616600483015280851660248301528084166044830152821660648201525f908190819081907340bc4d559834f72951a83a8e098a6b969f1c79a890636007a06390608401608060405180830381865af4158015611211573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061123591906124f2565b929b919a509850909650945050505050565b61124f611e1a565b6001600160a01b03811661127857604051631e4fbdf760e01b81525f6004820152602401610620565b61128181611e46565b50565b61128c611e1a565b6001600160a01b0382166112e25760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420636f6e7472616374206164647265737300000000000000006044820152606401610620565b6001600160a01b03919091165f908152600360205260409020805460ff1916911515919091179055565b6001600160a01b0382165f908152600160209081526040808320848452909152902060020154600160401b900460ff161561137f5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606401610620565b604051633af32abf60e01b81526001600160a01b0383811660048301527f000000000000000000000000d7fe5c4b54a62d96689138af1348e3af2d9ffb9e1690633af32abf90602401602060405180830381865afa1580156113e3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114079190612543565b6114535760405162461bcd60e51b815260206004820152601a60248201527f436f6c6c656374696f6e206e6f742077686974656c69737465640000000000006044820152606401610620565b6040516331a9108f60e11b8152600481018290526001600160a01b03831690636352211e90602401602060405180830381865afa9250505080156114b4575060408051601f3d908101601f191682019092526114b19181019061255e565b60015b6114f55760405162461bcd60e51b815260206004820152601260248201527113919508191bd95cc81b9bdd08195e1a5cdd60721b6044820152606401610620565b506040805142602082015243918101919091526001600160a01b0383166060820152608081018290525f9060a00160408051808303601f19018152908290528051602090910120631711922960e31b82527352deaa1c84233f7bb8c8a45baede41091c616506600483015291505f907336825bf3fbdf5a29e2d5148bfe7dcf7b5639e3209063b88c914890602401602060405180830381865afa15801561159e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c29190612579565b6040516319cb825f60e01b81527352deaa1c84233f7bb8c8a45baede41091c6165066004820152602481018490529091505f907336825bf3fbdf5a29e2d5148bfe7dcf7b5639e320906319cb825f906001600160801b0385169060440160206040518083038185885af115801561163b573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190611660919061259f565b6040805180820182526001600160a01b03978816815260208082019788526001600160401b03939093165f90815260029093529120905181546001600160a01b03191696169590951785555050905160019092019190915550565b6001600160401b0383165f9081526002602090815260408083208151808301835281546001600160a01b03908116808352600190930154948201949094529151631cc6f28360e31b815260048101919091529092917f000000000000000000000000d7fe5c4b54a62d96689138af1348e3af2d9ffb9e169063e63794189060240160e060405180830381865afa158015611757573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061177b91906122e0565b9050825f61178d606460ff84166125ba565b90505f60028210156117a1575060046117d7565b600a8210156117b2575060036117d7565b601e8210156117c3575060026117d7565b60328210156117d4575060016117d7565b505f5b5f600a6014601e603260646040516020016117f6959493929190612469565b60405160208183030381529060405261180e906124a8565b8260ff1660058110611822576118226123dc565b865191901a91505f9061639c9060ff8716906118489085906001600160401b031661227e565b611852919061227e565b61185c91906124df565b90505f61639c600887901c60ff168460ff1689602001516001600160401b0316611886919061227e565b611890919061227e565b61189a91906124df565b90505f61639c601088901c60ff168560ff168a604001516001600160401b03166118c4919061227e565b6118ce919061227e565b6118d891906124df565b90505f61639c601889901c60ff168660ff168b606001516001600160401b0316611902919061227e565b61190c919061227e565b61191691906124df565b90505f6040518060800160405280868c5f01516119339190612295565b6001600160401b03166001600160401b03168152602001858c6020015161195a9190612295565b6001600160401b03166001600160401b03168152602001848c604001516119819190612295565b6001600160401b03166001600160401b03168152602001838c606001516119a89190612295565b6001600160401b0316905260808b015160405163baae97e560e01b8152919250736e9a7a68ae6b4b27d9d5494c034939c52a49b6509163baae97e5916119f2918590600401612399565b5f6040518083038186803b158015611a08575f80fd5b505af4158015611a1a573d5f803e3d5ffd5b50505050604051806101800160405280825f60048110611a3c57611a3c6123dc565b60200201516001600160401b0316815260200182600160048110611a6257611a626123dc565b60200201516001600160401b0316815260200182600260048110611a8857611a886123dc565b60200201516001600160401b0316815260200182600360048110611aae57611aae6123dc565b60200201516001600160401b03168152602001600163ffffffff1681526020015f6001600160601b03168152602001611ae76001610d3c565b6001600160601b031681525f602082018190526040820181905260608201526001608082015260a00160ff89166004811115611b2557611b25611ed3565b6004811115611b3657611b36611ed3565b81525060015f8d5f01516001600160a01b03166001600160a01b031681526020019081526020015f205f8d6020015181526020019081526020015f205f820151815f015f6101000a8154816001600160401b0302191690836001600160401b031602179055506020820151815f0160086101000a8154816001600160401b0302191690836001600160401b031602179055506040820151815f0160106101000a8154816001600160401b0302191690836001600160401b031602179055506060820151815f0160186101000a8154816001600160401b0302191690836001600160401b031602179055506080820151816001015f6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160046101000a8154816001600160601b0302191690836001600160601b0316021790555060c08201518160010160106101000a8154816001600160601b0302191690836001600160601b0316021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff160217905550610100820151816002015f6101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548160ff0219169083151502179055506101608201518160020160096101000a81548160ff02191690836004811115611d6257611d62611ed3565b021790555050506001600160401b038e81165f90815260026020908152604080832080546001600160a01b0319168155600101929092558d8101518e51855186840151878601516060808a01518851948a1685529289169684019690965287168287015290951692850192909252915191926001600160a01b03909116917ffa7633a3a86c17bb543f34ff921690948c9be90209d81eb0fe6af9e0ac51b0709181900360800190a35050505050505050505050505050565b5f546001600160a01b03163314610d765760405163118cdaa760e01b8152336004820152602401610620565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381168114611281575f80fd5b5f8060408385031215611eba575f80fd5b8235611ec581611e95565b946020939093013593505050565b634e487b7160e01b5f52602160045260245ffd5b60058110611f0357634e487b7160e01b5f52602160045260245ffd5b9052565b81516001600160401b0316815261018081016020830151611f3360208401826001600160401b03169052565b506040830151611f4e60408401826001600160401b03169052565b506060830151611f6960608401826001600160401b03169052565b506080830151611f81608084018263ffffffff169052565b5060a0830151611f9c60a08401826001600160601b03169052565b5060c0830151611fb760c08401826001600160601b03169052565b5060e0830151611fcf60e084018263ffffffff169052565b506101008381015163ffffffff908116918401919091526101208085015190911690830152610140808401511515908301526101608084015161201482850182611ee7565b505092915050565b5f805f806080858703121561202f575f80fd5b843561203a81611e95565b966020860135965060408601359560600135945092505050565b6001600160401b0381168114611281575f80fd5b5f805f6060848603121561207a575f80fd5b833561208581612054565b9250602084013561209581611e95565b929592945050506040919091013590565b5f602082840312156120b6575f80fd5b813563ffffffff811681146120c9575f80fd5b9392505050565b8015158114611281575f80fd5b5f805f606084860312156120ef575f80fd5b83356120fa81611e95565b9250602084013591506040840135612111816120d0565b809150509250925092565b5f805f806080858703121561212f575f80fd5b843561213a81612054565b9350602085013561214a81612054565b9250604085013561215a81612054565b9150606085013561216a81612054565b939692955090935050565b5f60208284031215612185575f80fd5b81356120c981611e95565b5f80604083850312156121a1575f80fd5b82356121ac81611e95565b915060208301356121bc816120d0565b809150509250929050565b60208082526015908201527414dd185d1cc81b9bdd081a5b9a5d1a585b1a5e9959605a1b604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b808201808211156105bb576105bb6121f6565b6001600160601b0382811682821603908082111561223d5761223d6121f6565b5092915050565b5f63ffffffff80831681810361225c5761225c6121f6565b6001019392505050565b5f60018201612277576122776121f6565b5060010190565b80820281158282048414176105bb576105bb6121f6565b6001600160401b0381811683821601908082111561223d5761223d6121f6565b80516122c081612054565b919050565b805160ff811681146122c0575f80fd5b80516122c0816120d0565b5f60e082840312156122f0575f80fd5b60405160e081018181106001600160401b038211171561231e57634e487b7160e01b5f52604160045260245ffd5b60405261232a836122b5565b8152612338602084016122b5565b6020820152612349604084016122b5565b604082015261235a606084016122b5565b606082015261236b608084016122c5565b608082015261237c60a084016122c5565b60a082015261238d60c084016122d5565b60c08201529392505050565b60ff8316815260a081016020808301845f5b60048110156123d15781516001600160401b0316835291830191908301906001016123ab565b505050509392505050565b634e487b7160e01b5f52603260045260245ffd5b6001600160601b03818116838216028082169190828114612014576120146121f6565b634e487b7160e01b5f52601260045260245ffd5b5f6001600160601b038084168061244057612440612413565b92169190910492915050565b63ffffffff81811683821601908082111561223d5761223d6121f6565b6001600160f81b031960f896871b8116825294861b8516600182015292851b8416600284015290841b8316600383015290921b16600482015260050190565b805160208201516001600160d81b031980821692919060058310156124d75780818460050360031b1b83161693505b505050919050565b5f826124ed576124ed612413565b500490565b5f805f8060808587031215612505575f80fd5b61250e856122c5565b935061251c602086016122c5565b925061252a604086016122c5565b9150612538606086016122c5565b905092959194509250565b5f60208284031215612553575f80fd5b81516120c9816120d0565b5f6020828403121561256e575f80fd5b81516120c981611e95565b5f60208284031215612589575f80fd5b81516001600160801b03811681146120c9575f80fd5b5f602082840312156125af575f80fd5b81516120c981612054565b5f826125c8576125c8612413565b50069056fea2646970667358221220a504fcbe3e625e8ab219f74c968e6d1d5a0de433160b3e91abd61d5ae67f034b64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d7fe5c4b54a62d96689138af1348e3af2d9ffb9e
-----Decoded View---------------
Arg [0] : _collectionRegistry (address): 0xD7FE5c4B54a62d96689138af1348e3aF2D9fFb9E
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d7fe5c4b54a62d96689138af1348e3af2d9ffb9e
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
APE | 100.00% | $0.504965 | 0.0189 | $0.009519 |
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.