GLMR Price: $0.019055 (-0.01%)

Contract

0xDF9210896f0353745D9F25F6B49090CBE1C95aA8

Overview

GLMR Balance

Moonbeam Chain LogoMoonbeam Chain LogoMoonbeam Chain Logo0 GLMR

GLMR Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Set Custom Name57863662024-03-23 13:08:42678 days ago1711199322IN
0xDF921089...BE1C95aA8
0 GLMR0.0526559221.12435522
Set Custom Name56973622024-03-10 23:39:42690 days ago1710113982IN
0xDF921089...BE1C95aA8
0 GLMR0.03593679151
Set Custom Name56815822024-03-08 18:23:06692 days ago1709922186IN
0xDF921089...BE1C95aA8
0 GLMR0.04284267179.9144982
Set Custom Name56815792024-03-08 18:22:30692 days ago1709922150IN
0xDF921089...BE1C95aA8
0 GLMR0.04290187180.16310352
Set Custom Name56815782024-03-08 18:22:18692 days ago1709922138IN
0xDF921089...BE1C95aA8
0 GLMR0.04291683180.22592641
Set Custom Name56815762024-03-08 18:21:54692 days ago1709922114IN
0xDF921089...BE1C95aA8
0 GLMR0.043224181.51582982
Set Custom Name56815752024-03-08 18:21:42692 days ago1709922102IN
0xDF921089...BE1C95aA8
0 GLMR0.04293064180.28390286
Set Custom Name56738872024-03-07 16:21:36693 days ago1709828496IN
0xDF921089...BE1C95aA8
0 GLMR0.04480546188.15708144
Set Custom Name56738712024-03-07 16:18:24693 days ago1709828304IN
0xDF921089...BE1C95aA8
0 GLMR0.04451541186.93899992
Set Custom Name56738512024-03-07 16:14:00693 days ago1709828040IN
0xDF921089...BE1C95aA8
0 GLMR0.04415582185.42893715
Set Custom Name56738032024-03-07 16:04:24694 days ago1709827464IN
0xDF921089...BE1C95aA8
0 GLMR0.04500007188.97430414
Set Custom Name56662272024-03-06 14:14:48695 days ago1709734488IN
0xDF921089...BE1C95aA8
0 GLMR0.05691321239.00260777
Set Custom Name56662262024-03-06 14:14:36695 days ago1709734476IN
0xDF921089...BE1C95aA8
0 GLMR0.05695084239.1606373
Set Custom Name56662252024-03-06 14:14:24695 days ago1709734464IN
0xDF921089...BE1C95aA8
0 GLMR0.05701432239.42722215
Set Custom Name56662252024-03-06 14:14:24695 days ago1709734464IN
0xDF921089...BE1C95aA8
0 GLMR0.05701432239.42722215
Set Custom Name56106442024-02-27 16:43:54702 days ago1709052234IN
0xDF921089...BE1C95aA8
0 GLMR0.03613288151.73725025
Set Custom Name56100272024-02-27 14:37:18703 days ago1709044638IN
0xDF921089...BE1C95aA8
0 GLMR0.04611105193.63979511
Set Custom Name56100082024-02-27 14:32:54703 days ago1709044374IN
0xDF921089...BE1C95aA8
0 GLMR0.03913871164.35999707
Set Custom Name54086402024-01-30 2:04:51731 days ago1706580291IN
0xDF921089...BE1C95aA8
0 GLMR0.03061921128.5829921
Set Custom Name53845642024-01-26 16:26:00734 days ago1706286360IN
0xDF921089...BE1C95aA8
0 GLMR0.03087912129.67447418
Set Custom Name53845592024-01-26 16:25:00734 days ago1706286300IN
0xDF921089...BE1C95aA8
0 GLMR0.03090325129.7758337
Set Custom Name53845552024-01-26 16:24:12734 days ago1706286252IN
0xDF921089...BE1C95aA8
0 GLMR0.03092653129.87357041
Set Custom Name53845512024-01-26 16:23:24734 days ago1706286204IN
0xDF921089...BE1C95aA8
0 GLMR0.03097368130.07157332
Set Custom Name53845502024-01-26 16:23:12734 days ago1706286192IN
0xDF921089...BE1C95aA8
0 GLMR0.03097084130.05964117
Set Custom Name53845462024-01-26 16:22:24734 days ago1706286144IN
0xDF921089...BE1C95aA8
0 GLMR0.03096419130.0317287
View all transactions

View more zero value Internal Transactions in Advanced View mode

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AttributesManager

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.21;

import "@rmrk-team/evm-contracts/contracts/RMRK/extension/tokenAttributes/IERC7508.sol";
import "@rmrk-team/evm-contracts/contracts/RMRK/access/Ownable.sol";
import "@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC7401.sol";
import "@rmrk-team/evm-contracts/contracts/RMRK/equippable/IERC6220.sol";
import "./INameChangeTicket.sol";

error BattleNotFinished();
error CannotChallengeYourself();
error CannotChangeName();
error CannotHaveMultipleActiveChallenges();
error InvalidChallenge();
error NameChangeTicketNeeded();
error NotEnoughFreePoints();
error NotEnoughStamina();
error NotOwnedSnake();
error ResultAlreadyStored();

contract AttributesManager is Ownable {
    modifier onlySoldierOwner(uint256 soldierId) {
        _checkSoldierOwner(soldierId);
        _;
    }

    enum Element {
        Fire,
        Earth,
        Water,
        Air,
        None // Needed for enemy element in of case calculating boosts without enemy
    }

    enum Faction {
        Desert,
        Mountain,
        Islands,
        Valley,
        Forest,
        None
    }

    enum Skill {
        Combat,
        Tank,
        Heal,
        Sniper,
        None
    }

    enum Landscape {
        None,
        IslandsDay,
        IslandsNight,
        IslandsEclipse,
        DesertDay,
        DesertNight,
        DesertEclipse,
        ValleyDay,
        ValleyNight,
        ValleyEclipse,
        MountainDay,
        MountainNight,
        MountainEclipse,
        ForestDay,
        ForestNight,
        ForestEclipse
    }

    struct BattleStats {
        uint256 id; // Not stored, just used to identify the soldier
        uint24 attack; // Over 16M
        uint24 defense; // Over 16M
        uint24 health; // Over 16M
        uint24 stamina; // Over 16M
        uint24 maxHealth; // Over 16M
        uint24 maxStamina; // Over 16M
        uint16 level; // Over 65k levels
        uint16 freePoints; // Over 65k
        uint32 experience; // Over 65k levels (XP accumulates)
        uint32 lastStatsUpdate; // Up to year 2106
    }

    struct BattleBoostsPercentage {
        int16 elementElement;
        uint8 elementSkill;
        uint8 elementTerritory;
        uint8 factionTerritory;
        uint8 forest;
        uint8 landscape;
    }

    struct EquippedItems {
        Element element;
        Faction faction;
        Skill skill;
        Landscape landscape;
    }

    string private constant _STATS_KEY = "STATS";
    string private constant _NAME_KEY = "NAME";
    uint256 private constant _COMMANDERS_OFFSET = 20;
    uint256 private constant _SOLDIERS_OFFSET = 200;

    uint256 private _staminaRecoveredPerHour = 2;

    uint8 private _landscapeTerritoryBoost = 5;
    uint8 private _landscapeDaynightBoost = 5;
    uint8 private _elementSkillBoost = 10;
    uint8 private _elementTerritoryBoost = 10;
    uint8 private _factionTerritoryBoost = 10;
    uint8 private _forestBoost = 10;

    address private _snakeSoldiers;
    address private _elementGems;
    address private _skillGems;
    address private _factionGems;
    address private _landscapes;
    INameChangeTicket private _nameChangeTicket;
    IERC7508 private _attributesRepository;

    constructor(
        address snakeSoldiers,
        address elementGems,
        address skillGems,
        address factionGems,
        address landscapes,
        address attributesRepository
    ) {
        _snakeSoldiers = snakeSoldiers;
        _elementGems = elementGems;
        _skillGems = skillGems;
        _factionGems = factionGems;
        _landscapes = landscapes;
        _attributesRepository = IERC7508(attributesRepository);
    }

    // CONFIG GETTERS

    function getBoostsConfig()
        public
        view
        returns (
            uint8 landscapeTerritoryBoost,
            uint8 landscapeDaynightBoost,
            uint8 elementSkillBoost,
            uint8 elementTerritoryBoost,
            uint8 factionTerritoryBoost,
            uint8 forestBoost
        )
    {
        landscapeTerritoryBoost = _landscapeTerritoryBoost;
        landscapeDaynightBoost = _landscapeDaynightBoost;
        elementSkillBoost = _elementSkillBoost;
        elementTerritoryBoost = _elementTerritoryBoost;
        factionTerritoryBoost = _factionTerritoryBoost;
        forestBoost = _forestBoost;
    }

    // CONFIG SETTERS

    function setBoostsConfig(
        uint8 landscapeTerritoryBoost,
        uint8 landscapeDaynightBoost,
        uint8 elementSkillBoost,
        uint8 elementTerritoryBoost,
        uint8 factionTerritoryBoost,
        uint8 forestBoost
    ) public onlyOwner {
        _landscapeTerritoryBoost = landscapeTerritoryBoost;
        _landscapeDaynightBoost = landscapeDaynightBoost;
        _elementSkillBoost = elementSkillBoost;
        _elementTerritoryBoost = elementTerritoryBoost;
        _factionTerritoryBoost = factionTerritoryBoost;
        _forestBoost = forestBoost;
    }

    function setNameChangeTicketAddress(
        address nameChangeTicket
    ) public onlyOwner {
        _nameChangeTicket = INameChangeTicket(nameChangeTicket);
    }

    // STATS

    function getStats(
        uint256 soldierId
    ) public view returns (BattleStats memory stats) {
        uint256 mergedStats = _attributesRepository.getUintAttribute(
            _snakeSoldiers,
            soldierId,
            _STATS_KEY
        );
        stats.id = soldierId;
        stats.attack = uint24(mergedStats);
        stats.defense = uint24(mergedStats >> 24);
        stats.health = uint24(mergedStats >> 48);
        stats.stamina = uint24(mergedStats >> 72);
        stats.maxHealth = uint24(mergedStats >> 96);
        stats.maxStamina = uint24(mergedStats >> 120);
        stats.level = uint16(mergedStats >> 144);
        stats.freePoints = uint16(mergedStats >> 160);
        stats.experience = uint32(mergedStats >> 176);
        stats.lastStatsUpdate = uint32(mergedStats >> 208);

        stats.stamina = getCurrentStamina(stats);
    }

    function getCurrentStamina(
        BattleStats memory stats
    ) public view returns (uint24) {
        if (stats.lastStatsUpdate == 0) {
            return stats.maxStamina;
        }
        uint24 staminaRecovered = uint24(
            ((block.timestamp - stats.lastStatsUpdate) / 3600) *
                _staminaRecoveredPerHour
        );
        if (staminaRecovered + stats.stamina > stats.maxStamina) {
            return stats.maxStamina;
        } else {
            return staminaRecovered + stats.stamina;
        }
    }

    function getBoostedStatsForSnake(
        uint256 soldierId,
        Element enemyElement
    ) external view returns (BattleStats memory boostedStats) {
        BattleStats memory snakeStats = getStats(soldierId);
        EquippedItems memory snakeItems = getEquippedItems(soldierId);
        (
            Faction currentTerritory,
            bool currentDayNight
        ) = getCurrentLandAndDayNight();
        BattleBoostsPercentage
            memory snakeBoosts = getBoostsFromGemsTerritoryAndCelestialPhase(
                snakeItems,
                currentTerritory,
                currentDayNight,
                enemyElement
            );
        boostedStats = applyBoosts(snakeStats, snakeBoosts);
    }

    function getAdjustedStatsForBothSnakes(
        BattleStats memory challengerStats,
        BattleStats memory challengedStats,
        Faction challengeTerritory,
        bool challengeDayNight
    )
        public
        view
        returns (
            BattleStats memory challengerAdjustedStats,
            BattleStats memory challengedAdjustedStats
        )
    {
        EquippedItems memory challengerItems = getEquippedItems(
            challengerStats.id
        );
        EquippedItems memory challengedItems = getEquippedItems(
            challengedStats.id
        );

        BattleBoostsPercentage
            memory challengerBoosts = getBoostsFromGemsTerritoryAndCelestialPhase(
                challengerItems,
                challengeTerritory,
                challengeDayNight,
                challengedItems.element
            );
        BattleBoostsPercentage
            memory challengedBoosts = getBoostsFromGemsTerritoryAndCelestialPhase(
                challengedItems,
                challengeTerritory,
                challengeDayNight,
                challengerItems.element
            );

        challengerAdjustedStats = applyBoosts(
            challengerStats,
            challengerBoosts
        );
        challengedAdjustedStats = applyBoosts(
            challengedStats,
            challengedBoosts
        );
    }

    function getCurrentLandAndDayNight()
        public
        view
        returns (Faction currentLand, bool currentDayNight)
    {
        // Every 12 hours, the land changes
        // Every 6 hours, the day/night changes
        currentDayNight = (block.timestamp / 21600) % 2 == 0;
        currentLand = Faction((block.timestamp / 43200) % 5);
    }

    // NAME

    function getCustomName(
        uint256 soldierId
    ) public view returns (string memory) {
        return
            IERC7508(_attributesRepository).getStringAttribute(
                _snakeSoldiers,
                soldierId,
                _NAME_KEY
            );
    }

    function setCustomName(
        uint256 soldierId,
        string memory name
    ) external onlySoldierOwner(soldierId) {
        string memory curentName = getCustomName(soldierId);
        if (bytes(curentName).length > 0) {
            if (address(_nameChangeTicket) == address(0))
                revert CannotChangeName();
            if (_nameChangeTicket.balanceOf(msg.sender) == 0)
                revert NameChangeTicketNeeded();

            _nameChangeTicket.useTicket(msg.sender);
        }
        IERC7508(_attributesRepository).setStringAttribute(
            _snakeSoldiers,
            soldierId,
            _NAME_KEY,
            name
        );
    }

    // BOOSTS

    function getBoostsForSnake(
        uint256 soldierId,
        Element enemyElement
    ) external view returns (BattleBoostsPercentage memory boosts) {
        EquippedItems memory items = getEquippedItems(soldierId);
        (
            Faction challengeTerritory,
            bool challengeDayNight
        ) = getCurrentLandAndDayNight();
        boosts = getBoostsFromGemsTerritoryAndCelestialPhase(
            items,
            challengeTerritory,
            challengeDayNight,
            enemyElement
        );
    }

    function getBoostsFromGemsTerritoryAndCelestialPhase(
        EquippedItems memory items,
        Faction challengeTerritory,
        bool challengeDayNight,
        Element enemyElement
    ) public pure returns (BattleBoostsPercentage memory boosts) {
        boosts.elementSkill = getElementSkillBoost(items.element, items.skill);
        boosts.factionTerritory = getFactionTerritoryBoost(
            items.faction,
            challengeTerritory
        );
        boosts.elementTerritory = getElementTerritoryBoost(
            items.element,
            challengeTerritory
        );
        boosts.forest = getForestBoost(items.faction);
        boosts.elementElement = getFightingElementsBoost(
            items.element,
            enemyElement
        );
        boosts.landscape = getLandscapeBoost(
            items.landscape,
            challengeTerritory,
            challengeDayNight
        );
    }

    function applyBoosts(
        BattleStats memory stats,
        BattleBoostsPercentage memory boosts
    ) public pure returns (BattleStats memory adjustedStats) {
        adjustedStats = stats;
        uint256 baseAttackBoost = uint256(uint16(100 + boosts.elementElement));
        uint256 attackBoosts = baseAttackBoost +
            boosts.elementSkill +
            boosts.elementTerritory +
            boosts.landscape +
            boosts.forest;
        uint256 defenseBoosts = 100 +
            boosts.factionTerritory +
            boosts.landscape +
            boosts.forest;
        adjustedStats.attack = uint24((stats.attack * attackBoosts) / 100);
        adjustedStats.defense = uint24((stats.defense * defenseBoosts) / 100);
    }

    function getElementTerritoryBoost(
        Element element,
        Faction territory
    ) public pure returns (uint8) {
        if (uint256(element) == uint256(territory) && element != Element.None)
            return 10;
        else return 0;
    }

    function getForestBoost(Faction faction) public pure returns (uint8) {
        if (faction == Faction.Forest) {
            return 10;
        } else {
            return 0;
        }
    }

    function getElementSkillBoost(
        Element element,
        Skill skill
    ) public pure returns (uint8) {
        if (uint8(element) == uint8(skill) && element != Element.None) {
            return 10;
        } else {
            return 0;
        }
    }

    function getFightingElementsBoost(
        Element elementA,
        Element elementB
    ) public pure returns (int16) {
        if (elementB == Element.None) {
            // Not calculating with enemy
            return 0;
        } else if (elementA == Element.Fire && elementB == Element.Air) {
            // Fire->Air: +30%
            return 30;
        } else if (elementA == Element.Fire && elementB == Element.Earth) {
            // Fire->Earth: -5%
            return -5;
        } else if (elementA == Element.Fire && elementB == Element.Water) {
            // Fire->Water: 0%
            return 0;
        } else if (elementA == Element.Air && elementB == Element.Fire) {
            // Air->Fire: -10%
            return -10;
        } else if (elementA == Element.Air && elementB == Element.Earth) {
            // Air->Earth: +25%
            return 25;
        } else if (elementA == Element.Air && elementB == Element.Water) {
            // Air->Water: 0%
            return 0;
        } else if (elementA == Element.Earth && elementB == Element.Fire) {
            // Earth->Fire: +10%
            return 10;
        } else if (elementA == Element.Earth && elementB == Element.Air) {
            // Earth->Air: -20%
            return -20;
        } else if (elementA == Element.Earth && elementB == Element.Water) {
            // Earth->Water: +20%
            return 20;
        } else if (elementA == Element.Water && elementB == Element.Fire) {
            // Water->Fire: +25%
            return 25;
        } else if (elementA == Element.Water && elementB == Element.Air) {
            // Water->Air: +5%
            return 5;
        } else if (elementA == Element.Water && elementB == Element.Earth) {
            // Water->Earth: -10%
            return -10;
        } else {
            // Same element: -20%, -20%
            return -20;
        }
    }

    function getLandscapeBoost(
        Landscape landscape,
        Faction challengeTerritory,
        bool challengeDayNight
    ) public pure returns (uint8 boost) {
        if (
            challengeTerritory == Faction.Desert &&
            (landscape == Landscape.DesertDay ||
                landscape == Landscape.DesertNight ||
                landscape == Landscape.DesertEclipse)
        ) boost += 5;
        else if (
            challengeTerritory == Faction.Forest &&
            (landscape == Landscape.ForestDay ||
                landscape == Landscape.ForestNight ||
                landscape == Landscape.ForestEclipse)
        ) boost += 5;
        else if (
            challengeTerritory == Faction.Islands &&
            (landscape == Landscape.IslandsDay ||
                landscape == Landscape.IslandsNight ||
                landscape == Landscape.IslandsEclipse)
        ) boost += 5;
        else if (
            challengeTerritory == Faction.Mountain &&
            (landscape == Landscape.MountainDay ||
                landscape == Landscape.MountainNight ||
                landscape == Landscape.MountainEclipse)
        ) boost += 5;
        else if (
            challengeTerritory == Faction.Valley &&
            (landscape == Landscape.ValleyDay ||
                landscape == Landscape.ValleyNight ||
                landscape == Landscape.ValleyEclipse)
        ) boost += 5;

        if (
            landscape == Landscape.DesertEclipse ||
            landscape == Landscape.ForestEclipse ||
            landscape == Landscape.IslandsEclipse ||
            landscape == Landscape.MountainEclipse ||
            landscape == Landscape.ValleyEclipse
        ) boost += 5;
        else if (
            challengeDayNight &&
            (landscape == Landscape.DesertDay ||
                landscape == Landscape.ForestDay ||
                landscape == Landscape.IslandsDay ||
                landscape == Landscape.MountainDay ||
                landscape == Landscape.ValleyDay)
        ) boost += 5;
        else if (
            !challengeDayNight &&
            (landscape == Landscape.DesertNight ||
                landscape == Landscape.ForestNight ||
                landscape == Landscape.IslandsNight ||
                landscape == Landscape.MountainNight ||
                landscape == Landscape.ValleyNight)
        ) boost += 5;
    }

    function getFactionTerritoryBoost(
        Faction faction,
        Faction territory
    ) public pure returns (uint8) {
        if (faction == territory && faction != Faction.None) return 10;
        else return 0;
    }

    // INIT STATS

    function batchSetStats(BattleStats[] memory allStats) public onlyOwner {
        for (uint256 i; i < allStats.length; ) {
            _storeStats(allStats[i], false);
            unchecked {
                ++i;
            }
        }
    }

    // OTHER

    function getEquippedItems(
        uint256 soldierId
    ) public view returns (EquippedItems memory items) {
        IERC7401.Child[] memory children = IERC7401(_snakeSoldiers).childrenOf(
            soldierId
        );
        uint256 length = children.length;
        for (uint256 i; i < length; ) {
            IERC7401.Child memory child = children[i];
            if (
                IERC6220(_snakeSoldiers).isChildEquipped(
                    soldierId,
                    child.contractAddress,
                    child.tokenId
                )
            ) {
                // Only consider equipped
                if (child.contractAddress == _elementGems) {
                    items.element = Element(child.tokenId % 4);
                } else if (child.contractAddress == _skillGems) {
                    if (child.tokenId > _SOLDIERS_OFFSET) {
                        items.skill = Skill((child.tokenId % 8) / 2);
                    } else {
                        // For generals and commanders, we ensure the skills match the elements:
                        items.skill = Skill(child.tokenId % 4);
                    }
                } else if (child.contractAddress == _factionGems) {
                    if (child.tokenId > _COMMANDERS_OFFSET) {
                        items.faction = Faction(child.tokenId % 5);
                    } else {
                        // For generals, we ensure the faction match the elements
                        items.faction = Faction(child.tokenId % 4);
                    }
                } else if (child.contractAddress == _landscapes) {
                    uint64[] memory assetIds = IERC5773(_landscapes)
                        .getActiveAssets(child.tokenId);
                    items.landscape = Landscape(assetIds[0]);
                }
            }
            unchecked {
                ++i;
            }
        }
    }

    function useFreePoints(
        uint256 soldierId,
        uint24 attack,
        uint24 defense,
        uint24 maxHealth,
        uint24 maxStamina
    ) external onlySoldierOwner(soldierId) returns (BattleStats memory stats) {
        stats = getStats(soldierId);
        uint24 usedPoints = attack + defense + maxHealth + maxStamina;

        if (usedPoints > stats.freePoints) revert NotEnoughFreePoints();

        stats.attack += attack;
        stats.defense += defense;
        stats.maxHealth += maxHealth;
        stats.maxStamina += maxStamina;

        _storeStats(stats, false);
    }

    // INTERNAL HELPERS

    function _storeStats(
        BattleStats memory stats,
        bool updateLevelAndFreePoints
    ) private {
        if (updateLevelAndFreePoints) {
            if (uint32((stats.level + 1) * stats.level) > stats.experience) {
                stats.level += 1;
                stats.freePoints += _freePointsForLevel(stats.level);
            }
        }
        _attributesRepository.setUintAttribute(
            _snakeSoldiers,
            stats.id,
            _STATS_KEY,
            _mergeStats(stats)
        );
    }

    function _freePointsForLevel(
        uint16 level
    ) private pure returns (uint16 freePoints) {
        while (level != 0) {
            unchecked {
                freePoints++;
            }
            level >>= level;
        }
    }

    function _mergeStats(
        BattleStats memory stats
    ) private pure returns (uint256 mergedStats) {
        mergedStats = stats.attack;
        mergedStats |= uint256(stats.defense) << 24; // 24 bits offset
        mergedStats |= uint256(stats.health) << 48; // 24 bits offset
        mergedStats |= uint256(stats.stamina) << 72; // 24 bits offset
        mergedStats |= uint256(stats.maxHealth) << 96; // 24 bits offset
        mergedStats |= uint256(stats.maxStamina) << 120; // 24 bits offset
        mergedStats |= uint256(stats.level) << 144; // 24 bits offset
        mergedStats |= uint256(stats.freePoints) << 160; // 16 bits offset
        mergedStats |= uint256(stats.experience) << 176; // 16 bits offset
        mergedStats |= uint256(stats.lastStatsUpdate) << 208; // 32 bits offset
    }

    function _checkSoldierOwner(uint256 soldierId) private view {
        address owner = IERC7401(_snakeSoldiers).ownerOf(soldierId);
        if (owner != msg.sender) {
            revert NotOwnedSnake();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface 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[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.21;

import "@openzeppelin/contracts/utils/Context.sol";
import "../library/RMRKErrors.sol";

/**
 * @title Ownable
 * @author RMRK team
 * @notice A minimal ownable smart contractf or owner and contributors.
 * @dev This smart contract is based on "openzeppelin's access/Ownable.sol".
 */
contract Ownable is Context {
    address private _owner;
    mapping(address => uint256) private _contributors;

    /**
     * @notice Used to anounce the transfer of ownership.
     * @param previousOwner Address of the account that transferred their ownership role
     * @param newOwner Address of the account receiving the ownership role
     */
    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    /**
     * @notice Event that signifies that an address was granted contributor role or that the permission has been
     *  revoked.
     * @dev This can only be triggered by a current owner, so there is no need to include that information in the event.
     * @param contributor Address of the account that had contributor role status updated
     * @param isContributor A boolean value signifying whether the role has been granted (`true`) or revoked (`false`)
     */
    event ContributorUpdate(address indexed contributor, bool isContributor);

    /**
     * @dev Reverts if called by any account other than the owner or an approved contributor.
     */
    modifier onlyOwnerOrContributor() {
        _onlyOwnerOrContributor();
        _;
    }

    /**
     * @dev Reverts if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _onlyOwner();
        _;
    }

    /**
     * @dev Initializes the contract by setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @notice Returns the address of the current owner.
     * @return Address of the current owner
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @notice Leaves the contract without owner. Functions using the `onlyOwner` modifier will be disabled.
     * @dev Can only be called by the current owner.
     * @dev Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is
     *  only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @notice Transfers ownership of the contract to a new owner.
     * @dev Can only be called by the current owner.
     * @param newOwner Address of the new owner's account
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) revert RMRKNewOwnerIsZeroAddress();
        _transferOwnership(newOwner);
    }

    /**
     * @notice Transfers ownership of the contract to a new owner.
     * @dev Internal function without access restriction.
     * @dev Emits ***OwnershipTransferred*** event.
     * @param newOwner Address of the new owner's account
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @notice Adds or removes a contributor to the smart contract.
     * @dev Can only be called by the owner.
     * @dev Emits ***ContributorUpdate*** event.
     * @param contributor Address of the contributor's account
     * @param grantRole A boolean value signifying whether the contributor role is being granted (`true`) or revoked
     *  (`false`)
     */
    function manageContributor(
        address contributor,
        bool grantRole
    ) external onlyOwner {
        if (contributor == address(0)) revert RMRKNewContributorIsZeroAddress();
        grantRole
            ? _contributors[contributor] = 1
            : _contributors[contributor] = 0;
        emit ContributorUpdate(contributor, grantRole);
    }

    /**
     * @notice Used to check if the address is one of the contributors.
     * @param contributor Address of the contributor whose status we are checking
     * @return Boolean value indicating whether the address is a contributor or not
     */
    function isContributor(address contributor) public view returns (bool) {
        return _contributors[contributor] == 1;
    }

    /**
     * @notice Used to verify that the caller is either the owner or a contributor.
     * @dev If the caller is not the owner or a contributor, the execution will be reverted.
     */
    function _onlyOwnerOrContributor() private view {
        if (owner() != _msgSender() && !isContributor(_msgSender()))
            revert RMRKNotOwnerOrContributor();
    }

    /**
     * @notice Used to verify that the caller is the owner.
     * @dev If the caller is not the owner, the execution will be reverted.
     */
    function _onlyOwner() private view {
        if (owner() != _msgSender()) revert RMRKNotOwner();
    }
}

// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.21;

import "../multiasset/IERC5773.sol";

/**
 * @title IERC6220
 * @author RMRK team
 * @notice Interface smart contract of the RMRK equippable module.
 */
interface IERC6220 is IERC5773 {
    /**
     * @notice Used to store the core structure of the `Equippable` RMRK lego.
     * @return assetId The ID of the asset equipping a child
     * @return childAssetId The ID of the asset used as equipment
     * @return childId The ID of token that is equipped
     * @return childEquippableAddress Address of the collection to which the child asset belongs to
     */
    struct Equipment {
        uint64 assetId;
        uint64 childAssetId;
        uint256 childId;
        address childEquippableAddress;
    }

    /**
     * @notice Used to provide a struct for inputing equip data.
     * @dev Only used for input and not storage of data.
     * @return tokenId ID of the token we are managing
     * @return childIndex Index of a child in the list of token's active children
     * @return assetId ID of the asset that we are equipping into
     * @return slotPartId ID of the slot part that we are using to equip
     * @return childAssetId ID of the asset that we are equipping
     */
    struct IntakeEquip {
        uint256 tokenId;
        uint256 childIndex;
        uint64 assetId;
        uint64 slotPartId;
        uint64 childAssetId;
    }

    /**
     * @notice Used to notify listeners that a child's asset has been equipped into one of its parent assets.
     * @param tokenId ID of the token that had an asset equipped
     * @param assetId ID of the asset associated with the token we are equipping into
     * @param slotPartId ID of the slot we are using to equip
     * @param childId ID of the child token we are equipping into the slot
     * @param childAddress Address of the child token's collection
     * @param childAssetId ID of the asset associated with the token we are equipping
     */
    event ChildAssetEquipped(
        uint256 indexed tokenId,
        uint64 indexed assetId,
        uint64 indexed slotPartId,
        uint256 childId,
        address childAddress,
        uint64 childAssetId
    );

    /**
     * @notice Used to notify listeners that a child's asset has been unequipped from one of its parent assets.
     * @param tokenId ID of the token that had an asset unequipped
     * @param assetId ID of the asset associated with the token we are unequipping out of
     * @param slotPartId ID of the slot we are unequipping from
     * @param childId ID of the token being unequipped
     * @param childAddress Address of the collection that a token that is being unequipped belongs to
     * @param childAssetId ID of the asset associated with the token we are unequipping
     */
    event ChildAssetUnequipped(
        uint256 indexed tokenId,
        uint64 indexed assetId,
        uint64 indexed slotPartId,
        uint256 childId,
        address childAddress,
        uint64 childAssetId
    );

    /**
     * @notice Used to notify listeners that the assets belonging to a `equippableGroupId` have been marked as
     *  equippable into a given slot and parent
     * @param equippableGroupId ID of the equippable group being marked as equippable into the slot associated with
     *  `slotPartId` of the `parentAddress` collection
     * @param slotPartId ID of the slot part of the catalog into which the parts belonging to the equippable group
     *  associated with `equippableGroupId` can be equipped
     * @param parentAddress Address of the collection into which the parts belonging to `equippableGroupId` can be
     *  equipped
     */
    event ValidParentEquippableGroupIdSet(
        uint64 indexed equippableGroupId,
        uint64 indexed slotPartId,
        address parentAddress
    );

    /**
     * @notice Used to equip a child into a token.
     * @dev The `IntakeEquip` stuct contains the following data:
     *  [
     *      tokenId,
     *      childIndex,
     *      assetId,
     *      slotPartId,
     *      childAssetId
     *  ]
     * @param data An `IntakeEquip` struct specifying the equip data
     */
    function equip(IntakeEquip memory data) external;

    /**
     * @notice Used to unequip child from parent token.
     * @dev This can only be called by the owner of the token or by an account that has been granted permission to
     *  manage the given token by the current owner.
     * @param tokenId ID of the parent from which the child is being unequipped
     * @param assetId ID of the parent's asset that contains the `Slot` into which the child is equipped
     * @param slotPartId ID of the `Slot` from which to unequip the child
     */
    function unequip(
        uint256 tokenId,
        uint64 assetId,
        uint64 slotPartId
    ) external;

    /**
     * @notice Used to check whether the token has a given child equipped.
     * @dev This is used to prevent from transferring a child that is equipped.
     * @param tokenId ID of the parent token for which we are querying for
     * @param childAddress Address of the child token's smart contract
     * @param childId ID of the child token
     * @return A boolean value indicating whether the child token is equipped into the given token or not
     */
    function isChildEquipped(
        uint256 tokenId,
        address childAddress,
        uint256 childId
    ) external view returns (bool);

    /**
     * @notice Used to verify whether a token can be equipped into a given parent's slot.
     * @param parent Address of the parent token's smart contract
     * @param tokenId ID of the token we want to equip
     * @param assetId ID of the asset associated with the token we want to equip
     * @param slotId ID of the slot that we want to equip the token into
     * @return A boolean indicating whether the token with the given asset can be equipped into the desired slot
     */
    function canTokenBeEquippedWithAssetIntoSlot(
        address parent,
        uint256 tokenId,
        uint64 assetId,
        uint64 slotId
    ) external view returns (bool);

    /**
     * @notice Used to get the Equipment object equipped into the specified slot of the desired token.
     * @dev The `Equipment` struct consists of the following data:
     *  [
     *      assetId,
     *      childAssetId,
     *      childId,
     *      childEquippableAddress
     *  ]
     * @param tokenId ID of the token for which we are retrieving the equipped object
     * @param targetCatalogAddress Address of the `Catalog` associated with the `Slot` part of the token
     * @param slotPartId ID of the `Slot` part that we are checking for equipped objects
     * @return The `Equipment` struct containing data about the equipped object
     */
    function getEquipment(
        uint256 tokenId,
        address targetCatalogAddress,
        uint64 slotPartId
    ) external view returns (Equipment memory);

    /**
     * @notice Used to get the asset and equippable data associated with given `assetId`.
     * @param tokenId ID of the token for which to retrieve the asset
     * @param assetId ID of the asset of which we are retrieving
     * @return metadataURI The metadata URI of the asset
     * @return equippableGroupId ID of the equippable group this asset belongs to
     * @return catalogAddress The address of the catalog the part belongs to
     * @return partIds An array of IDs of parts included in the asset
     */
    function getAssetAndEquippableData(
        uint256 tokenId,
        uint64 assetId
    )
        external
        view
        returns (
            string memory metadataURI,
            uint64 equippableGroupId,
            address catalogAddress,
            uint64[] memory partIds
        );
}

File 6 of 10 : IERC7508.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.21;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
 * @title IERC7508
 * @author RMRK team
 * @notice Interface smart contract of the RMRK token properties extension.
 */
interface IERC7508 is IERC165 {
    /**
     * @notice A list of supported access types.
     * @return The `Issuer` type, where only the issuer can manage the parameter.
     * @return The `Collaborator` type, where only the collaborators can manage the parameter.
     * @return The `IssuerOrCollaborator` type, where only the issuer or collaborators can manage the parameter.
     * @return The `TokenOwner` type, where only the token owner can manage the parameters of their tokens.
     * @return The `SpecificAddress` type, where only specific addresses can manage the parameter.
     */
    enum AccessType {
        Issuer,
        Collaborator,
        IssuerOrCollaborator,
        TokenOwner,
        SpecificAddress
    }

    /**
     * @notice Structure used to represent a string attribute.
     * @return key The key of the attribute
     * @return value The value of the attribute
     */
    struct StringAttribute {
        string key;
        string value;
    }

    /**
     * @notice Structure used to represent an uint attribute.
     * @return key The key of the attribute
     * @return value The value of the attribute
     */
    struct UintAttribute {
        string key;
        uint256 value;
    }

    /**
     * @notice Structure used to represent a boolean attribute.
     * @return key The key of the attribute
     * @return value The value of the attribute
     */
    struct BoolAttribute {
        string key;
        bool value;
    }

    /**
     * @notice Structure used to represent an address attribute.
     * @return key The key of the attribute
     * @return value The value of the attribute
     */
    struct AddressAttribute {
        string key;
        address value;
    }

    /**
     * @notice Structure used to represent a bytes attribute.
     * @return key The key of the attribute
     * @return value The value of the attribute
     */
    struct BytesAttribute {
        string key;
        bytes value;
    }

    /**
     * @notice Used to notify listeners that a new collection has been registered to use the repository.
     * @param collection Address of the collection
     * @param issuer Address of the issuer of the collection; the addess authorized to manage the access control
     * @param registeringAddress Address that registered the collection
     * @param useOwnable A boolean value indicating whether the collection uses the Ownable extension to verify the
     *  issuer (`true`) or not (`false`)
     */
    event AccessControlRegistration(
        address indexed collection,
        address indexed issuer,
        address indexed registeringAddress,
        bool useOwnable
    );

    /**
     * @notice Used to notify listeners that the access control settings for a specific parameter have been updated.
     * @param collection Address of the collection
     * @param key The name of the parameter for which the access control settings have been updated
     * @param accessType The AccessType of the parameter for which the access control settings have been updated
     * @param specificAddress The specific addresses that has been updated
     */
    event AccessControlUpdate(
        address indexed collection,
        string key,
        AccessType accessType,
        address specificAddress
    );

    /**
     * @notice Used to notify listeners that a new collaborator has been added or removed.
     * @param collection Address of the collection
     * @param collaborator Address of the collaborator
     * @param isCollaborator A boolean value indicating whether the collaborator has been added (`true`) or removed
     *  (`false`)
     */
    event CollaboratorUpdate(
        address indexed collection,
        address indexed collaborator,
        bool isCollaborator
    );

    /**
     * @notice Used to notify listeners that a string attribute has been updated.
     * @param collection The collection address
     * @param tokenId The token ID
     * @param key The key of the attribute
     * @param value The new value of the attribute
     */
    event StringAttributeUpdated(
        address indexed collection,
        uint256 indexed tokenId,
        string key,
        string value
    );

    /**
     * @notice Used to notify listeners that an uint attribute has been updated.
     * @param collection The collection address
     * @param tokenId The token ID
     * @param key The key of the attribute
     * @param value The new value of the attribute
     */
    event UintAttributeUpdated(
        address indexed collection,
        uint256 indexed tokenId,
        string key,
        uint256 value
    );

    /**
     * @notice Used to notify listeners that a boolean attribute has been updated.
     * @param collection The collection address
     * @param tokenId The token ID
     * @param key The key of the attribute
     * @param value The new value of the attribute
     */
    event BoolAttributeUpdated(
        address indexed collection,
        uint256 indexed tokenId,
        string key,
        bool value
    );

    /**
     * @notice Used to notify listeners that an address attribute has been updated.
     * @param collection The collection address
     * @param tokenId The token ID
     * @param key The key of the attribute
     * @param value The new value of the attribute
     */
    event AddressAttributeUpdated(
        address indexed collection,
        uint256 indexed tokenId,
        string key,
        address value
    );

    /**
     * @notice Used to notify listeners that a bytes attribute has been updated.
     * @param collection The collection address
     * @param tokenId The token ID
     * @param key The key of the attribute
     * @param value The new value of the attribute
     */
    event BytesAttributeUpdated(
        address indexed collection,
        uint256 indexed tokenId,
        string key,
        bytes value
    );

    /**
     * @notice Used to register a collection to use the RMRK token attributes repository.
     * @dev  If the collection does not implement the Ownable interface, the `useOwnable` value must be set to `false`.
     * @dev Emits an {AccessControlRegistration} event.
     * @param collection The address of the collection that will use the RMRK token attributes repository.
     * @param issuer The address of the issuer of the collection.
     * @param useOwnable The boolean value to indicate if the collection implements the Ownable interface and whether it
     *  should be used to validate that the caller is the issuer (`true`) or to use the manually set issuer address
     *  (`false`).
     */
    function registerAccessControl(
        address collection,
        address issuer,
        bool useOwnable
    ) external;

    /**
     * @notice Used to manage the access control settings for a specific parameter.
     * @dev Only the `issuer` of the collection can call this function.
     * @dev The possible `accessType` values are:
     *  [
     *      Issuer,
     *      Collaborator,
     *      IssuerOrCollaborator,
     *      TokenOwner,
     *      SpecificAddress,
     *  ]
     * @dev Emits an {AccessControlUpdated} event.
     * @param collection The address of the collection being managed.
     * @param key The key of the attribute
     * @param accessType The type of access control to be applied to the parameter.
     * @param specificAddress The address to be added as a specific addresses allowed to manage the given
     *  parameter.
     */
    function manageAccessControl(
        address collection,
        string memory key,
        AccessType accessType,
        address specificAddress
    ) external;

    /**
     * @notice Used to manage the collaborators of a collection.
     * @dev The `collaboratorAddresses` and `collaboratorAddressAccess` arrays must be of the same length.
     * @dev Emits a {CollaboratorUpdate} event.
     * @param collection The address of the collection
     * @param collaboratorAddresses The array of collaborator addresses being managed
     * @param collaboratorAddressAccess The array of boolean values indicating if the collaborator address should
     *  receive the permission (`true`) or not (`false`).
     */
    function manageCollaborators(
        address collection,
        address[] memory collaboratorAddresses,
        bool[] memory collaboratorAddressAccess
    ) external;

    /**
     * @notice Used to set a number attribute.
     * @dev Emits a {UintAttributeUpdated} event.
     * @param collection Address of the collection receiving the attribute
     * @param tokenId The token ID
     * @param key The attribute key
     * @param value The attribute value
     */
    function setUintAttribute(
        address collection,
        uint256 tokenId,
        string memory key,
        uint256 value
    ) external;

    /**
     * @notice Used to set a string attribute.
     * @dev Emits a {StringAttributeUpdated} event.
     * @param collection Address of the collection receiving the attribute
     * @param tokenId The token ID
     * @param key The attribute key
     * @param value The attribute value
     */
    function setStringAttribute(
        address collection,
        uint256 tokenId,
        string memory key,
        string memory value
    ) external;

    /**
     * @notice Used to set a boolean attribute.
     * @dev Emits a {BoolAttributeUpdated} event.
     * @param collection Address of the collection receiving the attribute
     * @param tokenId The token ID
     * @param key The attribute key
     * @param value The attribute value
     */
    function setBoolAttribute(
        address collection,
        uint256 tokenId,
        string memory key,
        bool value
    ) external;

    /**
     * @notice Used to set an bytes attribute.
     * @dev Emits a {BytesAttributeUpdated} event.
     * @param collection Address of the collection receiving the attribute
     * @param tokenId The token ID
     * @param key The attribute key
     * @param value The attribute value
     */
    function setBytesAttribute(
        address collection,
        uint256 tokenId,
        string memory key,
        bytes memory value
    ) external;

    /**
     * @notice Used to set an address attribute.
     * @dev Emits a {AddressAttributeUpdated} event.
     * @param collection Address of the collection receiving the attribute
     * @param tokenId The token ID
     * @param key The attribute key
     * @param value The attribute value
     */
    function setAddressAttribute(
        address collection,
        uint256 tokenId,
        string memory key,
        address value
    ) external;

    /**
     * @notice Sets multiple string attributes for a token at once.
     * @dev The `StringAttribute` struct contains the following fields:
     *  [
     *      string key,
     *      string value
     *  ]
     * @param collection Address of the collection
     * @param tokenId ID of the token
     * @param attributes An array of `StringAttribute` structs to be assigned to the given token
     */
    function setStringAttributes(
        address collection,
        uint256 tokenId,
        StringAttribute[] memory attributes
    ) external;

    /**
     * @notice Sets multiple uint attributes for a token at once.
     * @dev The `UintAttribute` struct contains the following fields:
     *  [
     *      string key,
     *      uint value
     *  ]
     * @param collection Address of the collection
     * @param tokenId ID of the token
     * @param attributes An array of `UintAttribute` structs to be assigned to the given token
     */
    function setUintAttributes(
        address collection,
        uint256 tokenId,
        UintAttribute[] memory attributes
    ) external;

    /**
     * @notice Sets multiple bool attributes for a token at once.
     * @dev The `BoolAttribute` struct contains the following fields:
     *  [
     *      string key,
     *      bool value
     *  ]
     * @param collection Address of the collection
     * @param tokenId ID of the token
     * @param attributes An array of `BoolAttribute` structs to be assigned to the given token
     */
    function setBoolAttributes(
        address collection,
        uint256 tokenId,
        BoolAttribute[] memory attributes
    ) external;

    /**
     * @notice Sets multiple address attributes for a token at once.
     * @dev The `AddressAttribute` struct contains the following fields:
     *  [
     *      string key,
     *      address value
     *  ]
     * @param collection Address of the collection
     * @param tokenId ID of the token
     * @param attributes An array of `AddressAttribute` structs to be assigned to the given token
     */
    function setAddressAttributes(
        address collection,
        uint256 tokenId,
        AddressAttribute[] memory attributes
    ) external;

    /**
     * @notice Sets multiple bytes attributes for a token at once.
     * @dev The `BytesAttribute` struct contains the following fields:
     *  [
     *      string key,
     *      bytes value
     *  ]
     * @param collection Address of the collection
     * @param tokenId ID of the token
     * @param attributes An array of `BytesAttribute` structs to be assigned to the given token
     */
    function setBytesAttributes(
        address collection,
        uint256 tokenId,
        BytesAttribute[] memory attributes
    ) external;

    /**
     * @notice Sets multiple attributes of multiple types for a token at the same time.
     * @dev Emits a separate event for each attribute set.
     * @dev The `StringAttribute`, `UintAttribute`, `BoolAttribute`, `AddressAttribute` and `BytesAttribute` structs consists
     *  to the following fields (where `value` is of the appropriate type):
     *  [
     *      key,
     *      value,
     *  ]
     * @param collection The address of the collection
     * @param tokenId The token ID
     * @param stringAttributes An array of `StringAttribute` structs containing string attributes to set
     * @param uintAttributes An array of `UintAttribute` structs containing uint attributes to set
     * @param boolAttributes An array of `BoolAttribute` structs containing bool attributes to set
     * @param addressAttributes An array of `AddressAttribute` structs containing address attributes to set
     * @param bytesAttributes An array of `BytesAttribute` structs containing bytes attributes to set
     */
    function setAttributes(
        address collection,
        uint256 tokenId,
        StringAttribute[] memory stringAttributes,
        UintAttribute[] memory uintAttributes,
        BoolAttribute[] memory boolAttributes,
        AddressAttribute[] memory addressAttributes,
        BytesAttribute[] memory bytesAttributes
    ) external;

    /**
     * @notice Used to set the uint attribute on behalf of an authorized account.
     * @dev Emits a {UintAttributeUpdated} event.
     * @param setter Address of the account that presigned the attribute change
     * @param collection Address of the collection receiving the attribute
     * @param tokenId The ID of the token receiving the attribute
     * @param key The attribute key
     * @param value The attribute value
     * @param deadline The deadline timestamp for the presigned transaction
     * @param v `v` value of an ECDSA signature of the presigned message
     * @param r `r` value of an ECDSA signature of the presigned message
     * @param s `s` value of an ECDSA signature of the presigned message
     */
    function presignedSetUintAttribute(
        address setter,
        address collection,
        uint256 tokenId,
        string memory key,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @notice Used to set the string attribute on behalf of an authorized account.
     * @dev Emits a {StringAttributeUpdated} event.
     * @param setter Address of the account that presigned the attribute change
     * @param collection Address of the collection receiving the attribute
     * @param tokenId The ID of the token receiving the attribute
     * @param key The attribute key
     * @param value The attribute value
     * @param deadline The deadline timestamp for the presigned transaction
     * @param v `v` value of an ECDSA signature of the presigned message
     * @param r `r` value of an ECDSA signature of the presigned message
     * @param s `s` value of an ECDSA signature of the presigned message
     */
    function presignedSetStringAttribute(
        address setter,
        address collection,
        uint256 tokenId,
        string memory key,
        string memory value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @notice Used to set the bool attribute on behalf of an authorized account.
     * @dev Emits a {BoolAttributeUpdated} event.
     * @param setter Address of the account that presigned the attribute change
     * @param collection Address of the collection receiving the attribute
     * @param tokenId The ID of the token receiving the attribute
     * @param key The attribute key
     * @param value The attribute value
     * @param deadline The deadline timestamp for the presigned transaction
     * @param v `v` value of an ECDSA signature of the presigned message
     * @param r `r` value of an ECDSA signature of the presigned message
     * @param s `s` value of an ECDSA signature of the presigned message
     */
    function presignedSetBoolAttribute(
        address setter,
        address collection,
        uint256 tokenId,
        string memory key,
        bool value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @notice Used to set the bytes attribute on behalf of an authorized account.
     * @dev Emits a {BytesAttributeUpdated} event.
     * @param setter Address of the account that presigned the attribute change
     * @param collection Address of the collection receiving the attribute
     * @param tokenId The ID of the token receiving the attribute
     * @param key The attribute key
     * @param value The attribute value
     * @param deadline The deadline timestamp for the presigned transaction
     * @param v `v` value of an ECDSA signature of the presigned message
     * @param r `r` value of an ECDSA signature of the presigned message
     * @param s `s` value of an ECDSA signature of the presigned message
     */
    function presignedSetBytesAttribute(
        address setter,
        address collection,
        uint256 tokenId,
        string memory key,
        bytes memory value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @notice Used to set the address attribute on behalf of an authorized account.
     * @dev Emits a {AddressAttributeUpdated} event.
     * @param setter Address of the account that presigned the attribute change
     * @param collection Address of the collection receiving the attribute
     * @param tokenId The ID of the token receiving the attribute
     * @param key The attribute key
     * @param value The attribute value
     * @param deadline The deadline timestamp for the presigned transaction
     * @param v `v` value of an ECDSA signature of the presigned message
     * @param r `r` value of an ECDSA signature of the presigned message
     * @param s `s` value of an ECDSA signature of the presigned message
     */
    function presignedSetAddressAttribute(
        address setter,
        address collection,
        uint256 tokenId,
        string memory key,
        address value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @notice Used to check if the specified address is listed as a collaborator of the given collection's parameter.
     * @param collaborator Address to be checked.
     * @param collection Address of the collection.
     * @return Boolean value indicating if the address is a collaborator of the given collection's (`true`) or not
     *  (`false`).
     */
    function isCollaborator(
        address collaborator,
        address collection
    ) external view returns (bool);

    /**
     * @notice Used to check if the specified address is listed as a specific address of the given collection's
     *  parameter.
     * @param specificAddress Address to be checked.
     * @param collection Address of the collection.
     * @param key The key of the attribute
     * @return Boolean value indicating if the address is a specific address of the given collection's parameter
     *  (`true`) or not (`false`).
     */
    function isSpecificAddress(
        address specificAddress,
        address collection,
        string memory key
    ) external view returns (bool);

    /**
     * @notice Used to retrieve the string type token attributes.
     * @param collection The collection address
     * @param tokenId The token ID
     * @param key The key of the attribute
     * @return The value of the string attribute
     */
    function getStringAttribute(
        address collection,
        uint256 tokenId,
        string memory key
    ) external view returns (string memory);

    /**
     * @notice Used to retrieve the uint type token attributes.
     * @param collection The collection address
     * @param tokenId The token ID
     * @param key The key of the attribute
     * @return The value of the uint attribute
     */
    function getUintAttribute(
        address collection,
        uint256 tokenId,
        string memory key
    ) external view returns (uint256);

    /**
     * @notice Used to retrieve the bool type token attributes.
     * @param collection The collection address
     * @param tokenId The token ID
     * @param key The key of the attribute
     * @return The value of the bool attribute
     */
    function getBoolAttribute(
        address collection,
        uint256 tokenId,
        string memory key
    ) external view returns (bool);

    /**
     * @notice Used to retrieve the address type token attributes.
     * @param collection The collection address
     * @param tokenId The token ID
     * @param key The key of the attribute
     * @return The value of the address attribute
     */
    function getAddressAttribute(
        address collection,
        uint256 tokenId,
        string memory key
    ) external view returns (address);

    /**
     * @notice Used to retrieve the bytes type token attributes.
     * @param collection The collection address
     * @param tokenId The token ID
     * @param key The key of the attribute
     * @return The value of the bytes attribute
     */
    function getBytesAttribute(
        address collection,
        uint256 tokenId,
        string memory key
    ) external view returns (bytes memory);

    /**
     * @notice Used to retrieve the message to be signed for submitting a presigned uint attribute change.
     * @param collection The address of the collection smart contract of the token receiving the attribute
     * @param tokenId The ID of the token receiving the attribute
     * @param key The attribute key
     * @param value The attribute value
     * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid
     * @return Raw message to be signed by the authorized account
     */
    function prepareMessageToPresignUintAttribute(
        address collection,
        uint256 tokenId,
        string memory key,
        uint256 value,
        uint256 deadline
    ) external view returns (bytes32);

    /**
     * @notice Used to retrieve the message to be signed for submitting a presigned string attribute change.
     * @param collection The address of the collection smart contract of the token receiving the attribute
     * @param tokenId The ID of the token receiving the attribute
     * @param key The attribute key
     * @param value The attribute value
     * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid
     * @return Raw message to be signed by the authorized account
     */
    function prepareMessageToPresignStringAttribute(
        address collection,
        uint256 tokenId,
        string memory key,
        string memory value,
        uint256 deadline
    ) external view returns (bytes32);

    /**
     * @notice Used to retrieve the message to be signed for submitting a presigned bool attribute change.
     * @param collection The address of the collection smart contract of the token receiving the attribute
     * @param tokenId The ID of the token receiving the attribute
     * @param key The attribute key
     * @param value The attribute value
     * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid
     * @return Raw message to be signed by the authorized account
     */
    function prepareMessageToPresignBoolAttribute(
        address collection,
        uint256 tokenId,
        string memory key,
        bool value,
        uint256 deadline
    ) external view returns (bytes32);

    /**
     * @notice Used to retrieve the message to be signed for submitting a presigned bytes attribute change.
     * @param collection The address of the collection smart contract of the token receiving the attribute
     * @param tokenId The ID of the token receiving the attribute
     * @param key The attribute key
     * @param value The attribute value
     * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid
     * @return Raw message to be signed by the authorized account
     */
    function prepareMessageToPresignBytesAttribute(
        address collection,
        uint256 tokenId,
        string memory key,
        bytes memory value,
        uint256 deadline
    ) external view returns (bytes32);

    /**
     * @notice Used to retrieve the message to be signed for submitting a presigned address attribute change.
     * @param collection The address of the collection smart contract of the token receiving the attribute
     * @param tokenId The ID of the token receiving the attribute
     * @param key The attribute key
     * @param value The attribute value
     * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid
     * @return Raw message to be signed by the authorized account
     */
    function prepareMessageToPresignAddressAttribute(
        address collection,
        uint256 tokenId,
        string memory key,
        address value,
        uint256 deadline
    ) external view returns (bytes32);

    /**
     * @notice Used to retrieve multiple token attributes of any type at once.
     * @dev The `StringAttribute`, `UintAttribute`, `BoolAttribute`, `AddressAttribute` and `BytesAttribute` structs consists
     *  to the following fields (where `value` is of the appropriate type):
     *  [
     *      key,
     *      value,
     *  ]
     * @param collection The collection address
     * @param tokenId The token ID
     * @param stringKeys An array of string type attribute keys to retrieve
     * @param uintKeys An array of uint type attribute keys to retrieve
     * @param boolKeys An array of bool type attribute keys to retrieve
     * @param addressKeys An array of address type attribute keys to retrieve
     * @param bytesKeys An array of bytes type attribute keys to retrieve
     * @return stringAttributes An array of `StringAttribute` structs containing the string type attributes
     * @return uintAttributes An array of `UintAttribute` structs containing the uint type attributes
     * @return boolAttributes An array of `BoolAttribute` structs containing the bool type attributes
     * @return addressAttributes An array of `AddressAttribute` structs containing the address type attributes
     * @return bytesAttributes An array of `BytesAttribute` structs containing the bytes type attributes
     */
    function getAttributes(
        address collection,
        uint256 tokenId,
        string[] memory stringKeys,
        string[] memory uintKeys,
        string[] memory boolKeys,
        string[] memory addressKeys,
        string[] memory bytesKeys
    )
        external
        view
        returns (
            StringAttribute[] memory stringAttributes,
            UintAttribute[] memory uintAttributes,
            BoolAttribute[] memory boolAttributes,
            AddressAttribute[] memory addressAttributes,
            BytesAttribute[] memory bytesAttributes
        );

    /**
     * @notice Used to get multiple sting parameter values for a token.
     * @dev The `StringAttribute` struct contains the following fields:
     *  [
     *     string key,
     *     string value
     *  ]
     * @param collection Address of the collection the token belongs to
     * @param tokenId ID of the token for which the attributes are being retrieved
     * @param stringKeys An array of string keys to retrieve
     * @return An array of `StringAttribute` structs
     */
    function getStringAttributes(
        address collection,
        uint256 tokenId,
        string[] memory stringKeys
    ) external view returns (StringAttribute[] memory);

    /**
     * @notice Used to get multiple uint parameter values for a token.
     * @dev The `UintAttribute` struct contains the following fields:
     *  [
     *     string key,
     *     uint value
     *  ]
     * @param collection Address of the collection the token belongs to
     * @param tokenId ID of the token for which the attributes are being retrieved
     * @param uintKeys An array of uint keys to retrieve
     * @return An array of `UintAttribute` structs
     */
    function getUintAttributes(
        address collection,
        uint256 tokenId,
        string[] memory uintKeys
    ) external view returns (UintAttribute[] memory);

    /**
     * @notice Used to get multiple bool parameter values for a token.
     * @dev The `BoolAttribute` struct contains the following fields:
     *  [
     *     string key,
     *     bool value
     *  ]
     * @param collection Address of the collection the token belongs to
     * @param tokenId ID of the token for which the attributes are being retrieved
     * @param boolKeys An array of bool keys to retrieve
     * @return An array of `BoolAttribute` structs
     */
    function getBoolAttributes(
        address collection,
        uint256 tokenId,
        string[] memory boolKeys
    ) external view returns (BoolAttribute[] memory);

    /**
     * @notice Used to get multiple address parameter values for a token.
     * @dev The `AddressAttribute` struct contains the following fields:
     *  [
     *     string key,
     *     address value
     *  ]
     * @param collection Address of the collection the token belongs to
     * @param tokenId ID of the token for which the attributes are being retrieved
     * @param addressKeys An array of address keys to retrieve
     * @return An array of `AddressAttribute` structs
     */
    function getAddressAttributes(
        address collection,
        uint256 tokenId,
        string[] memory addressKeys
    ) external view returns (AddressAttribute[] memory);

    /**
     * @notice Used to get multiple bytes parameter values for a token.
     * @dev The `BytesAttribute` struct contains the following fields:
     *  [
     *     string key,
     *     bytes value
     *  ]
     * @param collection Address of the collection the token belongs to
     * @param tokenId ID of the token for which the attributes are being retrieved
     * @param bytesKeys An array of bytes keys to retrieve
     * @return An array of `BytesAttribute` structs
     */
    function getBytesAttributes(
        address collection,
        uint256 tokenId,
        string[] memory bytesKeys
    ) external view returns (BytesAttribute[] memory);
}

File 7 of 10 : RMRKErrors.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.21;

/// @title RMRKErrors
/// @author RMRK team
/// @notice A collection of errors used in the RMRK suite
/// @dev Errors are kept in a centralised file in order to provide a central point of reference and to avoid error
///  naming collisions due to inheritance

/// Attempting to grant the token to 0x0 address
error ERC721AddressZeroIsNotaValidOwner();
/// Attempting to grant approval to the current owner of the token
error ERC721ApprovalToCurrentOwner();
/// Attempting to grant approval when not being owner or approved for all should not be permitted
error ERC721ApproveCallerIsNotOwnerNorApprovedForAll();
/// Attempting to get approvals for a token owned by 0x0 (considered non-existent)
error ERC721ApprovedQueryForNonexistentToken();
/// Attempting to grant approval to self
error ERC721ApproveToCaller();
/// Attempting to use an invalid token ID
error ERC721InvalidTokenId();
/// Attempting to mint to 0x0 address
error ERC721MintToTheZeroAddress();
/// Attempting to manage a token without being its owner or approved by the owner
error ERC721NotApprovedOrOwner();
/// Attempting to mint an already minted token
error ERC721TokenAlreadyMinted();
/// Attempting to transfer the token from an address that is not the owner
error ERC721TransferFromIncorrectOwner();
/// Attempting to safe transfer to an address that is unable to receive the token
error ERC721TransferToNonReceiverImplementer();
/// Attempting to transfer the token to a 0x0 address
error ERC721TransferToTheZeroAddress();
/// Attempting to grant approval of assets to their current owner
error RMRKApprovalForAssetsToCurrentOwner();
/// Attempting to grant approval of assets without being the caller or approved for all
error RMRKApproveForAssetsCallerIsNotOwnerNorApprovedForAll();
/// Attempting to incorrectly configue a Catalog item
error RMRKBadConfig();
/// Attempting to set the priorities with an array of length that doesn't match the length of active assets array
error RMRKBadPriorityListLength();
/// Attempting to add an asset entry with `Part`s, without setting the `Catalog` address
error RMRKCatalogRequiredForParts();
/// Attempting to transfer a soulbound (non-transferrable) token
error RMRKCannotTransferSoulbound();
/// Attempting to accept a child that has already been accepted
error RMRKChildAlreadyExists();
/// Attempting to interact with a child, using index that is higher than the number of children
error RMRKChildIndexOutOfRange();
/// Attempting to find the index of a child token on a parent which does not own it.
error RMRKChildNotFoundInParent();
/// Attempting to pass collaborator address array and collaborator permission array of different lengths
error RMRKCollaboratorArraysNotEqualLength();
/// Attempting to register a collection that is already registered
error RMRKCollectionAlreadyRegistered();
/// Attempting to manage or interact with colleciton that is not registered
error RMRKCollectionNotRegistered();
/// Attempting to equip a `Part` with a child not approved by the Catalog
error RMRKEquippableEquipNotAllowedByCatalog();
/// Attempting to pass an epired ECDSA deadline
error RMRKExpiredDeadline();
/// Attempting to use ID 0, which is not supported
/// @dev The ID 0 in RMRK suite is reserved for empty values. Guarding against its use ensures the expected operation
error RMRKIdZeroForbidden();
/// Attempting to interact with an asset, using index greater than number of assets
error RMRKIndexOutOfRange();
/// Attempting to reclaim a child that can't be reclaimed
error RMRKInvalidChildReclaim();
/// Attempting to use and invalid ECDSA signature
error RMRKInvalidSignature();
/// Attempting to interact with an end-user account when the contract account is expected
error RMRKIsNotContract();
/// Attempting to interact with a contract that had its operation locked
error RMRKLocked();
/// Attempting to add a pending child after the number of pending children has reached the limit (default limit is 128)
error RMRKMaxPendingChildrenReached();
/// Attempting to add a pending asset after the number of pending assets has reached the limit (default limit is
///  128)
error RMRKMaxPendingAssetsReached();
/// Attempting to burn a total number of recursive children higher than maximum set
/// @param childContract Address of the collection smart contract in which the maximum number of recursive burns was reached
/// @param childId ID of the child token at which the maximum number of recursive burns was reached
error RMRKMaxRecursiveBurnsReached(address childContract, uint256 childId);
/// Attempting to mint a number of tokens that would cause the total supply to be greater than maximum supply
error RMRKMintOverMax();
/// Attempting to mint a nested token to a smart contract that doesn't support nesting
error RMRKMintToNonRMRKNestableImplementer();
/// Attempting to mint zero tokens
error RMRKMintZero();
/// Attempting to pass complementary arrays of different lengths
error RMRKMismachedArrayLength();
/// Attempting to transfer a child before it is unequipped
error RMRKMustUnequipFirst();
/// Attempting to nest a child over the nestable limit (current limit is 100 levels of nesting)
error RMRKNestableTooDeep();
/// Attempting to nest the token to own descendant, which would create a loop and leave the looped tokens in limbo
error RMRKNestableTransferToDescendant();
/// Attempting to nest the token to a smart contract that doesn't support nesting
error RMRKNestableTransferToNonRMRKNestableImplementer();
/// Attempting to nest the token into itself
error RMRKNestableTransferToSelf();
/// Attempting to interact with an asset that can not be found
error RMRKNoAssetMatchingId();
/// Attempting to manage an asset without owning it or having been granted permission by the owner to do so
error RMRKNotApprovedForAssetsOrOwner();
/// Attempting to interact with a token without being its owner or having been granted permission by the
///  owner to do so
/// @dev When a token is nested, only the direct owner (NFT parent) can mange it. In that case, approved addresses are
///  not allowed to manage it, in order to ensure the expected behaviour
error RMRKNotApprovedOrDirectOwner();
/// Attempting to manage a collection without being the collection's collaborator
error RMRKNotCollectionCollaborator();
/// Attemting to manage a collection without being the collection's issuer
error RMRKNotCollectionIssuer();
/// Attempting to manage a collection without being the collection's issuer or collaborator
error RMRKNotCollectionIssuerOrCollaborator();
/// Attempting to compose an asset wihtout having an associated Catalog
error RMRKNotComposableAsset();
/// Attempting to unequip an item that isn't equipped
error RMRKNotEquipped();
/// Attempting to interact with a management function without being the smart contract's owner
error RMRKNotOwner();
/// Attempting to interact with a function without being the owner or contributor of the collection
error RMRKNotOwnerOrContributor();
/// Attempting to manage a collection without being the specific address
error RMRKNotSpecificAddress();
/// Attempting to manage a token without being its owner
error RMRKNotTokenOwner();
/// Attempting to transfer the ownership to the 0x0 address
error RMRKNewOwnerIsZeroAddress();
/// Attempting to assign a 0x0 address as a contributor
error RMRKNewContributorIsZeroAddress();
/// Attemtping to use `Ownable` interface without implementing it
error RMRKOwnableNotImplemented();
/// Attempting an operation requiring the token being nested, while it is not
error RMRKParentIsNotNFT();
/// Attempting to add a `Part` with an ID that is already used
error RMRKPartAlreadyExists();
/// Attempting to use a `Part` that doesn't exist
error RMRKPartDoesNotExist();
/// Attempting to use a `Part` that is `Fixed` when `Slot` kind of `Part` should be used
error RMRKPartIsNotSlot();
/// Attempting to interact with a pending child using an index greater than the size of pending array
error RMRKPendingChildIndexOutOfRange();
/// Attempting to add an asset using an ID that has already been used
error RMRKAssetAlreadyExists();
/// Attempting to equip an item into a slot that already has an item equipped
error RMRKSlotAlreadyUsed();
/// Attempting to equip an item into a `Slot` that the target asset does not implement
error RMRKTargetAssetCannotReceiveSlot();
/// Attempting to equip a child into a `Slot` and parent that the child's collection doesn't support
error RMRKTokenCannotBeEquippedWithAssetIntoSlot();
/// Attempting to compose a NFT of a token without active assets
error RMRKTokenDoesNotHaveAsset();
/// Attempting to determine the asset with the top priority on a token without assets
error RMRKTokenHasNoAssets();
/// Attempting to accept or transfer a child which does not match the one at the specified index
error RMRKUnexpectedChildId();
/// Attempting to reject all pending assets but more assets than expected are pending
error RMRKUnexpectedNumberOfAssets();
/// Attempting to reject all pending children but children assets than expected are pending
error RMRKUnexpectedNumberOfChildren();
/// Attempting to accept or reject an asset which does not match the one at the specified index
error RMRKUnexpectedAssetId();
/// Attempting an operation expecting a parent to the token which is not the actual one
error RMRKUnexpectedParent();
/// Attempting not to pass an empty array of equippable addresses when adding or setting the equippable addresses
error RMRKZeroLengthIdsPassed();
/// Attempting to set the royalties to a value higher than 100% (10000 in basis points)
error RMRKRoyaltiesTooHigh();
/// Attempting to do a bulk operation on a token that is not owned by the caller
error RMRKCanOnlyDoBulkOperationsOnOwnedTokens();
/// Attempting to do a bulk operation with multiple tokens at a time
error RMRKCanOnlyDoBulkOperationsWithOneTokenAtATime();
/// Attempting to pay with native token with a value different than expected
error RMRKWrongValueSent();

// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.21;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
 * @title IERC5773
 * @author RMRK team
 * @notice Interface smart contract of the RMRK multi asset module.
 */
interface IERC5773 is IERC165 {
    /**
     * @notice Used to notify listeners that an asset object is initialized at `assetId`.
     * @param assetId ID of the asset that was initialized
     */
    event AssetSet(uint64 indexed assetId);

    /**
     * @notice Used to notify listeners that an asset object at `assetId` is added to token's pending asset
     *  array.
     * @param tokenIds An array of token IDs that received a new pending asset
     * @param assetId ID of the asset that has been added to the token's pending assets array
     * @param replacesId ID of the asset that would be replaced
     */
    event AssetAddedToTokens(
        uint256[] tokenIds,
        uint64 indexed assetId,
        uint64 indexed replacesId
    );

    /**
     * @notice Used to notify listeners that an asset object at `assetId` is accepted by the token and migrated
     *  from token's pending assets array to active assets array of the token.
     * @param tokenId ID of the token that had a new asset accepted
     * @param assetId ID of the asset that was accepted
     * @param replacesId ID of the asset that was replaced
     */
    event AssetAccepted(
        uint256 indexed tokenId,
        uint64 indexed assetId,
        uint64 indexed replacesId
    );

    /**
     * @notice Used to notify listeners that an asset object at `assetId` is rejected from token and is dropped
     *  from the pending assets array of the token.
     * @param tokenId ID of the token that had an asset rejected
     * @param assetId ID of the asset that was rejected
     */
    event AssetRejected(uint256 indexed tokenId, uint64 indexed assetId);

    /**
     * @notice Used to notify listeners that token's prioritiy array is reordered.
     * @param tokenId ID of the token that had the asset priority array updated
     */
    event AssetPrioritySet(uint256 indexed tokenId);

    /**
     * @notice Used to notify listeners that owner has granted an approval to the user to manage the assets of a
     *  given token.
     * @dev Approvals must be cleared on transfer
     * @param owner Address of the account that has granted the approval for all token's assets
     * @param approved Address of the account that has been granted approval to manage the token's assets
     * @param tokenId ID of the token on which the approval was granted
     */
    event ApprovalForAssets(
        address indexed owner,
        address indexed approved,
        uint256 indexed tokenId
    );

    /**
     * @notice Used to notify listeners that owner has granted approval to the user to manage assets of all of their
     *  tokens.
     * @param owner Address of the account that has granted the approval for all assets on all of their tokens
     * @param operator Address of the account that has been granted the approval to manage the token's assets on all of
     *  the tokens
     * @param approved Boolean value signifying whether the permission has been granted (`true`) or revoked (`false`)
     */
    event ApprovalForAllForAssets(
        address indexed owner,
        address indexed operator,
        bool approved
    );

    /**
     * @notice Accepts an asset at from the pending array of given token.
     * @dev Migrates the asset from the token's pending asset array to the token's active asset array.
     * @dev Active assets cannot be removed by anyone, but can be replaced by a new asset.
     * @dev Requirements:
     *
     *  - The caller must own the token or be approved to manage the token's assets
     *  - `tokenId` must exist.
     *  - `index` must be in range of the length of the pending asset array.
     * @dev Emits an {AssetAccepted} event.
     * @param tokenId ID of the token for which to accept the pending asset
     * @param index Index of the asset in the pending array to accept
     * @param assetId ID of the asset expected to be in the index
     */
    function acceptAsset(
        uint256 tokenId,
        uint256 index,
        uint64 assetId
    ) external;

    /**
     * @notice Rejects an asset from the pending array of given token.
     * @dev Removes the asset from the token's pending asset array.
     * @dev Requirements:
     *
     *  - The caller must own the token or be approved to manage the token's assets
     *  - `tokenId` must exist.
     *  - `index` must be in range of the length of the pending asset array.
     * @dev Emits a {AssetRejected} event.
     * @param tokenId ID of the token that the asset is being rejected from
     * @param index Index of the asset in the pending array to be rejected
     * @param assetId ID of the asset expected to be in the index
     */
    function rejectAsset(
        uint256 tokenId,
        uint256 index,
        uint64 assetId
    ) external;

    /**
     * @notice Rejects all assets from the pending array of a given token.
     * @dev Effecitvely deletes the pending array.
     * @dev Requirements:
     *
     *  - The caller must own the token or be approved to manage the token's assets
     *  - `tokenId` must exist.
     * @dev Emits a {AssetRejected} event with assetId = 0.
     * @param tokenId ID of the token of which to clear the pending array.
     * @param maxRejections Maximum number of expected assets to reject, used to prevent from rejecting assets which
     *  arrive just before this operation.
     */
    function rejectAllAssets(uint256 tokenId, uint256 maxRejections) external;

    /**
     * @notice Sets a new priority array for a given token.
     * @dev The priority array is a non-sequential list of `uint64`s, where the lowest value is considered highest
     *  priority.
     * @dev Value `0` of a priority is a special case equivalent to unitialized.
     * @dev Requirements:
     *
     *  - The caller must own the token or be approved to manage the token's assets
     *  - `tokenId` must exist.
     *  - The length of `priorities` must be equal the length of the active assets array.
     * @dev Emits a {AssetPrioritySet} event.
     * @param tokenId ID of the token to set the priorities for
     * @param priorities An array of priorities of active assets. The succesion of items in the priorities array
     *  matches that of the succesion of items in the active array
     */
    function setPriority(
        uint256 tokenId,
        uint64[] calldata priorities
    ) external;

    /**
     * @notice Used to retrieve IDs of the active assets of given token.
     * @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call
     *  `getAssetMetadata(tokenId, assetId)`.
     * @dev You can safely get 10k
     * @param tokenId ID of the token to retrieve the IDs of the active assets
     * @return An array of active asset IDs of the given token
     */
    function getActiveAssets(
        uint256 tokenId
    ) external view returns (uint64[] memory);

    /**
     * @notice Used to retrieve IDs of the pending assets of given token.
     * @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call
     *  `getAssetMetadata(tokenId, assetId)`.
     * @param tokenId ID of the token to retrieve the IDs of the pending assets
     * @return An array of pending asset IDs of the given token
     */
    function getPendingAssets(
        uint256 tokenId
    ) external view returns (uint64[] memory);

    /**
     * @notice Used to retrieve the priorities of the active resoources of a given token.
     * @dev Asset priorities are a non-sequential array of uint64 values with an array size equal to active asset
     *  priorites.
     * @param tokenId ID of the token for which to retrieve the priorities of the active assets
     * @return An array of priorities of the active assets of the given token
     */
    function getActiveAssetPriorities(
        uint256 tokenId
    ) external view returns (uint64[] memory);

    /**
     * @notice Used to retrieve the asset that will be replaced if a given asset from the token's pending array
     *  is accepted.
     * @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call
     *  `getAssetMetadata(tokenId, assetId)`.
     * @param tokenId ID of the token to check
     * @param newAssetId ID of the pending asset which will be accepted
     * @return ID of the asset which will be replaced
     */
    function getAssetReplacements(
        uint256 tokenId,
        uint64 newAssetId
    ) external view returns (uint64);

    /**
     * @notice Used to fetch the asset metadata of the specified token's active asset with the given index.
     * @dev Assets are stored by reference mapping `_assets[assetId]`.
     * @dev Can be overriden to implement enumerate, fallback or other custom logic.
     * @param tokenId ID of the token from which to retrieve the asset metadata
     * @param assetId Asset Id, must be in the active assets array
     * @return The metadata of the asset belonging to the specified index in the token's active assets
     *  array
     */
    function getAssetMetadata(
        uint256 tokenId,
        uint64 assetId
    ) external view returns (string memory);

    // Approvals

    /**
     * @notice Used to grant permission to the user to manage token's assets.
     * @dev This differs from transfer approvals, as approvals are not cleared when the approved party accepts or
     *  rejects an asset, or sets asset priorities. This approval is cleared on token transfer.
     * @dev Only a single account can be approved at a time, so approving the `0x0` address clears previous approvals.
     * @dev Requirements:
     *
     *  - The caller must own the token or be an approved operator.
     *  - `tokenId` must exist.
     * @dev Emits an {ApprovalForAssets} event.
     * @param to Address of the account to grant the approval to
     * @param tokenId ID of the token for which the approval to manage the assets is granted
     */
    function approveForAssets(address to, uint256 tokenId) external;

    /**
     * @notice Used to retrieve the address of the account approved to manage assets of a given token.
     * @dev Requirements:
     *
     *  - `tokenId` must exist.
     * @param tokenId ID of the token for which to retrieve the approved address
     * @return Address of the account that is approved to manage the specified token's assets
     */
    function getApprovedForAssets(
        uint256 tokenId
    ) external view returns (address);

    /**
     * @notice Used to add or remove an operator of assets for the caller.
     * @dev Operators can call {acceptAsset}, {rejectAsset}, {rejectAllAssets} or {setPriority} for any token
     *  owned by the caller.
     * @dev Requirements:
     *
     *  - The `operator` cannot be the caller.
     * @dev Emits an {ApprovalForAllForAssets} event.
     * @param operator Address of the account to which the operator role is granted or revoked from
     * @param approved The boolean value indicating whether the operator role is being granted (`true`) or revoked
     *  (`false`)
     */
    function setApprovalForAllForAssets(
        address operator,
        bool approved
    ) external;

    /**
     * @notice Used to check whether the address has been granted the operator role by a given address or not.
     * @dev See {setApprovalForAllForAssets}.
     * @param owner Address of the account that we are checking for whether it has granted the operator role
     * @param operator Address of the account that we are checking whether it has the operator role or not
     * @return A boolean value indicating wehter the account we are checking has been granted the operator role
     */
    function isApprovedForAllForAssets(
        address owner,
        address operator
    ) external view returns (bool);
}

// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.21;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
 * @title IERC7401
 * @author RMRK team
 * @notice Interface smart contract of the RMRK nestable module.
 */
interface IERC7401 is IERC165 {
    /**
     * @notice The core struct of RMRK ownership.
     * @dev The `DirectOwner` struct is used to store information of the next immediate owner, be it the parent token or
     *  the externally owned account.
     * @dev If the token is owned by the externally owned account, the `tokenId` should equal `0`.
     * @param tokenId ID of the parent token
     * @param ownerAddress Address of the owner of the token. If the owner is another token, then the address should be
     *  the one of the parent token's collection smart contract. If the owner is externally owned account, the address
     *  should be the address of this account
     * @param isNft A boolean value signifying whether the token is owned by another token (`true`) or by an externally
     *  owned account (`false`)
     */
    struct DirectOwner {
        uint256 tokenId;
        address ownerAddress;
    }

    /**
     * @notice Used to notify listeners that the token is being transferred.
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     * @param from Address of the previous immediate owner, which is a smart contract if the token was nested.
     * @param to Address of the new immediate owner, which is a smart contract if the token is being nested.
     * @param fromTokenId ID of the previous parent token. If the token was not nested before, the value should be `0`
     * @param toTokenId ID of the new parent token. If the token is not being nested, the value should be `0`
     * @param tokenId ID of the token being transferred
     */
    event NestTransfer(
        address indexed from,
        address indexed to,
        uint256 fromTokenId,
        uint256 toTokenId,
        uint256 indexed tokenId
    );

    /**
     * @notice Used to notify listeners that a new token has been added to a given token's pending children array.
     * @dev Emitted when a child NFT is added to a token's pending array.
     * @param tokenId ID of the token that received a new pending child token
     * @param childIndex Index of the proposed child token in the parent token's pending children array
     * @param childAddress Address of the proposed child token's collection smart contract
     * @param childId ID of the child token in the child token's collection smart contract
     */
    event ChildProposed(
        uint256 indexed tokenId,
        uint256 childIndex,
        address indexed childAddress,
        uint256 indexed childId
    );

    /**
     * @notice Used to notify listeners that a new child token was accepted by the parent token.
     * @dev Emitted when a parent token accepts a token from its pending array, migrating it to the active array.
     * @param tokenId ID of the token that accepted a new child token
     * @param childIndex Index of the newly accepted child token in the parent token's active children array
     * @param childAddress Address of the child token's collection smart contract
     * @param childId ID of the child token in the child token's collection smart contract
     */
    event ChildAccepted(
        uint256 indexed tokenId,
        uint256 childIndex,
        address indexed childAddress,
        uint256 indexed childId
    );

    /**
     * @notice Used to notify listeners that all pending child tokens of a given token have been rejected.
     * @dev Emitted when a token removes all a child tokens from its pending array.
     * @param tokenId ID of the token that rejected all of the pending children
     */
    event AllChildrenRejected(uint256 indexed tokenId);

    /**
     * @notice Used to notify listeners a child token has been transferred from parent token.
     * @dev Emitted when a token transfers a child from itself, transferring ownership to the root owner.
     * @param tokenId ID of the token that transferred a child token
     * @param childIndex Index of a child in the array from which it is being transferred
     * @param childAddress Address of the child token's collection smart contract
     * @param childId ID of the child token in the child token's collection smart contract
     * @param fromPending A boolean value signifying whether the token was in the pending child tokens array (`true`) or
     *  in the active child tokens array (`false`)
     * @param toZero A boolean value signifying whether the token is being transferred to the `0x0` address (`true`) or
     *  not (`false`)
     */
    event ChildTransferred(
        uint256 indexed tokenId,
        uint256 childIndex,
        address indexed childAddress,
        uint256 indexed childId,
        bool fromPending,
        bool toZero
    );

    /**
     * @notice The core child token struct, holding the information about the child tokens.
     * @return tokenId ID of the child token in the child token's collection smart contract
     * @return contractAddress Address of the child token's smart contract
     */
    struct Child {
        uint256 tokenId;
        address contractAddress;
    }

    /**
     * @notice Used to retrieve the *root* owner of a given token.
     * @dev The *root* owner of the token is an externally owned account (EOA). If the given token is child of another
     *  NFT, this will return an EOA address. Otherwise, if the token is owned by an EOA, this EOA wil be returned.
     * @param tokenId ID of the token for which the *root* owner has been retrieved
     * @return owner The *root* owner of the token
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @notice Used to retrieve the immediate owner of the given token.
     * @dev If the immediate owner is another token, the address returned, should be the one of the parent token's
     *  collection smart contract.
     * @param tokenId ID of the token for which the RMRK owner is being retrieved
     * @return Address of the given token's owner
     * @return The ID of the parent token. Should be `0` if the owner is an externally owned account
     * @return The boolean value signifying whether the owner is an NFT or not
     */
    function directOwnerOf(
        uint256 tokenId
    ) external view returns (address, uint256, bool);

    /**
     * @notice Used to burn a given token.
     * @dev When a token is burned, all of its child tokens are recursively burned as well.
     * @dev When specifying the maximum recursive burns, the execution will be reverted if there are more children to be
     *  burned.
     * @dev Setting the `maxRecursiveBurn` value to 0 will only attempt to burn the specified token and revert if there
     *  are any child tokens present.
     * @dev The approvals are cleared when the token is burned.
     * @dev Requirements:
     *
     *  - `tokenId` must exist.
     * @dev Emits a {Transfer} event.
     * @param tokenId ID of the token to burn
     * @param maxRecursiveBurns Maximum number of tokens to recursively burn
     * @return Number of recursively burned children
     */
    function burn(
        uint256 tokenId,
        uint256 maxRecursiveBurns
    ) external returns (uint256);

    /**
     * @notice Used to add a child token to a given parent token.
     * @dev This adds the child token into the given parent token's pending child tokens array.
     * @dev Requirements:
     *
     *  - `directOwnerOf` on the child contract must resolve to the called contract.
     *  - the pending array of the parent contract must not be full.
     * @param parentId ID of the parent token to receive the new child token
     * @param childId ID of the new proposed child token
     * @param data Additional data with no specified format
     */
    function addChild(
        uint256 parentId,
        uint256 childId,
        bytes memory data
    ) external;

    /**
     * @notice Used to accept a pending child token for a given parent token.
     * @dev This moves the child token from parent token's pending child tokens array into the active child tokens
     *  array.
     * @param parentId ID of the parent token for which the child token is being accepted
     * @param childIndex Index of a child tokem in the given parent's pending children array
     * @param childAddress Address of the collection smart contract of the child token expected to be located at the
     *  specified index of the given parent token's pending children array
     * @param childId ID of the child token expected to be located at the specified index of the given parent token's
     *  pending children array
     */
    function acceptChild(
        uint256 parentId,
        uint256 childIndex,
        address childAddress,
        uint256 childId
    ) external;

    /**
     * @notice Used to reject all pending children of a given parent token.
     * @dev Removes the children from the pending array mapping.
     * @dev This does not update the ownership storage data on children. If necessary, ownership can be reclaimed by the
     *  rootOwner of the previous parent.
     * @dev Requirements:
     *
     * Requirements:
     *
     * - `parentId` must exist
     * @param parentId ID of the parent token for which to reject all of the pending tokens.
     * @param maxRejections Maximum number of expected children to reject, used to prevent from rejecting children which
     *  arrive just before this operation.
     */
    function rejectAllChildren(
        uint256 parentId,
        uint256 maxRejections
    ) external;

    /**
     * @notice Used to transfer a child token from a given parent token.
     * @dev When transferring a child token, the owner of the token is set to `to`, or is not updated in the event of
     *  `to` being the `0x0` address.
     * @param tokenId ID of the parent token from which the child token is being transferred
     * @param to Address to which to transfer the token to
     * @param destinationId ID of the token to receive this child token (MUST be 0 if the destination is not a token)
     * @param childIndex Index of a token we are transferring, in the array it belongs to (can be either active array or
     *  pending array)
     * @param childAddress Address of the child token's collection smart contract.
     * @param childId ID of the child token in its own collection smart contract.
     * @param isPending A boolean value indicating whether the child token being transferred is in the pending array of
     *  the parent token (`true`) or in the active array (`false`)
     * @param data Additional data with no specified format, sent in call to `_to`
     */
    function transferChild(
        uint256 tokenId,
        address to,
        uint256 destinationId,
        uint256 childIndex,
        address childAddress,
        uint256 childId,
        bool isPending,
        bytes memory data
    ) external;

    /**
     * @notice Used to retrieve the active child tokens of a given parent token.
     * @dev Returns array of Child structs existing for parent token.
     * @dev The Child struct consists of the following values:
     *  [
     *      tokenId,
     *      contractAddress
     *  ]
     * @param parentId ID of the parent token for which to retrieve the active child tokens
     * @return An array of Child structs containing the parent token's active child tokens
     */
    function childrenOf(
        uint256 parentId
    ) external view returns (Child[] memory);

    /**
     * @notice Used to retrieve the pending child tokens of a given parent token.
     * @dev Returns array of pending Child structs existing for given parent.
     * @dev The Child struct consists of the following values:
     *  [
     *      tokenId,
     *      contractAddress
     *  ]
     * @param parentId ID of the parent token for which to retrieve the pending child tokens
     * @return An array of Child structs containing the parent token's pending child tokens
     */
    function pendingChildrenOf(
        uint256 parentId
    ) external view returns (Child[] memory);

    /**
     * @notice Used to retrieve a specific active child token for a given parent token.
     * @dev Returns a single Child struct locating at `index` of parent token's active child tokens array.
     * @dev The Child struct consists of the following values:
     *  [
     *      tokenId,
     *      contractAddress
     *  ]
     * @param parentId ID of the parent token for which the child is being retrieved
     * @param index Index of the child token in the parent token's active child tokens array
     * @return A Child struct containing data about the specified child
     */
    function childOf(
        uint256 parentId,
        uint256 index
    ) external view returns (Child memory);

    /**
     * @notice Used to retrieve a specific pending child token from a given parent token.
     * @dev Returns a single Child struct locating at `index` of parent token's active child tokens array.
     * @dev The Child struct consists of the following values:
     *  [
     *      tokenId,
     *      contractAddress
     *  ]
     * @param parentId ID of the parent token for which the pending child token is being retrieved
     * @param index Index of the child token in the parent token's pending child tokens array
     * @return A Child struct containting data about the specified child
     */
    function pendingChildOf(
        uint256 parentId,
        uint256 index
    ) external view returns (Child memory);

    /**
     * @notice Used to transfer the token into another token.
     * @param from Address of the direct owner of the token to be transferred
     * @param to Address of the receiving token's collection smart contract
     * @param tokenId ID of the token being transferred
     * @param destinationId ID of the token to receive the token being transferred
     * @param data Additional data with no specified format, sent in the addChild call
     */
    function nestTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        uint256 destinationId,
        bytes memory data
    ) external;
}

// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.21;

interface INameChangeTicket {
    function balanceOf(address owner) external view returns (uint256);

    function useTicket(address owner) external;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"snakeSoldiers","type":"address"},{"internalType":"address","name":"elementGems","type":"address"},{"internalType":"address","name":"skillGems","type":"address"},{"internalType":"address","name":"factionGems","type":"address"},{"internalType":"address","name":"landscapes","type":"address"},{"internalType":"address","name":"attributesRepository","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotChangeName","type":"error"},{"inputs":[],"name":"NameChangeTicketNeeded","type":"error"},{"inputs":[],"name":"NotEnoughFreePoints","type":"error"},{"inputs":[],"name":"NotOwnedSnake","type":"error"},{"inputs":[],"name":"RMRKNewContributorIsZeroAddress","type":"error"},{"inputs":[],"name":"RMRKNewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"RMRKNotOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"},{"indexed":false,"internalType":"bool","name":"isContributor","type":"bool"}],"name":"ContributorUpdate","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"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats","name":"stats","type":"tuple"},{"components":[{"internalType":"int16","name":"elementElement","type":"int16"},{"internalType":"uint8","name":"elementSkill","type":"uint8"},{"internalType":"uint8","name":"elementTerritory","type":"uint8"},{"internalType":"uint8","name":"factionTerritory","type":"uint8"},{"internalType":"uint8","name":"forest","type":"uint8"},{"internalType":"uint8","name":"landscape","type":"uint8"}],"internalType":"struct AttributesManager.BattleBoostsPercentage","name":"boosts","type":"tuple"}],"name":"applyBoosts","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats","name":"adjustedStats","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats[]","name":"allStats","type":"tuple[]"}],"name":"batchSetStats","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats","name":"challengerStats","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats","name":"challengedStats","type":"tuple"},{"internalType":"enum AttributesManager.Faction","name":"challengeTerritory","type":"uint8"},{"internalType":"bool","name":"challengeDayNight","type":"bool"}],"name":"getAdjustedStatsForBothSnakes","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats","name":"challengerAdjustedStats","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats","name":"challengedAdjustedStats","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"soldierId","type":"uint256"},{"internalType":"enum AttributesManager.Element","name":"enemyElement","type":"uint8"}],"name":"getBoostedStatsForSnake","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats","name":"boostedStats","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBoostsConfig","outputs":[{"internalType":"uint8","name":"landscapeTerritoryBoost","type":"uint8"},{"internalType":"uint8","name":"landscapeDaynightBoost","type":"uint8"},{"internalType":"uint8","name":"elementSkillBoost","type":"uint8"},{"internalType":"uint8","name":"elementTerritoryBoost","type":"uint8"},{"internalType":"uint8","name":"factionTerritoryBoost","type":"uint8"},{"internalType":"uint8","name":"forestBoost","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"soldierId","type":"uint256"},{"internalType":"enum AttributesManager.Element","name":"enemyElement","type":"uint8"}],"name":"getBoostsForSnake","outputs":[{"components":[{"internalType":"int16","name":"elementElement","type":"int16"},{"internalType":"uint8","name":"elementSkill","type":"uint8"},{"internalType":"uint8","name":"elementTerritory","type":"uint8"},{"internalType":"uint8","name":"factionTerritory","type":"uint8"},{"internalType":"uint8","name":"forest","type":"uint8"},{"internalType":"uint8","name":"landscape","type":"uint8"}],"internalType":"struct AttributesManager.BattleBoostsPercentage","name":"boosts","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum AttributesManager.Element","name":"element","type":"uint8"},{"internalType":"enum AttributesManager.Faction","name":"faction","type":"uint8"},{"internalType":"enum AttributesManager.Skill","name":"skill","type":"uint8"},{"internalType":"enum AttributesManager.Landscape","name":"landscape","type":"uint8"}],"internalType":"struct AttributesManager.EquippedItems","name":"items","type":"tuple"},{"internalType":"enum AttributesManager.Faction","name":"challengeTerritory","type":"uint8"},{"internalType":"bool","name":"challengeDayNight","type":"bool"},{"internalType":"enum AttributesManager.Element","name":"enemyElement","type":"uint8"}],"name":"getBoostsFromGemsTerritoryAndCelestialPhase","outputs":[{"components":[{"internalType":"int16","name":"elementElement","type":"int16"},{"internalType":"uint8","name":"elementSkill","type":"uint8"},{"internalType":"uint8","name":"elementTerritory","type":"uint8"},{"internalType":"uint8","name":"factionTerritory","type":"uint8"},{"internalType":"uint8","name":"forest","type":"uint8"},{"internalType":"uint8","name":"landscape","type":"uint8"}],"internalType":"struct AttributesManager.BattleBoostsPercentage","name":"boosts","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getCurrentLandAndDayNight","outputs":[{"internalType":"enum AttributesManager.Faction","name":"currentLand","type":"uint8"},{"internalType":"bool","name":"currentDayNight","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats","name":"stats","type":"tuple"}],"name":"getCurrentStamina","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"soldierId","type":"uint256"}],"name":"getCustomName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AttributesManager.Element","name":"element","type":"uint8"},{"internalType":"enum AttributesManager.Skill","name":"skill","type":"uint8"}],"name":"getElementSkillBoost","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum AttributesManager.Element","name":"element","type":"uint8"},{"internalType":"enum AttributesManager.Faction","name":"territory","type":"uint8"}],"name":"getElementTerritoryBoost","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"soldierId","type":"uint256"}],"name":"getEquippedItems","outputs":[{"components":[{"internalType":"enum AttributesManager.Element","name":"element","type":"uint8"},{"internalType":"enum AttributesManager.Faction","name":"faction","type":"uint8"},{"internalType":"enum AttributesManager.Skill","name":"skill","type":"uint8"},{"internalType":"enum AttributesManager.Landscape","name":"landscape","type":"uint8"}],"internalType":"struct AttributesManager.EquippedItems","name":"items","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AttributesManager.Faction","name":"faction","type":"uint8"},{"internalType":"enum AttributesManager.Faction","name":"territory","type":"uint8"}],"name":"getFactionTerritoryBoost","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum AttributesManager.Element","name":"elementA","type":"uint8"},{"internalType":"enum AttributesManager.Element","name":"elementB","type":"uint8"}],"name":"getFightingElementsBoost","outputs":[{"internalType":"int16","name":"","type":"int16"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum AttributesManager.Faction","name":"faction","type":"uint8"}],"name":"getForestBoost","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum AttributesManager.Landscape","name":"landscape","type":"uint8"},{"internalType":"enum AttributesManager.Faction","name":"challengeTerritory","type":"uint8"},{"internalType":"bool","name":"challengeDayNight","type":"bool"}],"name":"getLandscapeBoost","outputs":[{"internalType":"uint8","name":"boost","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"soldierId","type":"uint256"}],"name":"getStats","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats","name":"stats","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"isContributor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"},{"internalType":"bool","name":"grantRole","type":"bool"}],"name":"manageContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"landscapeTerritoryBoost","type":"uint8"},{"internalType":"uint8","name":"landscapeDaynightBoost","type":"uint8"},{"internalType":"uint8","name":"elementSkillBoost","type":"uint8"},{"internalType":"uint8","name":"elementTerritoryBoost","type":"uint8"},{"internalType":"uint8","name":"factionTerritoryBoost","type":"uint8"},{"internalType":"uint8","name":"forestBoost","type":"uint8"}],"name":"setBoostsConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"soldierId","type":"uint256"},{"internalType":"string","name":"name","type":"string"}],"name":"setCustomName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nameChangeTicket","type":"address"}],"name":"setNameChangeTicketAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"soldierId","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"}],"name":"useFreePoints","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"health","type":"uint24"},{"internalType":"uint24","name":"stamina","type":"uint24"},{"internalType":"uint24","name":"maxHealth","type":"uint24"},{"internalType":"uint24","name":"maxStamina","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"},{"internalType":"uint16","name":"freePoints","type":"uint16"},{"internalType":"uint32","name":"experience","type":"uint32"},{"internalType":"uint32","name":"lastStatsUpdate","type":"uint32"}],"internalType":"struct AttributesManager.BattleStats","name":"stats","type":"tuple"}],"stateMutability":"nonpayable","type":"function"}]

6080604052600280556003805465ffffffffffff1916650a0a0a0a05051790553480156200002b575f80fd5b5060405162002e1c38038062002e1c8339810160408190526200004e9162000149565b6200005933620000de565b600380546001600160a01b03978816660100000000000002600160301b600160d01b0319909116179055600480549587166001600160a01b0319968716179055600580549487169486169490941790935560068054928616928516929092179091556007805491851691841691909117905560098054919093169116179055620001c6565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b038116811462000144575f80fd5b919050565b5f805f805f8060c087890312156200015f575f80fd5b6200016a876200012d565b95506200017a602088016200012d565b94506200018a604088016200012d565b93506200019a606088016200012d565b9250620001aa608088016200012d565b9150620001ba60a088016200012d565b90509295509295509295565b612c4880620001d45f395ff3fe608060405234801561000f575f80fd5b50600436106101a1575f3560e01c8063766d8019116100f3578063d8e7c8e311610093578063e2994ae21161006e578063e2994ae214610490578063e3633c94146104a3578063f2fde38b146104c9578063f682133b146104dc575f80fd5b8063d8e7c8e31461044a578063ddfbf2321461045d578063e1cb414814610470575f80fd5b80637bf8d90f116100ce5780637bf8d90f146103e95780638da5cb5b146103fc5780638f37df7d14610416578063beb738a314610429575f80fd5b8063766d8019146103b057806379e8ca9e146103c35780637b303965146103d6575f80fd5b80633440c75d1161015e5780636e40c757116101395780636e40c75714610321578063715018a614610334578063726c6d9a1461033c57806372a55c2d1461039a575f80fd5b80633440c75d146102d957806343d2cbcb146102f95780635f54092d1461030e575f80fd5b80630e4fc78a146101a55780631399e9791461021e578063193ec777146102315780631cb238b5146102565780631d0d35f51461027d578063228c1eeb146102b9575b5f80fd5b6101b86101b3366004611eb1565b6104ef565b60405161021591905f60c082019050825160010b825260ff602084015116602083015260ff604084015116604083015260ff606084015116606083015260ff608084015116608083015260ff60a08401511660a083015292915050565b60405180910390f35b6101b861022c366004611fb9565b61054f565b61024461023f36600461207b565b61060a565b60405160ff9091168152602001610215565b61026961026436600461219c565b610638565b60405162ffffff9091168152602001610215565b6102a961028b3660046121cb565b6001600160a01b03165f908152600160208190526040909120541490565b6040519015158152602001610215565b6102cc6102c73660046121e6565b6106cb565b6040516102159190612316565b6102ec6102e7366004612325565b6107bd565b6040516102159190612389565b61030c6103073660046123c1565b61085e565b005b61024461031c366004612444565b610a14565b6102cc61032f366004612487565b610a6e565b61030c610b6e565b6003546040805160ff80841682526101008404811660208301526201000084048116928201929092526301000000830482166060820152640100000000830482166080820152650100000000009092041660a082015260c001610215565b6103a2610b81565b604051610215929190612564565b6102446103be366004612581565b610bcd565b61030c6103d136600461259b565b610c0e565b6102cc6103e4366004612325565b610cc9565b61030c6103f73660046125c7565b610e10565b5f546040516001600160a01b039091168152602001610215565b6102cc610424366004611eb1565b610e98565b61043c610437366004612637565b610eeb565b604051610215929190612685565b61030c6104583660046126c4565b610f62565b61024461046b366004612759565b610fa4565b61048361047e366004612325565b6113ea565b60405161021591906127ad565b61030c61049e3660046121cb565b611798565b6104b66104b1366004612809565b6117c2565b60405160019190910b8152602001610215565b61030c6104d73660046121cb565b611adc565b6102446104ea366004612809565b611b17565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905290610529846113ea565b90505f80610535610b81565b915091506105458383838861054f565b9695505050505050565b6040805160c0810182525f80825260208201819052818301819052606082018190526080820181905260a0820152855191860151909161058e91611b17565b60ff166020808301919091528501516105a79085610bcd565b60ff16606082015284516105bb9085610a14565b60ff16604082015260208501516105d19061060a565b60ff16608082015284516105e590836117c2565b60010b815260608501516105fa908585610fa4565b60ff1660a0820152949350505050565b5f600482600581111561061f5761061f61253c565b0361062c5750600a919050565b505f919050565b919050565b5f81610140015163ffffffff165f03610653575060c0015190565b5f600254610e1084610140015163ffffffff16426106719190612849565b61067b9190612870565b6106859190612883565b90508260c0015162ffffff168360800151826106a1919061289a565b62ffffff1611156106b557505060c0015190565b60808301516106c4908261289a565b9392505050565b6106d3611e4a565b856106dd81611b51565b6106e687610cc9565b91505f83856106f5888a61289a565b6106ff919061289a565b610709919061289a565b905082610100015161ffff168162ffffff16111561073a576040516336fbeeab60e21b815260040160405180910390fd5b868360200181815161074c919061289a565b62ffffff1690525060408301805187919061076890839061289a565b62ffffff1690525060a08301805186919061078490839061289a565b62ffffff1690525060c0830180518591906107a090839061289a565b62ffffff169052506107b2835f611bee565b505095945050505050565b6009546003546040805180820182526004808252634e414d4560e01b60208301529151632c6bd61b60e11b81526060946001600160a01b03908116946358d7ac369461081794600160301b909204909216928892016128bd565b5f60405180830381865afa158015610831573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261085891908101906128ec565b92915050565b8161086881611b51565b5f610872846107bd565b805190915015610986576008546001600160a01b03166108a457604051625e364b60e11b815260040160405180910390fd5b6008546040516370a0823160e01b81523360048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156108ea573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061090e9190612954565b5f0361092d57604051639e28e8df60e01b815260040160405180910390fd5b600854604051631a1760c960e31b81523360048201526001600160a01b039091169063d0bb0648906024015f604051808303815f87803b15801561096f575f80fd5b505af1158015610981573d5f803e3d5ffd5b505050505b6009546003546040805180820182526004808252634e414d4560e01b6020830152915163cedb3f8960e01b81526001600160a01b039485169463cedb3f89946109e194600160301b909104909116928a9290918a910161296b565b5f604051808303815f87803b1580156109f8575f80fd5b505af1158015610a0a573d5f803e3d5ffd5b5050505050505050565b5f816005811115610a2757610a2761253c565b836004811115610a3957610a3961253c565b148015610a59575060045b836004811115610a5657610a5661253c565b14155b15610a665750600a610858565b505f92915050565b610a76611e4a565b50805182905f90610a889060646129ae565b61ffff1690505f836080015160ff168460a0015160ff16856040015160ff16866020015160ff1685610aba91906129d1565b610ac491906129d1565b610ace91906129d1565b610ad891906129d1565b90505f84608001518560a0015186606001516064610af691906129e4565b610b0091906129e4565b610b0a91906129e4565b60ff169050606482876020015162ffffff16610b269190612883565b610b309190612870565b62ffffff90811660208601526040870151606491610b5091849116612883565b610b5a9190612870565b62ffffff1660408501525091949350505050565b610b76611db4565b610b7f5f611dde565b565b5f806002610b9161546042612870565b610b9b91906129fd565b1590506005610bac61a8c042612870565b610bb691906129fd565b6005811115610bc757610bc761253c565b91509091565b5f816005811115610be057610be061253c565b836005811115610bf257610bf261253c565b148015610a5957506005836005811115610a5657610a5661253c565b610c16611db4565b6001600160a01b038216610c3d5760405163016b812760e71b815260040160405180910390fd5b80610c61576001600160a01b0382165f908152600160205260408120819055610c7f565b6001600160a01b0382165f9081526001602081905260409091208190555b50816001600160a01b03167f4b5657e84cf8a17ac5587bbeb3cc2bab9826c4c67b8bad81b4849de49d37aac282604051610cbd911515815260200190565b60405180910390a25050565b610cd1611e4a565b6009546003546040805180820182526005815264535441545360d81b60208201529051631b8bfea360e01b81525f936001600160a01b0390811693631b8bfea393610d2c93600160301b9092049092169188916004016128bd565b602060405180830381865afa158015610d47573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d6b9190612954565b83835262ffffff8082166020850152601882901c81166040850152603082901c8116606080860191909152604883901c8216608086015282901c811660a080860191909152607883901c90911660c085015261ffff609083901c811660e08601529082901c1661010084015263ffffffff60b082901c811661012085015260d082901c166101408401529050610e0082610638565b62ffffff16608083015250919050565b610e18611db4565b6003805460ff928316650100000000000265ff000000000019948416640100000000029490941665ffff000000001995841663010000000263ff0000001997851662010000029790971663ffff0000199885166101000261ffff199093169490991693909317179590951695909517929092171692909217919091179055565b610ea0611e4a565b5f610eaa84610cc9565b90505f610eb6856113ea565b90505f80610ec2610b81565b915091505f610ed38484848a61054f565b9050610edf8582610a6e565b98975050505050505050565b610ef3611e4a565b610efb611e4a565b5f610f08875f01516113ea565b90505f610f17875f01516113ea565b90505f610f29838888855f015161054f565b90505f610f3b838989875f015161054f565b9050610f478a83610a6e565b9550610f538982610a6e565b94505050505094509492505050565b610f6a611db4565b5f5b8151811015610fa057610f98828281518110610f8a57610f8a612a10565b60200260200101515f611bee565b600101610f6c565b5050565b5f80836005811115610fb857610fb861253c565b14801561100d5750600484600f811115610fd457610fd461253c565b1480610ff15750600584600f811115610fef57610fef61253c565b145b8061100d5750600684600f81111561100b5761100b61253c565b145b156110245761101d6005826129e4565b905061120b565b60048360058111156110385761103861253c565b14801561108d5750600d84600f8111156110545761105461253c565b14806110715750600e84600f81111561106f5761106f61253c565b145b8061108d5750600f84600f81111561108b5761108b61253c565b145b1561109d5761101d6005826129e4565b60028360058111156110b1576110b161253c565b1480156111065750600184600f8111156110cd576110cd61253c565b14806110ea5750600284600f8111156110e8576110e861253c565b145b806111065750600384600f8111156111045761110461253c565b145b156111165761101d6005826129e4565b600183600581111561112a5761112a61253c565b14801561117f5750600a84600f8111156111465761114661253c565b14806111635750600b84600f8111156111615761116161253c565b145b8061117f5750600c84600f81111561117d5761117d61253c565b145b1561118f5761101d6005826129e4565b60038360058111156111a3576111a361253c565b1480156111f85750600784600f8111156111bf576111bf61253c565b14806111dc5750600884600f8111156111da576111da61253c565b145b806111f85750600984600f8111156111f6576111f661253c565b145b1561120b576112086005826129e4565b90505b600684600f81111561121f5761121f61253c565b148061123c5750600f84600f81111561123a5761123a61253c565b145b806112585750600384600f8111156112565761125661253c565b145b806112745750600c84600f8111156112725761127261253c565b145b806112905750600984600f81111561128e5761128e61253c565b145b156112a7576112a06005826129e4565b90506106c4565b8180156113345750600484600f8111156112c3576112c361253c565b14806112e05750600d84600f8111156112de576112de61253c565b145b806112fc5750600184600f8111156112fa576112fa61253c565b145b806113185750600a84600f8111156113165761131661253c565b145b806113345750600784600f8111156113325761133261253c565b145b15611344576112a06005826129e4565b811580156113d25750600584600f8111156113615761136161253c565b148061137e5750600e84600f81111561137c5761137c61253c565b145b8061139a5750600284600f8111156113985761139861253c565b145b806113b65750600b84600f8111156113b4576113b461253c565b145b806113d25750600884600f8111156113d0576113d061253c565b145b156106c4576113e26005826129e4565b949350505050565b6114116040805160808101909152805f81526020015f81526020015f81526020015f905290565b600354604051631bc6654760e21b8152600481018490525f91600160301b90046001600160a01b031690636f19951c906024015f60405180830381865afa15801561145e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526114859190810190612a24565b80519091505f5b81811015611790575f8382815181106114a7576114a7612a10565b60209081029190910181015160035491810151815160405163ee1dffcf60e01b8152600481018b90526001600160a01b0392831660248201526044810191909152919350600160301b9092049091169063ee1dffcf90606401602060405180830381865afa15801561151b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061153f9190612ad2565b156117875760045460208201516001600160a01b039182169116036115ab57805161156c906004906129fd565b600481111561157d5761157d61253c565b859060048111156115905761159061253c565b908160048111156115a3576115a361253c565b905250611787565b60055460208201516001600160a01b0391821691160361161f57805160c810156116115780516002906115e0906008906129fd565b6115ea9190612870565b60048111156115fb576115fb61253c565b856040019060048111156115905761159061253c565b80516115ea906004906129fd565b60065460208201516001600160a01b039182169116036116995780516014101561168b578051611651906005906129fd565b60058111156116625761166261253c565b856020019060058111156116785761167861253c565b908160058111156115a3576115a361253c565b8051611651906004906129fd565b60075460208201516001600160a01b03918216911603611787576007548151604051633940140f60e11b815260048101919091525f916001600160a01b031690637280281e906024015f60405180830381865afa1580156116fc573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526117239190810190612aed565b9050805f8151811061173757611737612a10565b60200260200101516001600160401b0316600f8111156117595761175961253c565b8660600190600f81111561176f5761176f61253c565b9081600f8111156117825761178261253c565b905250505b5060010161148c565b505050919050565b6117a0611db4565b600880546001600160a01b0319166001600160a01b0392909216919091179055565b5f60048260048111156117d7576117d761253c565b036117e357505f610858565b5f8360048111156117f6576117f661253c565b148015611814575060038260048111156118125761181261253c565b145b156118215750601e610858565b5f8360048111156118345761183461253c565b148015611852575060018260048111156118505761185061253c565b145b156118605750600419610858565b5f8360048111156118735761187361253c565b1480156118915750600282600481111561188f5761188f61253c565b145b1561189d57505f610858565b60038360048111156118b1576118b161253c565b1480156118ce57505f8260048111156118cc576118cc61253c565b145b156118dc5750600919610858565b60038360048111156118f0576118f061253c565b14801561190e5750600182600481111561190c5761190c61253c565b145b1561191b57506019610858565b600383600481111561192f5761192f61253c565b14801561194d5750600282600481111561194b5761194b61253c565b145b1561195957505f610858565b600183600481111561196d5761196d61253c565b14801561198a57505f8260048111156119885761198861253c565b145b156119975750600a610858565b60018360048111156119ab576119ab61253c565b1480156119c9575060038260048111156119c7576119c761253c565b145b156119d75750601319610858565b60018360048111156119eb576119eb61253c565b148015611a0957506002826004811115611a0757611a0761253c565b145b15611a1657506014610858565b6002836004811115611a2a57611a2a61253c565b148015611a4757505f826004811115611a4557611a4561253c565b145b15611a5457506019610858565b6002836004811115611a6857611a6861253c565b148015611a8657506003826004811115611a8457611a8461253c565b145b15611a9357506005610858565b6002836004811115611aa757611aa761253c565b148015611ac557506001826004811115611ac357611ac361253c565b145b15611ad35750600919610858565b50601319610858565b611ae4611db4565b6001600160a01b038116611b0b57604051634ece6ecf60e01b815260040160405180910390fd5b611b1481611dde565b50565b5f816004811115611b2a57611b2a61253c565b60ff16836004811115611b3f57611b3f61253c565b60ff16148015610a5957506004610a44565b6003546040516331a9108f60e11b8152600481018390525f91600160301b90046001600160a01b031690636352211e90602401602060405180830381865afa158015611b9f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bc39190612b7f565b90506001600160a01b0381163314610fa0576040516334a50d8b60e21b815260040160405180910390fd5b8015611c695761012082015160e083015163ffffffff90911690611c13816001612b9a565b611c1d9190612bb5565b61ffff161115611c695760018260e001818151611c3a9190612b9a565b61ffff1690525060e0820151611c4f90611e2d565b8261010001818151611c619190612b9a565b61ffff169052505b6009546003548351604080518082019091526005815264535441545360d81b60208201526001600160a01b039384169363ed20867293600160301b9004169190611d64875f816020015162ffffff1690506018826040015162ffffff16901b811790506030826060015162ffffff16901b811790506048826080015162ffffff16901b8117905060608260a0015162ffffff16901b8117905060788260c0015162ffffff16901b8117905060908260e0015161ffff16901b8117905060a082610100015161ffff16901b8117905060b082610120015163ffffffff16901b8117905060d082610140015163ffffffff16901b81179050919050565b6040518563ffffffff1660e01b8152600401611d839493929190612bdb565b5f604051808303815f87803b158015611d9a575f80fd5b505af1158015611dac573d5f803e3d5ffd5b505050505050565b5f546001600160a01b03163314610b7f57604051631c62d58f60e11b815260040160405180910390fd5b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f5b61ffff8216156106335761ffff909116801c90600101611e2f565b60408051610160810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b60058110611b14575f80fd5b5f8060408385031215611ec2575f80fd5b823591506020830135611ed481611ea5565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b60405161016081016001600160401b0381118282101715611f1657611f16611edf565b60405290565b60405160c081016001600160401b0381118282101715611f1657611f16611edf565b604080519081016001600160401b0381118282101715611f1657611f16611edf565b604051601f8201601f191681016001600160401b0381118282101715611f8857611f88611edf565b604052919050565b803560068110610633575f80fd5b803560108110610633575f80fd5b8015158114611b14575f80fd5b5f805f8084860360e0811215611fcd575f80fd5b6080811215611fda575f80fd5b50604051608081018181106001600160401b0382111715611ffd57611ffd611edf565b604052853561200b81611ea5565b815261201960208701611f90565b6020820152604086013561202c81611ea5565b604082015261203d60608701611f9e565b6060820152935061205060808601611f90565b925060a085013561206081611fac565b915060c085013561207081611ea5565b939692955090935050565b5f6020828403121561208b575f80fd5b6106c482611f90565b803562ffffff81168114610633575f80fd5b803561ffff81168114610633575f80fd5b803563ffffffff81168114610633575f80fd5b5f61016082840312156120db575f80fd5b6120e3611ef3565b9050813581526120f560208301612094565b602082015261210660408301612094565b604082015261211760608301612094565b606082015261212860808301612094565b608082015261213960a08301612094565b60a082015261214a60c08301612094565b60c082015261215b60e083016120a6565b60e082015261010061216e8184016120a6565b908201526101206121808382016120b7565b908201526101406121928382016120b7565b9082015292915050565b5f61016082840312156121ad575f80fd5b6106c483836120ca565b6001600160a01b0381168114611b14575f80fd5b5f602082840312156121db575f80fd5b81356106c4816121b7565b5f805f805f60a086880312156121fa575f80fd5b8535945061220a60208701612094565b935061221860408701612094565b925061222660608701612094565b915061223460808701612094565b90509295509295909350565b80518252602081015161225a602084018262ffffff169052565b506040810151612271604084018262ffffff169052565b506060810151612288606084018262ffffff169052565b50608081015161229f608084018262ffffff169052565b5060a08101516122b660a084018262ffffff169052565b5060c08101516122cd60c084018262ffffff169052565b5060e08101516122e360e084018261ffff169052565b506101008181015161ffff16908301526101208082015163ffffffff908116918401919091526101409182015116910152565b61016081016108588284612240565b5f60208284031215612335575f80fd5b5035919050565b5f5b8381101561235657818101518382015260200161233e565b50505f910152565b5f815180845261237581602086016020860161233c565b601f01601f19169290920160200192915050565b602081525f6106c4602083018461235e565b5f6001600160401b038211156123b3576123b3611edf565b50601f01601f191660200190565b5f80604083850312156123d2575f80fd5b8235915060208301356001600160401b038111156123ee575f80fd5b8301601f810185136123fe575f80fd5b803561241161240c8261239b565b611f60565b818152866020838501011115612425575f80fd5b816020840160208301375f602083830101528093505050509250929050565b5f8060408385031215612455575f80fd5b823561246081611ea5565b915061246e60208401611f90565b90509250929050565b803560ff81168114610633575f80fd5b5f8082840361022081121561249a575f80fd5b6124a485856120ca565b925060c061015f19820112156124b8575f80fd5b506124c1611f1c565b6101608401358060010b81146124d5575f80fd5b81526124e46101808501612477565b60208201526124f66101a08501612477565b60408201526125086101c08501612477565b606082015261251a6101e08501612477565b608082015261252c6102008501612477565b60a0820152809150509250929050565b634e487b7160e01b5f52602160045260245ffd5b600681106125605761256061253c565b9052565b604081016125728285612550565b82151560208301529392505050565b5f8060408385031215612592575f80fd5b61246083611f90565b5f80604083850312156125ac575f80fd5b82356125b7816121b7565b91506020830135611ed481611fac565b5f805f805f8060c087890312156125dc575f80fd5b6125e587612477565b95506125f360208801612477565b945061260160408801612477565b935061260f60608801612477565b925061261d60808801612477565b915061262b60a08801612477565b90509295509295509295565b5f805f80610300858703121561264b575f80fd5b61265586866120ca565b93506126658661016087016120ca565b92506126746102c08601611f90565b91506102e085013561207081611fac565b6102c081016126948285612240565b6106c4610160830184612240565b5f6001600160401b038211156126ba576126ba611edf565b5060051b60200190565b5f60208083850312156126d5575f80fd5b82356001600160401b038111156126ea575f80fd5b8301601f810185136126fa575f80fd5b803561270861240c826126a2565b8181526101609182028301840191848201919088841115612727575f80fd5b938501935b8385101561274d5761273e89866120ca565b8352938401939185019161272c565b50979650505050505050565b5f805f6060848603121561276b575f80fd5b61277484611f9e565b925061278260208501611f90565b9150604084013561279281611fac565b809150509250925092565b60058110611b1457611b1461253c565b815160808201906127bd8161279d565b8083525060208301516127d36020840182612550565b5060408301516127e28161279d565b60408301526060830151601081106127fc576127fc61253c565b8060608401525092915050565b5f806040838503121561281a575f80fd5b823561282581611ea5565b91506020830135611ed481611ea5565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561085857610858612835565b634e487b7160e01b5f52601260045260245ffd5b5f8261287e5761287e61285c565b500490565b808202811582820484141761085857610858612835565b62ffffff8181168382160190808211156128b6576128b6612835565b5092915050565b60018060a01b0384168152826020820152606060408201525f6128e3606083018461235e565b95945050505050565b5f602082840312156128fc575f80fd5b81516001600160401b03811115612911575f80fd5b8201601f81018413612921575f80fd5b805161292f61240c8261239b565b818152856020838501011115612943575f80fd5b6128e382602083016020860161233c565b5f60208284031215612964575f80fd5b5051919050565b60018060a01b0385168152836020820152608060408201525f612991608083018561235e565b82810360608401526129a3818561235e565b979650505050505050565b600181810b9083900b01617fff8113617fff198212171561085857610858612835565b8082018082111561085857610858612835565b60ff818116838216019081111561085857610858612835565b5f82612a0b57612a0b61285c565b500690565b634e487b7160e01b5f52603260045260245ffd5b5f6020808385031215612a35575f80fd5b82516001600160401b03811115612a4a575f80fd5b8301601f81018513612a5a575f80fd5b8051612a6861240c826126a2565b81815260069190911b82018301908381019087831115612a86575f80fd5b928401925b828410156129a35760408489031215612aa3575f8081fd5b612aab611f3e565b8451815285850151612abc816121b7565b8187015282526040939093019290840190612a8b565b5f60208284031215612ae2575f80fd5b81516106c481611fac565b5f6020808385031215612afe575f80fd5b82516001600160401b0380821115612b14575f80fd5b818501915085601f830112612b27575f80fd5b8151612b3561240c826126a2565b81815260059190911b83018401908481019088831115612b53575f80fd5b938501935b82851015610edf5784518481168114612b70575f8081fd5b82529385019390850190612b58565b5f60208284031215612b8f575f80fd5b81516106c4816121b7565b61ffff8181168382160190808211156128b6576128b6612835565b61ffff818116838216028082169190828114612bd357612bd3612835565b505092915050565b60018060a01b0385168152836020820152608060408201525f612c01608083018561235e565b90508260608301529594505050505056fea2646970667358221220bb4edadb5a97706c5cf4c36da78838cb7ae3af21f694b234a6241136da6f0cc064736f6c634300081500330000000000000000000000008f64ce931f0d36430b971548b81264eef3bd9b97000000000000000000000000a5b355125a2b7fd4c7a451c37b87e81b965a96b10000000000000000000000009e5babfad9a1a980b58db60585408735562b721e0000000000000000000000003f563d6d8e62405d01dc8a4e1dfb269f23aab1620000000000000000000000008e8e3ab3bfabb86b37f91b2f2ca83969ac2c0fad000000000000000000000000873526404f04d88bf7b4a8598b00a766a3393128

Deployed Bytecode

0x608060405234801561000f575f80fd5b50600436106101a1575f3560e01c8063766d8019116100f3578063d8e7c8e311610093578063e2994ae21161006e578063e2994ae214610490578063e3633c94146104a3578063f2fde38b146104c9578063f682133b146104dc575f80fd5b8063d8e7c8e31461044a578063ddfbf2321461045d578063e1cb414814610470575f80fd5b80637bf8d90f116100ce5780637bf8d90f146103e95780638da5cb5b146103fc5780638f37df7d14610416578063beb738a314610429575f80fd5b8063766d8019146103b057806379e8ca9e146103c35780637b303965146103d6575f80fd5b80633440c75d1161015e5780636e40c757116101395780636e40c75714610321578063715018a614610334578063726c6d9a1461033c57806372a55c2d1461039a575f80fd5b80633440c75d146102d957806343d2cbcb146102f95780635f54092d1461030e575f80fd5b80630e4fc78a146101a55780631399e9791461021e578063193ec777146102315780631cb238b5146102565780631d0d35f51461027d578063228c1eeb146102b9575b5f80fd5b6101b86101b3366004611eb1565b6104ef565b60405161021591905f60c082019050825160010b825260ff602084015116602083015260ff604084015116604083015260ff606084015116606083015260ff608084015116608083015260ff60a08401511660a083015292915050565b60405180910390f35b6101b861022c366004611fb9565b61054f565b61024461023f36600461207b565b61060a565b60405160ff9091168152602001610215565b61026961026436600461219c565b610638565b60405162ffffff9091168152602001610215565b6102a961028b3660046121cb565b6001600160a01b03165f908152600160208190526040909120541490565b6040519015158152602001610215565b6102cc6102c73660046121e6565b6106cb565b6040516102159190612316565b6102ec6102e7366004612325565b6107bd565b6040516102159190612389565b61030c6103073660046123c1565b61085e565b005b61024461031c366004612444565b610a14565b6102cc61032f366004612487565b610a6e565b61030c610b6e565b6003546040805160ff80841682526101008404811660208301526201000084048116928201929092526301000000830482166060820152640100000000830482166080820152650100000000009092041660a082015260c001610215565b6103a2610b81565b604051610215929190612564565b6102446103be366004612581565b610bcd565b61030c6103d136600461259b565b610c0e565b6102cc6103e4366004612325565b610cc9565b61030c6103f73660046125c7565b610e10565b5f546040516001600160a01b039091168152602001610215565b6102cc610424366004611eb1565b610e98565b61043c610437366004612637565b610eeb565b604051610215929190612685565b61030c6104583660046126c4565b610f62565b61024461046b366004612759565b610fa4565b61048361047e366004612325565b6113ea565b60405161021591906127ad565b61030c61049e3660046121cb565b611798565b6104b66104b1366004612809565b6117c2565b60405160019190910b8152602001610215565b61030c6104d73660046121cb565b611adc565b6102446104ea366004612809565b611b17565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905290610529846113ea565b90505f80610535610b81565b915091506105458383838861054f565b9695505050505050565b6040805160c0810182525f80825260208201819052818301819052606082018190526080820181905260a0820152855191860151909161058e91611b17565b60ff166020808301919091528501516105a79085610bcd565b60ff16606082015284516105bb9085610a14565b60ff16604082015260208501516105d19061060a565b60ff16608082015284516105e590836117c2565b60010b815260608501516105fa908585610fa4565b60ff1660a0820152949350505050565b5f600482600581111561061f5761061f61253c565b0361062c5750600a919050565b505f919050565b919050565b5f81610140015163ffffffff165f03610653575060c0015190565b5f600254610e1084610140015163ffffffff16426106719190612849565b61067b9190612870565b6106859190612883565b90508260c0015162ffffff168360800151826106a1919061289a565b62ffffff1611156106b557505060c0015190565b60808301516106c4908261289a565b9392505050565b6106d3611e4a565b856106dd81611b51565b6106e687610cc9565b91505f83856106f5888a61289a565b6106ff919061289a565b610709919061289a565b905082610100015161ffff168162ffffff16111561073a576040516336fbeeab60e21b815260040160405180910390fd5b868360200181815161074c919061289a565b62ffffff1690525060408301805187919061076890839061289a565b62ffffff1690525060a08301805186919061078490839061289a565b62ffffff1690525060c0830180518591906107a090839061289a565b62ffffff169052506107b2835f611bee565b505095945050505050565b6009546003546040805180820182526004808252634e414d4560e01b60208301529151632c6bd61b60e11b81526060946001600160a01b03908116946358d7ac369461081794600160301b909204909216928892016128bd565b5f60405180830381865afa158015610831573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261085891908101906128ec565b92915050565b8161086881611b51565b5f610872846107bd565b805190915015610986576008546001600160a01b03166108a457604051625e364b60e11b815260040160405180910390fd5b6008546040516370a0823160e01b81523360048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156108ea573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061090e9190612954565b5f0361092d57604051639e28e8df60e01b815260040160405180910390fd5b600854604051631a1760c960e31b81523360048201526001600160a01b039091169063d0bb0648906024015f604051808303815f87803b15801561096f575f80fd5b505af1158015610981573d5f803e3d5ffd5b505050505b6009546003546040805180820182526004808252634e414d4560e01b6020830152915163cedb3f8960e01b81526001600160a01b039485169463cedb3f89946109e194600160301b909104909116928a9290918a910161296b565b5f604051808303815f87803b1580156109f8575f80fd5b505af1158015610a0a573d5f803e3d5ffd5b5050505050505050565b5f816005811115610a2757610a2761253c565b836004811115610a3957610a3961253c565b148015610a59575060045b836004811115610a5657610a5661253c565b14155b15610a665750600a610858565b505f92915050565b610a76611e4a565b50805182905f90610a889060646129ae565b61ffff1690505f836080015160ff168460a0015160ff16856040015160ff16866020015160ff1685610aba91906129d1565b610ac491906129d1565b610ace91906129d1565b610ad891906129d1565b90505f84608001518560a0015186606001516064610af691906129e4565b610b0091906129e4565b610b0a91906129e4565b60ff169050606482876020015162ffffff16610b269190612883565b610b309190612870565b62ffffff90811660208601526040870151606491610b5091849116612883565b610b5a9190612870565b62ffffff1660408501525091949350505050565b610b76611db4565b610b7f5f611dde565b565b5f806002610b9161546042612870565b610b9b91906129fd565b1590506005610bac61a8c042612870565b610bb691906129fd565b6005811115610bc757610bc761253c565b91509091565b5f816005811115610be057610be061253c565b836005811115610bf257610bf261253c565b148015610a5957506005836005811115610a5657610a5661253c565b610c16611db4565b6001600160a01b038216610c3d5760405163016b812760e71b815260040160405180910390fd5b80610c61576001600160a01b0382165f908152600160205260408120819055610c7f565b6001600160a01b0382165f9081526001602081905260409091208190555b50816001600160a01b03167f4b5657e84cf8a17ac5587bbeb3cc2bab9826c4c67b8bad81b4849de49d37aac282604051610cbd911515815260200190565b60405180910390a25050565b610cd1611e4a565b6009546003546040805180820182526005815264535441545360d81b60208201529051631b8bfea360e01b81525f936001600160a01b0390811693631b8bfea393610d2c93600160301b9092049092169188916004016128bd565b602060405180830381865afa158015610d47573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d6b9190612954565b83835262ffffff8082166020850152601882901c81166040850152603082901c8116606080860191909152604883901c8216608086015282901c811660a080860191909152607883901c90911660c085015261ffff609083901c811660e08601529082901c1661010084015263ffffffff60b082901c811661012085015260d082901c166101408401529050610e0082610638565b62ffffff16608083015250919050565b610e18611db4565b6003805460ff928316650100000000000265ff000000000019948416640100000000029490941665ffff000000001995841663010000000263ff0000001997851662010000029790971663ffff0000199885166101000261ffff199093169490991693909317179590951695909517929092171692909217919091179055565b610ea0611e4a565b5f610eaa84610cc9565b90505f610eb6856113ea565b90505f80610ec2610b81565b915091505f610ed38484848a61054f565b9050610edf8582610a6e565b98975050505050505050565b610ef3611e4a565b610efb611e4a565b5f610f08875f01516113ea565b90505f610f17875f01516113ea565b90505f610f29838888855f015161054f565b90505f610f3b838989875f015161054f565b9050610f478a83610a6e565b9550610f538982610a6e565b94505050505094509492505050565b610f6a611db4565b5f5b8151811015610fa057610f98828281518110610f8a57610f8a612a10565b60200260200101515f611bee565b600101610f6c565b5050565b5f80836005811115610fb857610fb861253c565b14801561100d5750600484600f811115610fd457610fd461253c565b1480610ff15750600584600f811115610fef57610fef61253c565b145b8061100d5750600684600f81111561100b5761100b61253c565b145b156110245761101d6005826129e4565b905061120b565b60048360058111156110385761103861253c565b14801561108d5750600d84600f8111156110545761105461253c565b14806110715750600e84600f81111561106f5761106f61253c565b145b8061108d5750600f84600f81111561108b5761108b61253c565b145b1561109d5761101d6005826129e4565b60028360058111156110b1576110b161253c565b1480156111065750600184600f8111156110cd576110cd61253c565b14806110ea5750600284600f8111156110e8576110e861253c565b145b806111065750600384600f8111156111045761110461253c565b145b156111165761101d6005826129e4565b600183600581111561112a5761112a61253c565b14801561117f5750600a84600f8111156111465761114661253c565b14806111635750600b84600f8111156111615761116161253c565b145b8061117f5750600c84600f81111561117d5761117d61253c565b145b1561118f5761101d6005826129e4565b60038360058111156111a3576111a361253c565b1480156111f85750600784600f8111156111bf576111bf61253c565b14806111dc5750600884600f8111156111da576111da61253c565b145b806111f85750600984600f8111156111f6576111f661253c565b145b1561120b576112086005826129e4565b90505b600684600f81111561121f5761121f61253c565b148061123c5750600f84600f81111561123a5761123a61253c565b145b806112585750600384600f8111156112565761125661253c565b145b806112745750600c84600f8111156112725761127261253c565b145b806112905750600984600f81111561128e5761128e61253c565b145b156112a7576112a06005826129e4565b90506106c4565b8180156113345750600484600f8111156112c3576112c361253c565b14806112e05750600d84600f8111156112de576112de61253c565b145b806112fc5750600184600f8111156112fa576112fa61253c565b145b806113185750600a84600f8111156113165761131661253c565b145b806113345750600784600f8111156113325761133261253c565b145b15611344576112a06005826129e4565b811580156113d25750600584600f8111156113615761136161253c565b148061137e5750600e84600f81111561137c5761137c61253c565b145b8061139a5750600284600f8111156113985761139861253c565b145b806113b65750600b84600f8111156113b4576113b461253c565b145b806113d25750600884600f8111156113d0576113d061253c565b145b156106c4576113e26005826129e4565b949350505050565b6114116040805160808101909152805f81526020015f81526020015f81526020015f905290565b600354604051631bc6654760e21b8152600481018490525f91600160301b90046001600160a01b031690636f19951c906024015f60405180830381865afa15801561145e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526114859190810190612a24565b80519091505f5b81811015611790575f8382815181106114a7576114a7612a10565b60209081029190910181015160035491810151815160405163ee1dffcf60e01b8152600481018b90526001600160a01b0392831660248201526044810191909152919350600160301b9092049091169063ee1dffcf90606401602060405180830381865afa15801561151b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061153f9190612ad2565b156117875760045460208201516001600160a01b039182169116036115ab57805161156c906004906129fd565b600481111561157d5761157d61253c565b859060048111156115905761159061253c565b908160048111156115a3576115a361253c565b905250611787565b60055460208201516001600160a01b0391821691160361161f57805160c810156116115780516002906115e0906008906129fd565b6115ea9190612870565b60048111156115fb576115fb61253c565b856040019060048111156115905761159061253c565b80516115ea906004906129fd565b60065460208201516001600160a01b039182169116036116995780516014101561168b578051611651906005906129fd565b60058111156116625761166261253c565b856020019060058111156116785761167861253c565b908160058111156115a3576115a361253c565b8051611651906004906129fd565b60075460208201516001600160a01b03918216911603611787576007548151604051633940140f60e11b815260048101919091525f916001600160a01b031690637280281e906024015f60405180830381865afa1580156116fc573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526117239190810190612aed565b9050805f8151811061173757611737612a10565b60200260200101516001600160401b0316600f8111156117595761175961253c565b8660600190600f81111561176f5761176f61253c565b9081600f8111156117825761178261253c565b905250505b5060010161148c565b505050919050565b6117a0611db4565b600880546001600160a01b0319166001600160a01b0392909216919091179055565b5f60048260048111156117d7576117d761253c565b036117e357505f610858565b5f8360048111156117f6576117f661253c565b148015611814575060038260048111156118125761181261253c565b145b156118215750601e610858565b5f8360048111156118345761183461253c565b148015611852575060018260048111156118505761185061253c565b145b156118605750600419610858565b5f8360048111156118735761187361253c565b1480156118915750600282600481111561188f5761188f61253c565b145b1561189d57505f610858565b60038360048111156118b1576118b161253c565b1480156118ce57505f8260048111156118cc576118cc61253c565b145b156118dc5750600919610858565b60038360048111156118f0576118f061253c565b14801561190e5750600182600481111561190c5761190c61253c565b145b1561191b57506019610858565b600383600481111561192f5761192f61253c565b14801561194d5750600282600481111561194b5761194b61253c565b145b1561195957505f610858565b600183600481111561196d5761196d61253c565b14801561198a57505f8260048111156119885761198861253c565b145b156119975750600a610858565b60018360048111156119ab576119ab61253c565b1480156119c9575060038260048111156119c7576119c761253c565b145b156119d75750601319610858565b60018360048111156119eb576119eb61253c565b148015611a0957506002826004811115611a0757611a0761253c565b145b15611a1657506014610858565b6002836004811115611a2a57611a2a61253c565b148015611a4757505f826004811115611a4557611a4561253c565b145b15611a5457506019610858565b6002836004811115611a6857611a6861253c565b148015611a8657506003826004811115611a8457611a8461253c565b145b15611a9357506005610858565b6002836004811115611aa757611aa761253c565b148015611ac557506001826004811115611ac357611ac361253c565b145b15611ad35750600919610858565b50601319610858565b611ae4611db4565b6001600160a01b038116611b0b57604051634ece6ecf60e01b815260040160405180910390fd5b611b1481611dde565b50565b5f816004811115611b2a57611b2a61253c565b60ff16836004811115611b3f57611b3f61253c565b60ff16148015610a5957506004610a44565b6003546040516331a9108f60e11b8152600481018390525f91600160301b90046001600160a01b031690636352211e90602401602060405180830381865afa158015611b9f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bc39190612b7f565b90506001600160a01b0381163314610fa0576040516334a50d8b60e21b815260040160405180910390fd5b8015611c695761012082015160e083015163ffffffff90911690611c13816001612b9a565b611c1d9190612bb5565b61ffff161115611c695760018260e001818151611c3a9190612b9a565b61ffff1690525060e0820151611c4f90611e2d565b8261010001818151611c619190612b9a565b61ffff169052505b6009546003548351604080518082019091526005815264535441545360d81b60208201526001600160a01b039384169363ed20867293600160301b9004169190611d64875f816020015162ffffff1690506018826040015162ffffff16901b811790506030826060015162ffffff16901b811790506048826080015162ffffff16901b8117905060608260a0015162ffffff16901b8117905060788260c0015162ffffff16901b8117905060908260e0015161ffff16901b8117905060a082610100015161ffff16901b8117905060b082610120015163ffffffff16901b8117905060d082610140015163ffffffff16901b81179050919050565b6040518563ffffffff1660e01b8152600401611d839493929190612bdb565b5f604051808303815f87803b158015611d9a575f80fd5b505af1158015611dac573d5f803e3d5ffd5b505050505050565b5f546001600160a01b03163314610b7f57604051631c62d58f60e11b815260040160405180910390fd5b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f5b61ffff8216156106335761ffff909116801c90600101611e2f565b60408051610160810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b60058110611b14575f80fd5b5f8060408385031215611ec2575f80fd5b823591506020830135611ed481611ea5565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b60405161016081016001600160401b0381118282101715611f1657611f16611edf565b60405290565b60405160c081016001600160401b0381118282101715611f1657611f16611edf565b604080519081016001600160401b0381118282101715611f1657611f16611edf565b604051601f8201601f191681016001600160401b0381118282101715611f8857611f88611edf565b604052919050565b803560068110610633575f80fd5b803560108110610633575f80fd5b8015158114611b14575f80fd5b5f805f8084860360e0811215611fcd575f80fd5b6080811215611fda575f80fd5b50604051608081018181106001600160401b0382111715611ffd57611ffd611edf565b604052853561200b81611ea5565b815261201960208701611f90565b6020820152604086013561202c81611ea5565b604082015261203d60608701611f9e565b6060820152935061205060808601611f90565b925060a085013561206081611fac565b915060c085013561207081611ea5565b939692955090935050565b5f6020828403121561208b575f80fd5b6106c482611f90565b803562ffffff81168114610633575f80fd5b803561ffff81168114610633575f80fd5b803563ffffffff81168114610633575f80fd5b5f61016082840312156120db575f80fd5b6120e3611ef3565b9050813581526120f560208301612094565b602082015261210660408301612094565b604082015261211760608301612094565b606082015261212860808301612094565b608082015261213960a08301612094565b60a082015261214a60c08301612094565b60c082015261215b60e083016120a6565b60e082015261010061216e8184016120a6565b908201526101206121808382016120b7565b908201526101406121928382016120b7565b9082015292915050565b5f61016082840312156121ad575f80fd5b6106c483836120ca565b6001600160a01b0381168114611b14575f80fd5b5f602082840312156121db575f80fd5b81356106c4816121b7565b5f805f805f60a086880312156121fa575f80fd5b8535945061220a60208701612094565b935061221860408701612094565b925061222660608701612094565b915061223460808701612094565b90509295509295909350565b80518252602081015161225a602084018262ffffff169052565b506040810151612271604084018262ffffff169052565b506060810151612288606084018262ffffff169052565b50608081015161229f608084018262ffffff169052565b5060a08101516122b660a084018262ffffff169052565b5060c08101516122cd60c084018262ffffff169052565b5060e08101516122e360e084018261ffff169052565b506101008181015161ffff16908301526101208082015163ffffffff908116918401919091526101409182015116910152565b61016081016108588284612240565b5f60208284031215612335575f80fd5b5035919050565b5f5b8381101561235657818101518382015260200161233e565b50505f910152565b5f815180845261237581602086016020860161233c565b601f01601f19169290920160200192915050565b602081525f6106c4602083018461235e565b5f6001600160401b038211156123b3576123b3611edf565b50601f01601f191660200190565b5f80604083850312156123d2575f80fd5b8235915060208301356001600160401b038111156123ee575f80fd5b8301601f810185136123fe575f80fd5b803561241161240c8261239b565b611f60565b818152866020838501011115612425575f80fd5b816020840160208301375f602083830101528093505050509250929050565b5f8060408385031215612455575f80fd5b823561246081611ea5565b915061246e60208401611f90565b90509250929050565b803560ff81168114610633575f80fd5b5f8082840361022081121561249a575f80fd5b6124a485856120ca565b925060c061015f19820112156124b8575f80fd5b506124c1611f1c565b6101608401358060010b81146124d5575f80fd5b81526124e46101808501612477565b60208201526124f66101a08501612477565b60408201526125086101c08501612477565b606082015261251a6101e08501612477565b608082015261252c6102008501612477565b60a0820152809150509250929050565b634e487b7160e01b5f52602160045260245ffd5b600681106125605761256061253c565b9052565b604081016125728285612550565b82151560208301529392505050565b5f8060408385031215612592575f80fd5b61246083611f90565b5f80604083850312156125ac575f80fd5b82356125b7816121b7565b91506020830135611ed481611fac565b5f805f805f8060c087890312156125dc575f80fd5b6125e587612477565b95506125f360208801612477565b945061260160408801612477565b935061260f60608801612477565b925061261d60808801612477565b915061262b60a08801612477565b90509295509295509295565b5f805f80610300858703121561264b575f80fd5b61265586866120ca565b93506126658661016087016120ca565b92506126746102c08601611f90565b91506102e085013561207081611fac565b6102c081016126948285612240565b6106c4610160830184612240565b5f6001600160401b038211156126ba576126ba611edf565b5060051b60200190565b5f60208083850312156126d5575f80fd5b82356001600160401b038111156126ea575f80fd5b8301601f810185136126fa575f80fd5b803561270861240c826126a2565b8181526101609182028301840191848201919088841115612727575f80fd5b938501935b8385101561274d5761273e89866120ca565b8352938401939185019161272c565b50979650505050505050565b5f805f6060848603121561276b575f80fd5b61277484611f9e565b925061278260208501611f90565b9150604084013561279281611fac565b809150509250925092565b60058110611b1457611b1461253c565b815160808201906127bd8161279d565b8083525060208301516127d36020840182612550565b5060408301516127e28161279d565b60408301526060830151601081106127fc576127fc61253c565b8060608401525092915050565b5f806040838503121561281a575f80fd5b823561282581611ea5565b91506020830135611ed481611ea5565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561085857610858612835565b634e487b7160e01b5f52601260045260245ffd5b5f8261287e5761287e61285c565b500490565b808202811582820484141761085857610858612835565b62ffffff8181168382160190808211156128b6576128b6612835565b5092915050565b60018060a01b0384168152826020820152606060408201525f6128e3606083018461235e565b95945050505050565b5f602082840312156128fc575f80fd5b81516001600160401b03811115612911575f80fd5b8201601f81018413612921575f80fd5b805161292f61240c8261239b565b818152856020838501011115612943575f80fd5b6128e382602083016020860161233c565b5f60208284031215612964575f80fd5b5051919050565b60018060a01b0385168152836020820152608060408201525f612991608083018561235e565b82810360608401526129a3818561235e565b979650505050505050565b600181810b9083900b01617fff8113617fff198212171561085857610858612835565b8082018082111561085857610858612835565b60ff818116838216019081111561085857610858612835565b5f82612a0b57612a0b61285c565b500690565b634e487b7160e01b5f52603260045260245ffd5b5f6020808385031215612a35575f80fd5b82516001600160401b03811115612a4a575f80fd5b8301601f81018513612a5a575f80fd5b8051612a6861240c826126a2565b81815260069190911b82018301908381019087831115612a86575f80fd5b928401925b828410156129a35760408489031215612aa3575f8081fd5b612aab611f3e565b8451815285850151612abc816121b7565b8187015282526040939093019290840190612a8b565b5f60208284031215612ae2575f80fd5b81516106c481611fac565b5f6020808385031215612afe575f80fd5b82516001600160401b0380821115612b14575f80fd5b818501915085601f830112612b27575f80fd5b8151612b3561240c826126a2565b81815260059190911b83018401908481019088831115612b53575f80fd5b938501935b82851015610edf5784518481168114612b70575f8081fd5b82529385019390850190612b58565b5f60208284031215612b8f575f80fd5b81516106c4816121b7565b61ffff8181168382160190808211156128b6576128b6612835565b61ffff818116838216028082169190828114612bd357612bd3612835565b505092915050565b60018060a01b0385168152836020820152608060408201525f612c01608083018561235e565b90508260608301529594505050505056fea2646970667358221220bb4edadb5a97706c5cf4c36da78838cb7ae3af21f694b234a6241136da6f0cc064736f6c63430008150033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000008f64ce931f0d36430b971548b81264eef3bd9b97000000000000000000000000a5b355125a2b7fd4c7a451c37b87e81b965a96b10000000000000000000000009e5babfad9a1a980b58db60585408735562b721e0000000000000000000000003f563d6d8e62405d01dc8a4e1dfb269f23aab1620000000000000000000000008e8e3ab3bfabb86b37f91b2f2ca83969ac2c0fad000000000000000000000000873526404f04d88bf7b4a8598b00a766a3393128

-----Decoded View---------------
Arg [0] : snakeSoldiers (address): 0x8F64Ce931f0D36430B971548b81264EeF3bD9B97
Arg [1] : elementGems (address): 0xa5B355125A2b7Fd4c7A451C37B87e81B965a96B1
Arg [2] : skillGems (address): 0x9E5bABfad9a1A980b58Db60585408735562B721E
Arg [3] : factionGems (address): 0x3f563D6d8E62405d01dc8A4e1dFB269f23aAB162
Arg [4] : landscapes (address): 0x8e8e3aB3BFaBB86b37F91b2f2cA83969Ac2c0FaD
Arg [5] : attributesRepository (address): 0x873526404f04D88Bf7b4A8598B00a766a3393128

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000008f64ce931f0d36430b971548b81264eef3bd9b97
Arg [1] : 000000000000000000000000a5b355125a2b7fd4c7a451c37b87e81b965a96b1
Arg [2] : 0000000000000000000000009e5babfad9a1a980b58db60585408735562b721e
Arg [3] : 0000000000000000000000003f563d6d8e62405d01dc8a4e1dfb269f23aab162
Arg [4] : 0000000000000000000000008e8e3ab3bfabb86b37f91b2f2ca83969ac2c0fad
Arg [5] : 000000000000000000000000873526404f04d88bf7b4a8598b00a766a3393128


Block Transaction Gas Used Reward
view all blocks collator

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ 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.