Overview
S Balance
0 S
S Value
-More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Controller
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 50 runs
Other Settings:
istanbul EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 /** ▒▓▒ ▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓███▓▓▒ ▒▒▒▒▓▓▓▒▓▓▓▓▓▓▓██▓ ▒██▒▓▓▓▓█▓██████████████████▓ ▒▒▒▓███████████████▒ ▒██▒▓█████████████████████▒ ▒▓██████████▓███████ ▒███████████▓▒ ▒███▓▓██████▓ █████████▒ ▒▓▒▓███████▒ ███████▓ ▒▒▒▒▒▓▓█▓▒ ▓█▓████████ ▒▒▒▒▒ ▒▒▒▒▓▓▓█████▒ ▓█████████▓ ▒▓▓▓▒▓██████▓ ▒▓▓████████▒ ▒██▓▓▓███████▒ ▒▒▓███▓████ ▒███▓█████▒ ▒▒█████▓██▓ ██████▓ ▒▒▒▓██▓██▓█████▒ ▒▒▓▓▒ ▒██▓▒▓▓████████ ▓█████▓███████▓ ██▓▓██████████▒ ▒█████████████ ███████████▓ ▒▓▓▓▓▓▓▒▓ ▒█████████▒ ▒▓▓ ▒▓█▒ ▒▒█▒▒ ▓██████ ▒▒▓▓▒ ▒▒█▒ ▓▒ ▒████ ▒▓█▓█▓▒ ▓▒██▓▒ ██ ▒▓█▓▓▓██▒ ▓█▓▓▓▓▓█▓▓▓▒ ▒▒▒ ▒▒▒▓▓▓▓▒▓▒▒▓▒▓▓▓▓▓▓▓▓▒ ▒▓█▒ ▒▓▒▓█▓ ▒▓█▓▓▓▓▓▓▓▓▓▓▒ ▒▒▒▓▒ ▒▒▒▓▓ ▓▓ ▓▓█▓ ▒▒▓▓ ▒▒█▒ ▒▓▒▓█▓ ▒▒▓▓▓▒▓▒ ▒▓▓▓▒█▒ ▒▒▒█▒ ▒▒█▓▒▒▒▓▓▓▒ ▓██▓▓▓▓▓▓▓███▓ ▒ ▒▓▓█▓ ▒▓▓▓▓█▓█▓ ▒█▓▓▒ ▓▓█▓▒▓█▓▒▒ ▓█▓ ▓███▓ ▓▓▒ ▒▒▓▓█▓▒▒▓█▒ ▒▓██▓ ▓██▓▒ ▒█▓ ▓▓██ ▒▓▓▓▒▒▓█▓ ▒▓████▒ ██▓▓▒▒▒▒▓▓███▓▒ ▒▓▓▓▓▒▒ ▒▓▓▓▓▓▓▓▒▒▒▓█▓▓▓▓█▓▓▒▒▓▓▓▓▓▒ ▒▓████▓▒ ▓▓███████▓▓▒ */ pragma solidity 0.8.23; import "../interfaces/IApplicationEvents.sol"; import "../proxy/Controllable.sol"; import "../lib/ControllerLib.sol"; contract Controller is Controllable, IController { //region ------------------------ Constants /// @notice Version of the contract string public constant override VERSION = "1.0.3"; uint public constant DEPLOYER_ELIGIBILITY_PERIOD = ControllerLib.DEPLOYER_ELIGIBILITY_PERIOD; //endregion ------------------------ Constants //region ------------------------ Initializer function init(address governance_) external initializer { __Controllable_init(address(this)); ControllerLib._S().governance = governance_; } //endregion ------------------------ Initializer //region ------------------------ Views function isDeployer(address adr) public view override returns (bool) { return ControllerLib.isDeployer(adr); } function governance() external view override returns (address) { return ControllerLib.governance(); } function futureGovernance() external view returns (address) { return ControllerLib.futureGovernance(); } function statController() external view override returns (address) { return ControllerLib.statController(); } function storyController() external view override returns (address) { return ControllerLib.storyController(); } function oracle() external view override returns (address) { return ControllerLib.oracle(); } function treasury() external view override returns (address) { return ControllerLib.treasury(); } function dungeonFactory() external view override returns (address) { return ControllerLib.dungeonFactory(); } function gameObjectController() external view override returns (address) { return ControllerLib.gameObjectController(); } function reinforcementController() external view override returns (address) { return ControllerLib.reinforcementController(); } function itemController() external view override returns (address) { return ControllerLib.itemController(); } function heroController() external view override returns (address) { return ControllerLib.heroController(); } function gameToken() external view override returns (address) { return ControllerLib.gameToken(); } function validTreasuryTokens(address token) external view override returns (bool) { return ControllerLib.validTreasuryTokens(token); } function onPause() external view override returns (bool) { return ControllerLib.onPause(); } function userController() external view override returns (address) { return ControllerLib.userController(); } function guildController() external view override returns (address) { return ControllerLib.guildController(); } function rewardsPool() external view override returns (address) { return ControllerLib.rewardsPool(); } function gameTokenPrice() external view override returns (uint) { return ControllerLib.gameTokenPrice(); } //endregion ------------------------ Views //region ------------------------ Gov actions - setters function changePause(bool value) external { ControllerLib.changePause(value); } function offerGovernance(address newGov) external { ControllerLib.offerGovernance(newGov); } function acceptGovernance() external { ControllerLib.acceptGovernance(); } function setStatController(address value) external { ControllerLib.setStatController(value); } function setStoryController(address value) external { ControllerLib.setStoryController(value); } function setGameObjectController(address value) external { ControllerLib.setGameObjectController(value); } function setReinforcementController(address value) external { ControllerLib.setReinforcementController(value); } function setOracle(address value) external { ControllerLib.setOracle(value); } function setTreasury(address value) external { ControllerLib.setTreasury(value); } function setItemController(address value) external { ControllerLib.setItemController(value); } function setHeroController(address value) external { ControllerLib.setHeroController(value); } function setGameToken(address value) external { ControllerLib.setGameToken(value); } function setDungeonFactory(address value) external { ControllerLib.setDungeonFactory(value); } function changeDeployer(address eoa, bool remove) external { ControllerLib.changeDeployer(eoa, remove); } function setUserController(address value) external { ControllerLib.setUserController(value); } function setGuildController(address value) external { ControllerLib.setGuildController(value); } function setRewardsPool(address value) external { ControllerLib.setRewardsPool(value); } function setGameTokenPrice(uint value) external { ControllerLib.setGameTokenPrice(value); } //endregion ------------------------ Gov actions - setters //region ------------------------ Gov actions - others function updateProxies(address[] memory proxies, address newLogic) external { ControllerLib.updateProxies(proxies, newLogic); } function claimToGovernance(address token) external { ControllerLib.claimToGovernance(token); } //endregion ------------------------ Gov actions - others //region ------------------------ REGISTER ACTIONS function changeTreasuryTokenStatus(address token, bool status) external { ControllerLib.changeTreasuryTokenStatus(token, status); } //endregion ------------------------ REGISTER ACTIONS //region ------------------------ User actions /// @notice Transfer {amount} from {from}, divide it on three parts: to treasury, to governance, to burn /// User must approve given amount to the controller. /// @param amount Assume that this amount is approved by {from} to this contract function process(address token, uint amount, address from) external { ControllerLib.process(IController(address(this)), token, amount, from); } function percentToBurn(uint totalSupply) external pure returns (uint) { return ControllerLib.percentToBurn(totalSupply); } function getProcessDetails(address token, uint amount) external view returns (uint toBurn, uint toTreasury, uint toGov, uint toRewardsPool) { (toBurn, toTreasury, toGov, toRewardsPool) = ControllerLib.getProcessDetails(token, amount, IController(address(this)).gameToken()); } //endregion ------------------------ User actions }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; /// @notice All errors of the app interface IAppErrors { //region ERC20Errors /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); //endregion ERC20Errors //region ERC721Errors /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); //endregion ERC721Errors error ZeroAddress(); error ZeroValueNotAllowed(); error ZeroToken(); error LengthsMismatch(); error NotEnoughBalance(); error NotEnoughAllowance(); error EmptyNameNotAllowed(); error NotInitialized(); error AlreadyInitialized(); error ReentrancyGuardReentrantCall(); error TooLongString(); error AlreadyDeployed(address deployed); //region Restrictions error ErrorNotDeployer(address sender); error ErrorNotGoc(); error NotGovernance(address sender); error ErrorOnlyEoa(); error NotEOA(address sender); error ErrorForbidden(address sender); error AdminOnly(); error ErrorNotItemController(address sender); error ErrorNotHeroController(address sender); error ErrorNotDungeonFactory(address sender); error ErrorNotObjectController(address sender); error ErrorNotStoryController(); error ErrorNotAllowedSender(); error MintNotAllowed(); //endregion Restrictions //region PackingLib error TooHighValue(uint value); error IntValueOutOfRange(int value); error OutOfBounds(uint index, uint length); error UnexpectedValue(uint expected, uint actual); error WrongValue(uint newValue, uint actual); error IntOutOfRange(int value); error ZeroValue(); /// @notice packCustomDataChange requires an input string with two zero bytes at the beginning /// 0xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0000 /// This error happens if these bytes are not zero error IncompatibleInputString(); error IncorrectOtherItemTypeKind(uint8 kind); //endregion PackingLib //region Hero error ErrorHeroIsNotRegistered(address heroToken); error ErrorHeroIsDead(address heroToken, uint heroTokenId); error ErrorHeroNotInDungeon(); error HeroInDungeon(); error ErrorNotOwner(address token, uint tokenId); error Staked(address heroToken, uint heroId); error NameTaken(); error TooBigName(); error WrongSymbolsInTheName(); error NoPayToken(address token, uint payTokenAmount); error AlreadyHaveReinforcement(); /// @notice SIP-001 - Reinforcement requires 3 skills error ErrorReinforcementRequiresThreeSkills(); error WrongTier(uint tier); error NotEnoughNgLevel(uint8 ngLevel); error NgpNotActive(address hero); error RebornNotAllowed(); error AlreadyPrePaidHero(); //endregion Hero //region Dungeon error ErrorDungeonIsFreeAlready(); error ErrorNoEligibleDungeons(); error ErrorDungeonBusy(); error ErrorNoDungeonsForBiome(uint8 heroBiome); error ErrorDungeonCompleted(); error ErrorAlreadyInDungeon(); error NotEnoughTokens(uint balance, uint expectedBalance); error DungeonAlreadySpecific(uint16 dungNum); error DungeonAlreadySpecific2(uint16 dungNum); error WrongSpecificDungeon(); //endregion Dungeon //region Items error ErrorItemNotEligibleForTheSlot(uint itemType, uint8 itemSlot); error ErrorItemSlotBusyHand(uint8 slot); error ErrorItemSlotBusy(); error ErrorItemNotInSlot(); error ErrorConsumableItemIsUsed(address item); error ErrorCannotRemoveItemFromMap(); error ErrorCannotRemoveDataFromMap(); error EquippedItemsExist(); error ItemEquipped(address item, uint itemId); error ZeroItemMetaType(); error NotZeroOtherItemMetaType(); error ZeroLevel(); error ItemTypeChanged(); error ItemMetaTypeChanged(); error UnknownItem(address item); error ErrorEquipForbidden(); error EquipForbiddenInDungeon(); error TakeOffForbiddenInDungeon(); error Consumable(address item); error NotConsumable(address item); error Broken(address item); error ZeroLife(); error RequirementsToItemAttributes(); error NotEquipped(address item); error ZeroDurability(); error ZeroAugmentation(); error TooHighAgLevel(uint8 augmentationLevel); error UseForbiddenZeroPayToken(); error IncorrectMinMaxAttributeRange(int32 min, int32 max); error SameIdsNotAllowed(); error ZeroFragility(); error OtherTypeItemNotRepairable(); error NotOther(); error DoubleItemUsageForbidden(uint itemIndex, address[] items); error ItemAlreadyUsedInSlot(address item, uint8 equippedSlot); error WrongWayToRegisterItem(); error UnionItemNotFound(address item); error WrongListUnionItemTokens(address item, uint countTokens, uint requiredCountTokens); error UnknownUnionConfig(uint unionConfigId); error UserHasNoKeyPass(address user, address keyPassItem); error MaxValue(uint value); error UnexpectedOtherItem(address item); error NotExist(); //endregion Items //region Stages error ErrorWrongStage(uint stage); error ErrorNotStages(); //endregion Stages //region Level error ErrorWrongLevel(uint heroLevel); error ErrorLevelTooLow(uint heroLevel); error ErrorHeroLevelStartFrom1(); error ErrorWrongLevelUpSum(); error ErrorMaxLevel(); //endregion Level //region Treasure error ErrorNotValidTreasureToken(address treasureToken); //endregion Treasure //region State error ErrorPaused(); error ErrorNotReady(); error ErrorNotObject1(); error ErrorNotObject2(); error ErrorNotCompleted(); //endregion State //region Biome error ErrorNotBiome(); error ErrorIncorrectBiome(uint biome); error TooHighBiome(uint biome); //endregion Biome //region Misc error ErrorWrongMultiplier(uint multiplier); error ErrorNotEnoughMana(uint32 mana, uint requiredMana); error ErrorExperienceMustNotDecrease(); error ErrorNotEnoughExperience(); error ErrorNotChances(); error ErrorNotEligible(address heroToken, uint16 dungNum); error ErrorZeroKarmaNotAllowed(); //endregion Misc //region GOC error GenObjectIdBiomeOverflow(uint8 biome); error GenObjectIdSubTypeOverflow(uint subType); error GenObjectIdIdOverflow(uint id); error UnknownObjectTypeGoc1(uint8 objectType); error UnknownObjectTypeGoc2(uint8 objectType); error UnknownObjectTypeGocLib1(uint8 objectType); error UnknownObjectTypeGocLib2(uint8 objectType); error UnknownObjectTypeForSubtype(uint8 objectSubType); error FightDelay(); error ZeroChance(); error TooHighChance(uint32 chance); error TooHighRandom(uint random); error EmptyObjects(); error ObjectNotFound(); error WrongGetObjectTypeInput(); error WrongChances(uint32 chances, uint32 maxChances); //endregion GOC //region Story error PageNotRemovedError(uint pageId); error NotItem1(); error NotItem2(); error NotRandom(uint32 random); error NotHeroData(); error NotGlobalData(); error ZeroStoryIdRemoveStory(); error ZeroStoryIdStoryAction(); error ZeroStoryIdAction(); error NotEnoughAmount(uint balance, uint requiredAmount); error NotAnswer(); error AnswerStoryIdMismatch(uint16 storyId, uint16 storyIdFromAnswerHash); error AnswerPageIdMismatch(uint16 pageId, uint16 pageIdFromAnswerHash); //endregion Story //region FightLib error NotMagic(); error NotAType(uint atype); //endregion FightLib //region MonsterLib error NotYourDebuffItem(); error UnknownAttackType(uint attackType); error NotYourAttackItem(); /// @notice The skill item cannot be used because it doesn't belong either to the hero or to the hero's helper error NotYourBuffItem(); //endregion MonsterLib //region GameToken error ApproveToZeroAddress(); error MintToZeroAddress(); error TransferToZeroAddress(); error TransferAmountExceedsBalance(uint balance, uint value); error InsufficientAllowance(); error BurnAmountExceedsBalance(); error NotMinter(address sender); //endregion GameToken //region NFT error TokenTransferNotAllowed(); error IdOverflow(uint id); error NotExistToken(uint tokenId); error EquippedItemIsNotAllowedToTransfer(uint tokenId); //endregion NFT //region CalcLib error TooLowX(uint x); //endregion CalcLib //region Controller error NotFutureGovernance(address sender); //endregion Controller //region Oracle error OracleWrongInput(); //endregion Oracle //region ReinforcementController error AlreadyStaked(); error MaxFee(uint8 fee); error MinFee(uint8 fee); error StakeHeroNotStats(); error NotStaked(); error NoStakedHeroes(); error GuildHelperNotAvailable(uint guildId, address helper, uint helperId); error HelperNotAvailableInGivenBiome(); //endregion ReinforcementController //region SponsoredHero error InvalidHeroClass(); error ZeroAmount(); error InvalidProof(); error NoHeroesAvailable(); error AlreadyRegistered(); //endregion SponsoredHero //region SacraRelay error SacraRelayNotOwner(); error SacraRelayNotDelegator(); error SacraRelayNotOperator(); error SacraRelayInvalidChainId(uint callChainId, uint blockChainId); error SacraRelayInvalidNonce(uint callNonce, uint txNonce); error SacraRelayDeadline(); error SacraRelayDelegationExpired(); error SacraRelayNotAllowed(); error SacraRelayInvalidSignature(); /// @notice This error is generated when custom error is caught /// There is no info about custom error in SacraRelay /// but you can decode custom error by selector, see tests error SacraRelayNoErrorSelector(bytes4 selector, string tracingInfo); /// @notice This error is generated when custom error is caught /// There is no info about custom error in SacraRelay /// but you can decode custom error manually from {errorBytes} as following: /// if (keccak256(abi.encodeWithSignature("MyError()")) == keccak256(errorBytes)) { ... } error SacraRelayUnexpectedReturnData(bytes errorBytes, string tracingInfo); error SacraRelayCallToNotContract(address notContract, string tracingInfo); //endregion SacraRelay //region Misc error UnknownHeroClass(uint heroClass); error AbsDiff(int32 a, int32 b); //region Misc //region ------------------------ UserController error NoAvailableLootBox(address msgSender, uint lootBoxKind); error FameHallHeroAlreadyRegistered(uint8 openedNgLevel); //endregion ------------------------ UserController //region ------------------------ Guilds error AlreadyGuildMember(); error NotGuildMember(); error WrongGuild(); error GuildActionForbidden(uint right); error GuildHasMaxSize(uint guildSize); error GuildHasMaxLevel(uint level); error TooLongUrl(); error TooLongDescription(); error CannotRemoveGuildOwnerFromNotEmptyGuild(); error GuildControllerOnly(); error GuildAlreadyHasShelter(); error ShelterIsBusy(); error ShelterIsNotRegistered(); error ShelterIsNotOwnedByTheGuild(); error ShelterIsInUse(); error GuildHasNoShelter(); error ShelterBidIsNotAllowedToBeUsed(); error ShelterHasHeroesInside(); error SecondGuildAdminIsNotAllowed(); error NotEnoughGuildBankBalance(uint guildId); error GuildReinforcementCooldownPeriod(); error NoStakedGuildHeroes(); error NotStakedInGuild(); error ShelterHasNotEnoughLevelForReinforcement(); error NotBusyGuildHelper(); error GuildRequestNotActive(); error GuildRequestNotAvailable(); error NotAdminCannotAddMemberWithNotZeroRights(); //endregion ------------------------ Guilds //region ------------------------ Shelters error ErrorNotShelterController(); error ErrorNotGuildController(); error ShelterHasNotItem(uint shelterId, address item); error MaxNumberItemsSoldToday(uint numSoldItems, uint limit); error GuildHasNotEnoughPvpPoints(uint64 pointsAvailable, uint pointRequired); error FreeShelterItemsAreNotAllowed(uint shelterId, address item); error TooLowShelterLevel(uint8 shelterLevel, uint8 allowedShelterLevel); error NotEnoughPvpPointsCapacity(address user, uint usedPoints, uint pricePvpPoints, uint64 capactiy); error IncorrectShelterLevel(uint8 shelterLevel); //endregion ------------------------ Shelters //region ------------------------ Auction error WrongAuctionPosition(); error AuctionPositionClosed(); error AuctionBidOpened(uint positionId); error TooLowAmountToBid(); error AuctionEnded(); error TooLowAmountForNewBid(); error AuctionSellerOnly(); error AuctionBuyerOnly(); error AuctionBidNotFound(); error AuctionBidClosed(); error OnlyShelterAuction(); error CannotCloseLastBid(); error AuctionNotEnded(); error NotShelterAuction(); error AuctionPositionOpened(uint positionId); error AuctionSellerCannotBid(); error CannotApplyNotLastBid(); error AuctionGuildWithShelterCannotBid(); //endregion ------------------------ Auction //region ------------------------ Pawnshop error AuctionPositionNotSupported(uint positionId); error PositionNotSupported(uint positionId); error NotNftPositionNotSupported(uint positionId); error CallFailed(bytes callResultData); error PawnShopZeroOwner(); error PawnShopZeroFeeRecipient(); error PawnShopNotOwner(); error PawnShopAlreadyAnnounced(); error PawnShopTimeLock(); error PawnShopWrongAddressValue(); error PawnShopWrongUintValue(); error PawnShopZeroAddress(); error PawnShopTooHighValue(); error PawnShopZeroAToken(); error PawnShopZeroCToken(); error PawnShopWrongAmounts(); error PawnShopPosFeeForInstantDealForbidden(); error PawnShopPosFeeAbsurdlyHigh(); error PawnShopIncorrect(); error PawnShopWrongId(); error PawnShopNotBorrower(); error PawnShopPositionClosed(); error PawnShopPositionExecuted(); error PawnShopWrongBidAmount(); error PawnShopTooLowBid(); error PawnShopNewBidTooLow(); error PawnShopBidAlreadyExists(); error PawnShopAuctionEnded(); error PawnShopNotLender(); error PawnShopTooEarlyToClaim(); error PawnShopPositionNotExecuted(); error PawnShopAlreadyClaimed(); error PawnShopAuctionNotEnded(); error PawnShopBidClosed(); error PawnShopNoBids(); error PawnShopAuctionBidNotFound(); error PawnShopWrongBid(); error PawnShopBidNotFound(); //endregion ------------------------ Pawnshop }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "./IGOC.sol"; import "./IStatController.sol"; import "./IDungeonFactory.sol"; import "./IStoryController.sol"; import "./IFightCalculator.sol"; /// @notice All events of the app interface IApplicationEvents { //region ------------------ StatController event HeroItemSlotChanged( address heroToken, uint heroTokenId, uint itemType, uint itemSlot, address itemToken, uint itemTokenId, bool equip, address caller ); event CurrentStatsChanged( address heroToken, uint heroTokenId, IStatController.ChangeableStats change, bool increase, address caller ); event BonusAttributesChanged( address heroToken, uint heroTokenId, bool add, bool temporally, address caller ); event TemporallyAttributesCleared(address heroToken, uint heroTokenId, address caller); event NewHeroInited(address heroToken, uint heroTokenId, IStatController.ChangeableStats stats); event LevelUp( address heroToken, uint heroTokenId, uint heroClass, IStatController.CoreAttributes change ); event ConsumableUsed(address heroToken, uint heroTokenId, address item); event RemoveConsumableUsage(address heroToken, uint heroTokenId, address item); event HeroCustomDataChanged(address token, uint tokenId, bytes32 index, uint value); event HeroCustomDataChangedNg(address token, uint tokenId, bytes32 index, uint value, uint8 ngLevel); event HeroCustomDataCleared(address token, uint tokenId); event GlobalCustomDataChanged(bytes32 index, uint value); //endregion ------------------ StatController //region ------------------ DungeonFactoryController event DungeonLaunched( uint16 dungeonLogicNum, uint64 dungeonId, address heroToken, uint heroTokenId, address treasuryToken, uint treasuryAmount ); event BossCompleted(uint32 objectId, uint biome, address hero, uint heroId); event FreeDungeonAdded(uint8 biome, uint64 dungeonId); event ObjectOpened(uint64 dungId, address hero, uint id, uint32 objId, uint iteration, uint currentStage); event Clear(uint64 dungId); event DungeonLogicRegistered(uint16 dungLogicId, IDungeonFactory.DungeonGenerateInfo info); event DungeonLogicRemoved(uint16 dungLogicId); event DungeonSpecificLogicRegistered(uint16 dungLogicId, uint biome, uint heroCls); event DungeonSpecificLogicRemoved(uint16 dungLogicId, uint heroLvl, uint heroCls); event DungeonRegistered(uint16 dungLogicId, uint64 dungeonId); event DungeonRemoved(uint16 dungLogicId, uint64 dungeonId); event MinLevelForTreasuryChanged(address token, uint level); event ObjectAction( uint64 dungId, IGOC.ActionResult result, uint currentStage, address heroToken, uint heroTokenId, uint newStage ); /// @notice On add the item to the dungeon event AddTreasuryItem(uint64 dungId, address itemAdr, uint itemId); event AddTreasuryToken(uint64 dungId, address token, uint amount); event ClaimToken(uint64 dungId, address token, uint amount); event ClaimItem(uint64 dungId, address token, uint id); event Entered(uint64 dungId, address hero, uint id); event DungeonCompleted(uint16 dungLogicNum, uint64 dungId, address hero, uint heroId); event Exit(uint64 dungId, bool claim); event ExitForcibly(uint64 dungId, address hero, uint heroId); event FreeDungeonRemoved(uint8 biome, uint64 dungeonId); event HeroCurrentDungeonChanged(address hero, uint heroId, uint64 dungeonId); //endregion ------------------ DungeonFactoryController //region ------------------ GameObjectController event EventRegistered(uint32 objectId, IGOC.EventRegInfo eventRegInfo); event StoryRegistered(uint32 objectId, uint16 storyId); event MonsterRegistered(uint32 objectId, IGOC.MonsterGenInfo monsterGenInfo); event ObjectRemoved(uint32 objectId); event ObjectResultEvent( uint64 dungeonId, uint32 objectId, IGOC.ObjectType objectType, address hero, uint heroId, uint8 stageId, uint iteration, bytes data, IGOC.ActionResult result, uint salt ); //endregion ------------------ GameObjectController //region ------------------ StoryController event SetBurnItemsMeta(uint storyId, IStoryController.AnswerBurnRandomItemMeta meta); event SetNextObjRewriteMeta(uint storyId, IStoryController.NextObjRewriteMeta meta); event SetAnswersMeta(uint storyId, uint16[] answerPageIds, uint8[] answerHeroClasses, uint16[] answerIds); event SetAnswerNextPageMeta(uint storyId, IStoryController.AnswerNextPageMeta meta); event SetAnswerAttributeRequirements(uint storyId, IStoryController.AnswerAttributeRequirementsMeta meta); event SetAnswerItemRequirements(uint storyId, IStoryController.AnswerItemRequirementsMeta meta); event SetAnswerTokenRequirementsMeta(uint storyId, IStoryController.AnswerTokenRequirementsMeta meta); event SetAnswerAttributes(uint storyId, IStoryController.AnswerAttributesMeta meta); event SetAnswerHeroCustomDataRequirementMeta(uint storyId, IStoryController.AnswerCustomDataMeta meta); event SetAnswerGlobalCustomDataRequirementMeta(uint storyId, IStoryController.AnswerCustomDataMeta meta); event SetSuccessInfo(uint storyId, IStoryController.AnswerResultMeta meta); event SetFailInfo(uint storyId, IStoryController.AnswerResultMeta meta); event SetCustomDataResult(uint storyId, IStoryController.AnswerCustomDataResultMeta meta, IStoryController.CustomDataResult _type); event StoryCustomDataRequirements(uint storyId, bytes32 requiredCustomDataIndex, uint requiredCustomDataMinValue, uint requiredCustomDataMaxValue, bool requiredCustomDataIsHero); event StoryRequiredLevel(uint storyId, uint requiredLevel); event StoryFinalized(uint32 objectId, uint storyId); event StoryRemoved(uint32 objectId, uint storyId); event ItemBurned( address heroToken, uint heroTokenId, uint64 dungeonId, uint objectId, address nftToken, uint nftId, uint stageId, uint iteration ); /// @notice Durability of the item was reduced to 0 event ItemBroken( address heroToken, uint heroTokenId, uint64 dungeonId, uint objectId, address nftToken, uint nftId, uint stageId, uint iteration ); event NotEquippedItemBurned( address heroToken, uint heroTokenId, uint64 dungeonId, uint storyId, address nftToken, uint nftId, uint stageId, uint iteration ); event StoryChangeAttributes( uint32 objectId, address heroToken, uint heroTokenId, uint64 dungeonId, uint storyId, uint stageId, uint iteration, int32[] attributes ); //endregion ------------------ StoryController //region ------------------------ HeroController event HeroRegistered(address hero, uint8 heroClass, address payToken, uint payAmount); event HeroCreatedNgp(address hero, uint heroId, string name, address owner, string refCode, uint8 tier, uint8 ngLevel); event BiomeChanged(address hero, uint heroId, uint8 biome); event LevelUp(address hero, uint heroId, address owner, IStatController.CoreAttributes change); event ReinforcementAsked(address hero, uint heroId, address helpHeroToken, uint helpHeroId); event GuildReinforcementAsked(address hero, uint heroId, address helpHeroToken, uint helpHeroId); event OtherItemGuildReinforcement(address item, uint itemId, address hero, uint heroId, address helpHeroToken, uint helpHeroId); event ReinforcementReleased(address hero, uint heroId, address helperToken, uint helperId); event GuildReinforcementReleased(address hero, uint heroId, address helperToken, uint helperId); event Killed(address hero, uint heroId, address killer, bytes32[] dropItems, uint dropTokenAmount); event Reborn(address hero, uint heroId, uint8 newNgLevel); event BossKilled(address account, address hero, uint heroId, uint8 biome, uint8 newNgLevel, bool reborn, uint rewardAmount); event TierSetup(uint8 tier, address hero, uint72 payAmount, uint8[] slots, address[][] items); //endregion ------------------------ HeroController //region ------------------------ FightLib event FightResultProcessed( address sender, IFightCalculator.FightInfoInternal result, IFightCalculator.FightCall callData, uint iteration ); //endregion ------------------------ FightLib //region ------------------------ Oracle event Random(uint number, uint max); //endregion ------------------------ Oracle //region ------------------------ Controller event OfferGovernance(address newGov); event GovernanceAccepted(address gov); event StatControllerChanged(address value); event StoryControllerChanged(address value); event GameObjectControllerChanged(address value); event ReinforcementControllerChanged(address value); event OracleChanged(address value); event TreasuryChanged(address value); event ItemControllerChanged(address value); event HeroControllerChanged(address value); event GameTokenChanged(address value); event DungeonFactoryChanged(address value); event ProxyUpdated(address proxy, address logic); event Claimed(address token, uint amount); event TokenStatusChanged(address token, bool status); event UserControllerChanged(address value); event GuildControllerChanged(address value); event GameTokenPriceChanged(uint value); event RewardsPoolChanged(address value); event Process(address token, uint amount, address from, uint toBurn, uint toTreasury, uint toGov); //endregion ------------------------ Controller //region ------------------------ ReinforcementController event HeroStaked(address heroToken, uint heroId, uint biome, uint score); event HeroStakedV2(address heroToken, uint heroId, uint biome, uint rewardAmount); event HeroWithdraw(address heroToken, uint heroId); event HeroAsk(address heroToken, uint heroId); event HeroAskV2(address heroToken, uint heroId, uint hitsLast24h, uint fixedFee, uint helperRewardAmount); event TokenRewardRegistered(address heroToken, uint heroId, address token, uint amountAdded, uint totalAmount); event GuildTokenRewardRegistered(address heroToken, uint heroId, address token, uint amountAdded, uint guildId); event NftRewardRegistered(address heroToken, uint heroId, address token, uint id); event GuildNftRewardRegistered(address heroToken, uint heroId, address token, uint id, uint guildId); event ToHelperRatioChanged(uint value); event ClaimedToken(address heroToken, uint heroId, address token, uint amount, address recipient); event ClaimedItem(address heroToken, uint heroId, address item, uint itemId, address recipient); event MinLevelChanged(uint8 value); event MinLifeChancesChanged(uint value); //endregion ------------------------ ReinforcementController //region ------------------------ Treasury, reward pool event AssetsSentToDungeon(address dungeon, address token, uint amount); event RewardSentToUser(address receiver, address token, uint rewardAmount); event NotEnoughReward(address receiver, address token, uint rewardAmountToPay); event BaseAmountChanged(uint oldValue, uint newValue); //endregion ------------------------ Treasury, reward pool //region ------------------------ EventLib event EventResult(uint64 dungeonId, address heroToken, uint heroTokenId, uint8 stageId, IStatController.ActionInternalInfo gen, uint iteration); //endregion ------------------------ EventLib //region ------------------------ Item controller and helper contracts event ItemRegistered(address item, IItemController.RegisterItemParams info); event OtherItemRegistered(address item, IItemController.ItemMeta meta, bytes packedItemMetaData); event ItemRemoved(address item); event OtherItemRemoved(address item); event NewItemMinted(address item, uint itemId, IItemController.MintInfo info); event Equipped(address item, uint itemId, address heroToken, uint heroTokenId, uint8 itemSlot); event TakenOff(address item, uint itemId, address heroToken, uint heroTokenId, uint8 itemSlot, address destination); event ItemRepaired(address item, uint itemId, uint consumedItemId, uint16 baseDurability); event FailedToRepairItem(address item, uint itemId, uint consumedItemId, uint16 itemDurability); event Augmented(address item, uint itemId, uint consumedItemId, uint8 augLevel, IItemController.AugmentInfo info); event NotAugmented(address item, uint itemId, uint consumedItemId, uint8 augLevel); event ReduceDurability(address item, uint itemId, uint newDurability); event Used(address item, uint tokenId, address heroToken, uint heroTokenId); event Destroyed(address item, uint itemId); event FragilityReduced(address item, uint itemId, address consumedItem, uint consumedItemId, uint fragility); event ItemControllerHelper(address helper); event SetUnionConfig(uint configId, address[] items, uint[] count, address itemToMint); event RemoveUnionConfig(uint configId); event SetUnionKeyPass(address keyPassItem); event CombineItems(address msgSender, uint configId, address[] items, uint[][] itemIds, address mintedItem, uint mintedItemId); //endregion ------------------------ Item controller and helper contracts //region ------------------------ NFT and GameToken (only custom events, not ERC20/721 standards) event ChangePauseStatus(bool value); event MinterChanged(address value); event UniqueUriChanged(uint id, string uri); event BaseUriChanged(string uri); event HeroMinted(uint heroId); event HeroBurned(uint heroId); event HeroUriByStatusChanged(string uri, uint statusLvl); event ItemMinted(uint tokenId); event ItemBurned(uint tokenId); event UriByRarityChanged(string uri, uint rarity); event SponsoredHeroCreated(address msgSender, address heroAddress, uint heroId, string heroName); //endregion ------------------------ NFT and GameToken (only custom events, not ERC20/721 standards) //region ------------------------ User controller event SetUserName(address user, string name); event SetUserAvatar(address user, string avatar); event LootBoxOpened(address user, uint lootBoxKind, address[] itemTokens, uint[] itemTokenIds); event LootBoxConfigChanged(uint lootBoxKind, address[] mintItems, uint32[] mintItemsChances, uint maxDropItems); event SetFeeRenaming(uint feeRenaming); event ActivityCompleted(address user, bool daily, bool weekly); event FameHallHeroRegistered(address hero, uint heroId, address heroOwner, uint8 openedNgLevel); //endregion ------------------------ User controller //region ------------------------ Guild event GuildCreated(address owner, uint guildId, string name, string urlLogo); event AddToGuild(uint guildId, address newUser); event ChangeGuildRights(uint guildId, address user, uint rights); event RemoveFromGuild(uint guildId, address user); event GuildDeleted(uint guildId); event GuildLevelUp(uint guildId, uint8 newLevel); event GuildRename(uint guildId, string newName); event GuildLogoChanged(uint guildId, string newLogoUrl); event GuildDescriptionChanged(uint guildId, string newDescription); event SetGuildRelation(uint guildId1, uint guildId2, bool peace); event TransferFromGuildBank(address user, address token, uint amount, address recipient); event TransferNftFromGuildBank(address user, address[] nfts, uint[] tokenIds, address recipient); event GuildBankDeployed(uint guildId, address guildBank); event SetToHelperRatio(uint guildId, uint8 value, address user); event TopUpGuildBank(address msgSender, uint guildId, address guildBank, uint amount); event GuildRequestRegistered(address msgSender, uint guildId, string userMessage, uint depositAmount); event GuildRequestStatusChanged(address msgSender, uint guildRequestId, uint8 newStatus, address user); event SetToHelperRatio(uint guildId, address msgSender, uint8 toHelperRatio); event SetGuildRequestDepositAmount(uint guildId, address msgSender, uint amount); event SetGuildBaseFee(uint fee); event SetPvpPointsCapacity(address msgSender, uint64 capacityPvpPoints, address[] users); event SetShelterController(address shelterController); event SetShelterAuction(address shelterAuction); event PayForBidFromGuildBank(uint guildId, uint amount, uint bid); //endregion ------------------------ Guild //region ------------------------ Guild shelter event RegisterShelter(uint sheleterId, uint price); event SetShelterItems( uint shelterId, address[] items, uint64[] pricesInPvpPoints, uint128[] pricesInGameTokens, uint16[] maxItemsPerDayThresholds ); event RemoveShelterItems(uint shelterId, address[] items); event BuyShelter(uint guidlId, uint shelterId); event LeaveShelter(uint guildId, uint shelterId); event NewShelterBid(uint shelterId, uint buyerGuildId, uint amount); event RevokeShelterBid(uint shelterId); event UseShelterBid(uint shelterId, uint sellerGuildId, uint buyerGuidId, uint amount); event PurchaseShelterItem(address msgSender, address item, uint numSoldItems, uint priceInPvpPoints, uint priceInGameToken); event ChangeShelterOwner(uint shelterId, uint fromGuildId, uint toGuildId); event RestInShelter(address msgSender, address heroToken, uint heroTokenId); //endregion ------------------------ Guild shelter //region ------------------------ Guild reinforcement event GuildHeroStaked(address heroToken, uint heroId, uint guildId); event GuildHeroWithdrawn(address heroToken, uint heroId, uint guildId); event GuildHeroAsked(address heroToken, uint heroId, uint guildId, address user); /// @param user Address can be 0 if heroId was already burnt at the moment of reinforcement releasing event GuildHeroReleased(address heroToken, uint heroId, uint guildId, address user); //endregion ------------------------ Guild reinforcement //region ------------------------ Guild auction event AuctionPositionOpened(uint positionId, uint shelterId, uint sellerGuildId, address msgSender, uint minAuctionPrice); event AuctionPositionClosed(uint positionId, address msgSender); event AuctionBidOpened(uint bidId, uint positionId, uint amount, address msgSender); //endregion ------------------------ Guild auction //region ------------------------ Guild bank event GuildBankTransfer(address token, address recipient, uint amount); event GuildBankTransferNft(address to, address nft, uint tokenId); event GuildBankTransferNftMulti(address to, address[] nfts, uint[] tokenIds); //endregion ------------------------ Guild bank //region ------------------------ Pawnshop event PawnShopRouterDeployed(address pawnShop, address gameToken, address routerOwner, address deployed); event PawnShopRouterTransfer(address token, uint amount, address receiver); event PawnShopRouterBulkSell(address[] nfts, uint[] nftIds, uint[] prices, address nftOwner, uint[] positionIds); event PawnShopRouterClosePositions(uint[] positionIds, address receiver); event PawnShopRouterBulkBuy(uint[] positionIds, address receiver); //endregion ------------------------ Pawnshop }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; interface IControllable { function VERSION() external pure returns (string memory); function revision() external view returns (uint); function previousImplementation() external view returns (address); function isController(address contract_) external view returns (bool); function isGovernance(address contract_) external view returns (bool); function created() external view returns (uint256); function createdBlock() external view returns (uint256); function controller() external view returns (address); function increaseRevision(address oldLogic) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; interface IController { function governance() external view returns (address); function statController() external view returns (address); function storyController() external view returns (address); function gameObjectController() external view returns (address); function reinforcementController() external view returns (address); function oracle() external view returns (address); function treasury() external view returns (address); function itemController() external view returns (address); function heroController() external view returns (address); function dungeonFactory() external view returns (address); function gameToken() external view returns (address); function validTreasuryTokens(address token) external view returns (bool); function isDeployer(address adr) external view returns (bool); function onPause() external view returns (bool); function userController() external view returns (address); function guildController() external view returns (address); function rewardsPool() external view returns (address); function gameTokenPrice() external view returns (uint); function process(address token, uint amount, address from) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "../openzeppelin/EnumerableSet.sol"; import "../openzeppelin/EnumerableMap.sol"; interface IDungeonFactory { /// @custom:storage-location erc7201:dungeon.factory.main struct MainState { /// @dev biome => dungeonLaunchedId mapping(uint => EnumerableSet.UintSet) freeDungeons; /// @dev hero + heroId + biome (packMapObject) -> completed mapping(bytes32 => bool) bossCompleted; /// @dev hero + heroId + dungNum (packDungeonKey) -> completed mapping(bytes32 => bool) specificDungeonCompleted; /// @notice Max biome completed by the hero /// @dev hero + heroId (nftPacked) -> max biome completed mapping(bytes32 => uint8) maxBiomeCompleted; /// @notice which dungeon the hero is currently in /// @dev hero+id => current DungeonId mapping(bytes32 => uint64) heroCurrentDungeon; // --- /// @notice Specific dungeon for the given pair of hero level + hero class /// ALl specific dungeons are listed also in allSpecificDungeons /// @dev packUint8Array(specReqBiome, specReqHeroClass) => dungNum mapping(bytes32 => uint16) dungeonSpecific; /// @dev contains all specific dungNum for easy management EnumerableSet.UintSet allSpecificDungeons; /// @dev biome => dungNum mapping(uint8 => EnumerableSet.UintSet) dungeonsLogicByBiome; // --- /// @dev max available biome. auto-increment with new dung deploy uint8 maxBiome; /// @notice Address of treasure token => min hero level required /// @dev manual threshold for treasury mapping(address => uint) minLevelForTreasury; /// @notice Contains arrays for SKILL_1, SKILL_2, SKILL_3 with 0 or 1 /// i.e. [0, 1, 0] means that durability of SKILL_2 should be reduced /// @dev hero + heroId => uint8[] array where idx = slotNum mapping(bytes32 => bytes32) skillSlotsForDurabilityReduction; /// @notice Counter of dungeons, it's incremented on launch of a new dungeon uint64 dungeonCounter; /// @dev dungNum = init attributes mapping(uint16 => DungeonAttributes) dungeonAttributes; /// @dev dungeonId => status mapping(uint64 => DungeonStatus) dungeonStatuses; } struct ObjectGenerateInfo { /// @notice List of chamber types for each unique object /// @dev uint8 types, packed using PackingLib.packUint8Array bytes32[] objTypesByStages; /// @notice List of chances for each chamber type /// @dev uint64 chances uint32[][] objChancesByStages; } struct DungeonGenerateInfo { /// @notice List of chamber types for each unique object uint8[][] objTypesByStages; /// @notice List of chances for each chamber type uint32[][] objChancesByStages; uint32[] uniqObjects; uint8 minLevel; uint8 maxLevel; bytes32[] requiredCustomDataIndex; uint64[] requiredCustomDataMinValue; uint64[] requiredCustomDataMaxValue; bool[] requiredCustomDataIsHero; } /// @notice Attributes of the given dungeon logic struct DungeonAttributes { /// @notice Total number of stages that should be passed to complete the dungeon uint8 stages; uint8 biome; /// @notice Default list of objects that should be passed in the dungeon uint32[] uniqObjects; /// @dev min+max (packUint8Array) bytes32 minMaxLevel; bytes32[] requiredCustomDataIndex; /// @notice Packed DungeonGenerateInfo.requiredCustomData: MinValue, MaxValue, IsHero /// @dev min+max+isHero(packStoryCustomDataRequirements) bytes32[] requiredCustomDataValue; ObjectGenerateInfo info; } /// @notice Current status of the given dungeon struct DungeonStatus { uint64 dungeonId; /// @notice Dungeon logic id uint16 dungNum; /// @notice True if the dungeon is completed by the hero bool isCompleted; /// @notice Hero in the dungeon or 0 address heroToken; uint heroTokenId; /// @notice Current object that should be passed by the hero. 0 - new object is not opened uint32 currentObject; /// @notice Current stage in the dungeon that should be passed by the hero. uint8 currentStage; EnumerableMap.AddressToUintMap treasuryTokens; /// @notice All items that were minted on result of made actions bytes32[] treasuryItems; /// @notice Total number of stages that should be passed to complete the dungeon /// This value can be bigger than length of uniqObjects uint8 stages; /// @notice List of objects to be passed in the stage. The list can be dynamically changed during passing the stages uint32[] uniqObjects; } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// function launchForNewHero(address heroToken, uint heroTokenId, address owner) external returns (uint64 dungeonId); function maxBiomeCompleted(address heroToken, uint heroTokenId) external view returns (uint8); function currentDungeon(address heroToken, uint heroTokenId) external view returns (uint64); function skillSlotsForDurabilityReduction(address heroToken, uint heroTokenId) external view returns (uint8[] memory result); function setBossCompleted(uint32 objectId, address heroToken, uint heroTokenId, uint8 heroBiome) external; /// @notice Hero exists current dungeon forcibly same as when dying but without loosing life chance function exitForcibly(address heroToken, uint heroTokenId, address msgSender) external; function maxAvailableBiome() external view returns (uint8); function reborn(address hero, uint heroId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "./IStatController.sol"; import "./IItemController.sol"; interface IFightCalculator { enum AttackType { UNKNOWN, // 0 MELEE, // 1 MAGIC, // 2 SLOT_3, SLOT_4, SLOT_5, SLOT_6, SLOT_7, SLOT_8, SLOT_9, SLOT_10 } /// @notice Attacker info: suitable both for hero and monsters struct AttackInfo { /// @notice Type of the attack /// by default, if attack token presents, it's magic attack and not-magic otherwise /// but this logic can become more complicated after introducing new attack types AttackType attackType; /// @notice NFT selected by hero for attack, it should be equip on. /// If attacker is a monster, this is a special case (stub NFT with zero ID is used) address attackToken; uint attackTokenId; address[] skillTokens; uint[] skillTokenIds; } struct FighterInfo { int32[] fighterAttributes; IStatController.ChangeableStats fighterStats; AttackType attackType; address attackToken; uint attackTokenId; uint race; } struct Statuses { bool stun; bool burn; bool freeze; bool confuse; bool curse; bool poison; bool gotCriticalHit; bool missed; bool hitBlocked; } struct FightResult { int32 healthA; int32 healthB; int32 manaConsumedA; int32 manaConsumedB; } struct FightCall { FighterInfo fighterA; FighterInfo fighterB; uint64 dungeonId; uint32 objectId; address heroAdr; uint heroId; uint8 stageId; uint iteration; uint8 turn; } struct SkillSlots { bool slot1; bool slot2; bool slot3; } //region ------------------------ FightLib-internal (FightInfoInternal is required by IApplicationEvents..) struct FightInfoInternal { Fighter fighterA; Fighter fighterB; } struct Fighter { IFightCalculator.FighterInfo info; IItemController.AttackInfo magicAttack; int32 health; int32 manaConsumed; int32 damage; int32 damagePoison; int32 damageReflect; IFightCalculator.Statuses statuses; } //endregion ------------------------ FightLib-internal function fight(FightCall memory callData) external returns (FightResult memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "./IERC20.sol"; interface IGameToken is IERC20 { function minter() external view returns (address); function mint(address account, uint amount) external returns (bool); function burn(uint amount) external returns (bool); function setMinter(address minter_) external; function pause(bool value) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "../openzeppelin/EnumerableSet.sol"; import "./IController.sol"; interface IGOC { enum ObjectType { UNKNOWN, // 0 EVENT, // 1 MONSTER, // 2 STORY, // 3 END_SLOT } enum ObjectSubType { UNKNOWN_0, // 0 ENEMY_NPC_1, // 1 ENEMY_NPC_SUPER_RARE_2, // 2 BOSS_3, // 3 SHRINE_4, // 4 CHEST_5, // 5 STORY_6, // 6 STORY_UNIQUE_7, // 7 SHRINE_UNIQUE_8, // 8 CHEST_UNIQUE_9, // 9 ENEMY_NPC_UNIQUE_10, // 10 STORY_ON_ROAD_11, // 11 STORY_UNDERGROUND_12, // 12 STORY_NIGHT_CAMP_13, // 13 STORY_MOUNTAIN_14, // 14 STORY_WATER_15, // 15 STORY_CASTLE_16, // 16 STORY_HELL_17, // 17 STORY_SPACE_18, // 18 STORY_WOOD_19, // 19 STORY_CATACOMBS_20, // 20 STORY_BAD_HOUSE_21, // 21 STORY_GOOD_TOWN_22, // 22 STORY_BAD_TOWN_23, // 23 STORY_BANDIT_CAMP_24, // 24 STORY_BEAST_LAIR_25, // 25 STORY_PRISON_26, // 26 STORY_SWAMP_27, // 27 STORY_INSIDE_28, // 28 STORY_OUTSIDE_29, // 29 STORY_INSIDE_RARE_30, STORY_OUTSIDE_RARE_31, ENEMY_NPC_INSIDE_32, ENEMY_NPC_INSIDE_RARE_33, ENEMY_NPC_OUTSIDE_34, ENEMY_NPC_OUTSIDE_RARE_35, END_SLOT } /// @custom:storage-location erc7201:game.object.controller.main struct MainState { /// @dev objId = biome(00) type(00) id(0000) => biome(uint8) + objType(uint8) /// Id is id of the event, story or monster. mapping(uint32 => bytes32) objectMeta; /// @dev biome(uint8) + objType(uint8) => set of object id mapping(bytes32 => EnumerableSet.UintSet) objectIds; /// @dev heroAdr180 + heroId64 + cType8 + biome8 => set of already played objects. Should be cleared periodically mapping(bytes32 => EnumerableSet.UintSet) playedObjects; /// @dev HeroAdr(160) + heroId(uint64) + objId(uint32) => iteration count. It needs for properly emit events for every new entrance. mapping(bytes32 => uint) iterations; /// @dev objId(uint32) => EventInfo mapping(uint32 => EventInfo) eventInfos; /// @dev objId(uint32) => storyId mapping(uint32 => uint16) storyIds; /// @dev objId(uint32) => MonsterInfo mapping(uint32 => MonsterInfo) monsterInfos; /// @dev hero+id => last fight action timestamp mapping(bytes32 => uint) lastHeroFightTs; /// @dev delay for user actions in fight (suppose to prevent bot actions) uint fightDelay; } struct ActionResult { bool kill; bool completed; address heroToken; address[] mintItems; int32 heal; int32 manaRegen; int32 lifeChancesRecovered; int32 damage; int32 manaConsumed; uint32 objectId; uint32 experience; uint heroTokenId; uint iteration; uint32[] rewriteNextObject; } struct EventInfo { /// @dev chance to use good or bad attributes/stats uint32 goodChance; /// @dev toBytes32ArrayWithIds bytes32[] goodAttributes; bytes32[] badAttributes; /// @dev experience(uint32) + heal(int32) + manaRegen(int32) + lifeChancesRecovered(int32) + damage(int32) + manaConsume(int32) packStatsChange bytes32 statsChange; /// @dev item+chance packItemMintInfo bytes32[] mintItems; } struct MonsterInfo { /// @dev toBytes32ArrayWithIds bytes32[] attributes; /// @dev level(uint8) + race(uint8) + experience(uint32) + maxDropItems(uint8) packMonsterStats bytes32 stats; /// @dev attackToken(160) + attackTokenId(uint64) + attackType(uint8) packAttackInfo bytes32 attackInfo; /// @dev item+chance packItemMintInfo bytes32[] mintItems; /// @dev heroAdr(160) + heroId(uint64) => iteration => GeneratedMonster packed mapping(bytes32 => mapping(uint => bytes32)) _generatedMonsters; } struct MultiplierInfo { uint8 biome; /// @notice NG_LEVEL of the hero who is going to fight with the given monster /// Use type(uint8).max for !NG+ uint8 heroNgLevel; } struct GeneratedMonster { bool generated; uint8 turnCounter; int32 hp; uint32 amplifier; } struct MonsterGenInfo { uint16 monsterId; uint8 biome; ObjectSubType subType; uint8[] attributeIds; int32[] attributeValues; uint8 level; uint8 race; uint32 experience; uint8 maxDropItems; address attackToken; uint64 attackTokenId; uint8 attackType; address[] mintItems; uint32[] mintItemsChances; } struct ActionContext { address sender; address heroToken; IController controller; uint8 biome; uint8 objectSubType; uint8 stageId; uint8 heroNgLevel; uint32 objectId; uint64 dungeonId; uint heroTokenId; uint salt; uint iteration; bytes data; } struct EventRegInfo { uint8 biome; uint16 eventId; ObjectSubType subType; uint32 goodChance; AttributeGenerateInfo goodAttributes; AttributeGenerateInfo badAttributes; uint32 experience; int32 heal; int32 manaRegen; int32 lifeChancesRecovered; int32 damage; int32 manaConsumed; address[] mintItems; uint32[] mintItemsChances; } struct AttributeGenerateInfo { uint8[] ids; int32[] values; } ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// /// @dev represent object registration if non zero values function getObjectMeta(uint32 objectId) external view returns (uint8 biome, uint8 objectSubType); function isBattleObject(uint32 objectId) external view returns (bool); function getRandomObject( uint8[] memory cTypes, uint32[] memory chances, uint8 biomeLevel, address heroToken, uint heroTokenId ) external returns (uint32 objectId); function open(address heroToken, uint heroTokenId, uint32 objectId) external returns (uint iteration); function action( address sender, uint64 dungeonId, uint32 objectId, address heroToken, uint heroTokenId, uint8 stageId, bytes memory data ) external returns (ActionResult memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "../openzeppelin/EnumerableSet.sol"; import "../openzeppelin/EnumerableMap.sol"; interface IHeroController { /// @custom:storage-location erc7201:hero.controller.main struct MainState { /// @dev A central place for all hero tokens /// @dev Deprecated. Controller is used instead. address heroTokensVault; /// @dev heroAdr => packed tokenAdr160+ amount96 mapping(address => bytes32) payToken; /// @dev heroAdr => heroCls8 mapping(address => uint8) heroClass; // --- /// @dev hero+id => individual hero name mapping(bytes32 => string) heroName; /// @dev name => hero+id, needs for checking uniq names mapping(string => bytes32) nameToHero; // --- /// @dev hero+id => biome mapping(bytes32 => uint8) heroBiome; /// @notice Exist reinforcement of any kind for the given hero /// @dev hero+id => packed reinforcement helper+id mapping(bytes32 => bytes32) reinforcementHero; /// @dev hero+id => reinforcement packed attributes mapping(bytes32 => bytes32[]) reinforcementHeroAttributes; /// @notice packedHero (hero + id) => count of calls of beforeTokenTransfer mapping(bytes32 => uint) countHeroTransfers; // ------------------------------------ NG plus /// @notice (tier, hero address) => TierInfo, where tier = [2, 3] /// @dev For tier=1 no data is required. Amount for tier 1 is stored in {payToken}, no items are minted /// Token from {payToken} is equal for all tiers mapping(bytes32 packedTierHero => TierInfo) tiers; mapping(bytes32 packedHero => HeroInfo) heroInfo; /// @notice Max NG_LVL reached by the heroes of a given account mapping(address user => uint8 maxNgLevel) maxUserNgLevel; /// @notice When the hero has killed boss on the given biome first time /// packedBiomeNgLevel = packed (biome, NG_LEVEL) mapping(bytes32 packedHero => mapping (bytes32 packedBiomeNgLevel => uint timestamp)) killedBosses; /// @notice Max NG_LEVEL reached by any user uint maxOpenedNgLevel; } /// @notice Tier = hero creation cost option /// There are 3 tiers: /// 1: most chip option, just pay fixed amount {payTokens} - new hero is created /// 2: pay bigger amount - random skill is equipped on the newly created hero /// 3: pay even more amount - random sill + some random items are equipped on the newly created hero struct TierInfo { /// @notice Cost of the hero creation using the given tier in terms of the token stored in {payToken} /// This amount is used for tiers 2, 3. For tier 1 the amount is taken from {payToken} uint amount; /// @notice All slots for which items-to-mint are registered in {itemsToMint} EnumerableSet.UintSet slots; /// @notice slot => items that can be minted and equipped on the hero to the given {slot} after hero creation mapping(uint8 slot => address[] items) itemsToMint; } /// @notice Current NG+-related values struct HeroInfo { /// @notice Hero tier = [0..3]. 0 - the hero is post-paid, it can be changed by upgrading the hero to pre-paid uint8 tier; /// @notice NG_LVL of the hero uint8 ngLevel; /// @notice True if hero has passed last biome on current NG+ and so NG_LEVEL can be incremented (reborn is allowed) bool rebornAllowed; /// @notice Amount paid for the hero on creation OR on upgrade to NG+ /// Amount paid for creation of the hero in terms of game token (!NG+) is NOT stored here. /// @dev uint72 is used here to pack the whole struct to single slot uint72 paidAmount; /// @notice Pay token used to pay {paidAmount} address paidToken; } /// @notice Input data to create new hero struct HeroCreationData { /// @notice Desired NG_LVL of the hero uint8 ngLevel; /// @notice Desired tire of the newly created hero. Allowed values: [1..3] uint8 tier; /// @notice Enter to the dungeon after creation bool enter; /// @notice Desired hero name string heroName; /// @notice Optional: user account for which the hero is created address targetUserAccount; /// @notice Optional: ref-code to be passed to the hero-creation-related event string refCode; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function heroClass(address hero) external view returns (uint8); function heroBiome(address hero, uint heroId) external view returns (uint8); function payTokenInfo(address hero) external view returns (address token, uint amount); function heroReinforcementHelp(address hero, uint heroId) external view returns (address helperHeroToken, uint helperHeroId); function score(address hero, uint heroId) external view returns (uint); function isAllowedToTransfer(address hero, uint heroId) external view returns (bool); function beforeTokenTransfer(address hero, uint heroId) external returns (bool); // --- function create(address hero, string memory heroName_, bool enter) external returns (uint); function kill(address hero, uint heroId) external returns (bytes32[] memory dropItems); /// @notice Take off all items from the hero, reduce life to 1. The hero is NOT burnt. /// Optionally reduce mana to zero and/or decrease life chance. function softKill(address hero, uint heroId, bool decLifeChances, bool resetMana) external returns (bytes32[] memory dropItems); function releaseReinforcement(address hero, uint heroId) external returns (address helperToken, uint helperId); function resetLifeAndMana(address hero, uint heroId) external; function countHeroTransfers(address hero, uint heroId) external view returns (uint); function askGuildReinforcement(address hero, uint heroId, address helper, uint helperId) external; function getHeroInfo(address hero, uint heroId) external view returns (IHeroController.HeroInfo memory data); function registerKilledBoss(address hero, uint heroId, uint32 objectId) external; function maxOpenedNgLevel() external view returns (uint); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "./IStatController.sol"; import "./IGOC.sol"; import "../openzeppelin/EnumerableSet.sol"; interface IItemController { enum GlobalParam { UNKNOWN_0, /// @notice Address of ItemControllerHelper ITEM_CONTROLLER_HELPER_ADDRESS_1 } /// @custom:storage-location erc7201:item.controller.main struct MainState { ////////////////// GENERATE ////////////////// EnumerableSet.AddressSet items; /// @dev itemAdr => itemMetaType8 + itemLvl8 + itemType8 + baseDurability16 + defaultRarity8 + minAttr8 + maxAttr8 + manaCost32 + req(packed core 128) mapping(address => bytes32) itemMeta; /// @dev itemAdr => packed tokenAdr160+ amount96 mapping(address => bytes32) augmentInfo; // --- common attr --- /// @dev itemAdr => id8 + min(int32) + max(int32) + chance32 mapping(address => bytes32[]) generateInfoAttributes; // --- consumable --- /// @dev itemAdr => ids+values (toBytes32ArrayWithIds) mapping(address => bytes32[]) _itemConsumableAttributes; /// @dev itemAdr => IStatController.ChangeableStats packed int32[] mapping(address => bytes32) itemConsumableStats; // --- buff --- /// @dev itemAdr => id8 + min(int32) + max(int32) + chance32 mapping(address => bytes32[]) generateInfoCasterAttributes; /// @dev itemAdr => id8 + minDmg(int32) + maxDmg(int32) + chance32 mapping(address => bytes32[]) generateInfoTargetAttributes; // --- attack --- /// @dev itemAdr => packed AttackInfo: attackType8 + min32 + max32 + factors(packed core 128) mapping(address => bytes32) generateInfoAttack; ////////////////// ITEMS INFO ////////////////// /// @dev itemAdr+id => itemRarity8 + augmentationLevel8 + itemDurability16 mapping(bytes32 => bytes32) itemInfo; /// @dev itemAdr+id => heroAdr+id mapping(bytes32 => bytes32) equippedOn; // --- common attr --- /// @dev itemAdr+Id => ids+values (toBytes32ArrayWithIds) mapping(bytes32 => bytes32[]) _itemAttributes; // --- consumable --- // consumable stats unchangeable, get them by address // --- buff --- /// @dev itemAdr+Id => ids+values (toBytes32ArrayWithIds) mapping(bytes32 => bytes32[]) _itemCasterAttributes; /// @dev itemAdr+Id => ids+values (toBytes32ArrayWithIds) mapping(bytes32 => bytes32[]) _itemTargetAttributes; // --- attack --- /// @dev itemAdr+Id => packed AttackInfo: attackType8 + min32 + max32 + factors(packed core 128) mapping(bytes32 => bytes32) _itemAttackInfo; ////////////////// Additional generate info ////////////////// /// @notice (itemAdr) => Bitmask of ConsumableActionBits mapping(address => uint) _consumableActionMask; /// --------------------------------- SIP-003: Item fragility /// @notice itemAdr + id => item fragility counter that displays the chance of an unsuccessful repair /// @dev [0...100_000], decimals 3 mapping(bytes32 packedItem => uint fragility) itemFragility; /// @notice Universal mapping to store various addresses and numbers (params of the contract) mapping (GlobalParam param => uint value) globalParam; /// @notice Item address => packedMetadata /// {packedMetaData} is encoded using abi.encode/abi.decode /// Read first byte, detect meta data type by the byte value, apply proper decoder from PackingLib mapping(address item => bytes packedMetaData) packedItemMetaData; } struct RegisterItemParams { ItemMeta itemMeta; address augmentToken; uint augmentAmount; ItemGenerateInfo commonAttributes; IGOC.AttributeGenerateInfo consumableAttributes; IStatController.ChangeableStats consumableStats; ItemGenerateInfo casterAttributes; ItemGenerateInfo targetAttributes; AttackInfo genAttackInfo; /// @notice Bit mask of ConsumableActionBits uint consumableActionMask; } /// @notice Possible actions that can be triggered by using the consumable item enum ConsumableActionBits { CLEAR_TEMPORARY_ATTRIBUTES_0 // other items are used instead this mask } struct ItemGenerateInfo { /// @notice Attribute ids uint8[] ids; /// @notice Min value of the attribute, != 0 int32[] mins; /// @notice Max value of the attribute, != 0 int32[] maxs; /// @notice Chance of the selection [0..MAX_CHANCES] uint32[] chances; } struct ItemMeta { uint8 itemMetaType; // Level in range 1-99. Reducing durability in low level dungeons. lvl/5+1 = biome uint8 itemLevel; IItemController.ItemType itemType; uint16 baseDurability; uint8 defaultRarity; uint32 manaCost; // it doesn't include positions with 100% chance uint8 minRandomAttributes; uint8 maxRandomAttributes; IStatController.CoreAttributes requirements; } // Deprecated. Todo - remove enum FeeType { UNKNOWN, REPAIR, AUGMENT, STORY, END_SLOT } enum ItemRarity { UNKNOWN, // 0 NORMAL, // 1 MAGIC, // 2 RARE, // 3 SET, // 4 UNIQUE, // 5 END_SLOT } enum ItemType { NO_SLOT, // 0 HEAD, // 1 BODY, // 2 GLOVES, // 3 BELT, // 4 AMULET, // 5 RING, // 6 OFF_HAND, // 7 BOOTS, // 8 ONE_HAND, // 9 TWO_HAND, // 10 SKILL, // 11 OTHER, // 12 END_SLOT } enum ItemMetaType { UNKNOWN, // 0 COMMON, // 1 ATTACK, // 2 BUFF, // 3 CONSUMABLE, // 4 END_SLOT } enum AttackType { UNKNOWN, // 0 FIRE, // 1 COLD, // 2 LIGHTNING, // 3 CHAOS, // 4 END_SLOT } struct AttackInfo { AttackType aType; int32 min; int32 max; // if not zero - activate attribute factor for the attribute IStatController.CoreAttributes attributeFactors; } struct ItemInfo { ItemRarity rarity; uint8 augmentationLevel; uint16 durability; } /// @dev The struct is used in events, so it's moved here from the lib struct MintInfo { IItemController.ItemMeta meta; uint8[] attributesIds; int32[] attributesValues; IItemController.ItemRarity itemRarity; IItemController.AttackInfo attackInfo; uint8[] casterIds; int32[] casterValues; uint8[] targetIds; int32[] targetValues; } /// @dev The struct is used in events, so it's moved here from the lib struct AugmentInfo { uint8[] attributesIds; int32[] attributesValues; IItemController.AttackInfo attackInfo; uint8[] casterIds; int32[] casterValues; uint8[] targetIds; int32[] targetValues; } ///region ------------------------ Item type "Other" /// @notice Possible kinds of "Other" items /// Each "Other" item has each own structure for metadata, see OtherItemXXX enum OtherSubtypeKind { UNKNOWN_0, /// @notice Item to reduce fragility, see SCB-1014. Metadata is {OtherItemReduceFragility} REDUCE_FRAGILITY_1, /// @notice This item allows asking guild reinforcement to the guild member USE_GUILD_REINFORCEMENT_2, /// @notice Exit from dungeon (shelter of level 3 is required) EXIT_FROM_DUNGEON_3, /// @notice Rest in the shelter: restore of hp & mp, clear temporally attributes, clear used consumables (shelter of level 3 is required) REST_IN_SHELTER_4, /// @notice Stub item (i.e. OTHER_4) that has no logic in contracts, but it has correct (not empty) packedMetaData EMPTY_NO_LOGIC_5, END_SLOT } struct OtherItemReduceFragility { /// @notice "Other" item kind. It MUST BE first field in the struct. uint8 kind; /// @notice Value on which the fragility will be reduced. /// @dev [0...100%], decimals 3, so the value is in the range [0...10_000] uint248 value; } ///endregion ------------------------ Item type "Other" //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// function itemMeta(address item) external view returns (ItemMeta memory meta); function augmentInfo(address item) external view returns (address token, uint amount); function genAttributeInfo(address item) external view returns (ItemGenerateInfo memory info); function genCasterAttributeInfo(address item) external view returns (ItemGenerateInfo memory info); function genTargetAttributeInfo(address item) external view returns (ItemGenerateInfo memory info); function genAttackInfo(address item) external view returns (AttackInfo memory info); function itemInfo(address item, uint itemId) external view returns (ItemInfo memory info); function equippedOn(address item, uint itemId) external view returns (address hero, uint heroId); function itemAttributes(address item, uint itemId) external view returns (int32[] memory values, uint8[] memory ids); function consumableAttributes(address item) external view returns (int32[] memory values, uint8[] memory ids); function consumableStats(address item) external view returns (IStatController.ChangeableStats memory stats); function casterAttributes(address item, uint itemId) external view returns (int32[] memory values, uint8[] memory ids); function targetAttributes(address item, uint itemId) external view returns (int32[] memory values, uint8[] memory ids); function itemAttackInfo(address item, uint itemId) external view returns (AttackInfo memory info); function score(address item, uint tokenId) external view returns (uint); function isAllowedToTransfer(address item, uint tokenId) external view returns (bool); // --- function mint(address item, address recipient) external returns (uint itemId); function reduceDurability(address hero, uint heroId, uint8 biome, bool reduceDurabilityAllSkills) external; function destroy(address item, uint tokenId) external; function takeOffDirectly( address item, uint itemId, address hero, uint heroId, uint8 itemSlot, address destination, bool broken ) external; /// @notice SIP-003: item fragility counter that displays the chance of an unsuccessful repair. /// @dev [0...100%], decimals 3, so the value is in the range [0...10_000] function itemFragility(address item, uint itemId) external view returns (uint); /// @notice SIP-003: The quest mechanic that previously burned the item will increase its fragility by 1% function incBrokenItemFragility(address item, uint itemId) external; function equip( address hero, uint heroId, address[] calldata items, uint[] calldata itemIds, uint8[] calldata itemSlots ) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; interface IOracle { function getRandomNumber(uint max, uint seed) external returns (uint); function getRandomNumberInRange(uint min, uint max, uint seed) external returns (uint); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; interface IProxyControlled { function upgrade(address newImplementation_) external; function implementation() external view returns (address); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "../openzeppelin/EnumerableSet.sol"; import "../openzeppelin/EnumerableMap.sol"; interface IStatController { /// @custom:storage-location erc7201:stat.controller.main struct MainState { mapping(bytes32 => bytes32[]) heroTotalAttributes; /// @dev heroAdr+heroId => int32 packed strength, dexterity, vitality, energy mapping(bytes32 => bytes32) _heroCore; mapping(bytes32 => bytes32[]) heroBonusAttributes; mapping(bytes32 => bytes32[]) heroTemporallyAttributes; /// @dev heroAdr+heroId => uint32 packed level, experience, life, mana, lifeChances mapping(bytes32 => bytes32) heroStats; /// @dev heroAdr+heroId+itemSlot => itemAdr + itemId mapping(bytes32 => bytes32) heroSlots; /// @dev heroAdr+heroId => busy slots uint8[] packed mapping(bytes32 => bytes32) heroBusySlots; mapping(bytes32 => EnumerableSet.AddressSet) usedConsumables; /// @dev heroCustomDataV2 is used instead mapping(bytes32 => mapping(bytes32 => uint)) _deprecated_heroCustomData; mapping(bytes32 => uint) globalCustomData; /// @notice packNftIdWithValue(hero, heroId, ngLevel) => hero custom data map /// @dev initially it was packedHero => hero custom data map mapping(bytes32 => EnumerableMap.Bytes32ToUintMap) heroCustomDataV2; } enum ATTRIBUTES { // core STRENGTH, // 0 DEXTERITY, // 1 VITALITY, // 2 ENERGY, // 3 // attributes DAMAGE_MIN, // 4 DAMAGE_MAX, // 5 ATTACK_RATING, // 6 DEFENSE, // 7 BLOCK_RATING, // 8 LIFE, // 9 MANA, // 10 // resistance FIRE_RESISTANCE, // 11 COLD_RESISTANCE, // 12 LIGHTNING_RESISTANCE, // 13 // dmg against DMG_AGAINST_HUMAN, // 14 DMG_AGAINST_UNDEAD, // 15 DMG_AGAINST_DAEMON, // 16 DMG_AGAINST_BEAST, // 17 // defence against DEF_AGAINST_HUMAN, // 18 DEF_AGAINST_UNDEAD, // 19 DEF_AGAINST_DAEMON, // 20 DEF_AGAINST_BEAST, // 21 // --- unique, not augmentable // hero will not die until have positive chances LIFE_CHANCES, // 22 // increase chance to get an item MAGIC_FIND, // 23 // decrease chance to get an item DESTROY_ITEMS, // 24 // percent of chance x2 dmg CRITICAL_HIT, // 25 // dmg factors MELEE_DMG_FACTOR, // 26 FIRE_DMG_FACTOR, // 27 COLD_DMG_FACTOR, // 28 LIGHTNING_DMG_FACTOR, // 29 // increase attack rating on given percent AR_FACTOR, // 30 // percent of damage will be converted to HP LIFE_STOLEN_PER_HIT, // 31 // amount of mana restored after each battle MANA_AFTER_KILL, // 32 // reduce all damage on percent after all other reductions DAMAGE_REDUCTION, // 33 // -- statuses // chance to stun an enemy, stunned enemy skip next hit STUN, // 34 // chance burn an enemy, burned enemy will loss 50% of defence BURN, // 35 // chance freeze an enemy, frozen enemy will loss 50% of MELEE damage FREEZE, // 36 // chance to reduce enemy's attack rating on 50% CONFUSE, // 37 // chance curse an enemy, cursed enemy will loss 50% of resistance CURSE, // 38 // percent of dmg return to attacker REFLECT_DAMAGE_MELEE, // 39 REFLECT_DAMAGE_MAGIC, // 40 // chance to poison enemy, poisoned enemy will loss 10% of the current health POISON, // 41 // reduce chance get any of uniq statuses RESIST_TO_STATUSES, // 42 END_SLOT // 43 } // possible // HEAL_FACTOR struct CoreAttributes { int32 strength; int32 dexterity; int32 vitality; int32 energy; } struct ChangeableStats { uint32 level; uint32 experience; uint32 life; uint32 mana; uint32 lifeChances; } enum ItemSlots { UNKNOWN, // 0 HEAD, // 1 BODY, // 2 GLOVES, // 3 BELT, // 4 AMULET, // 5 BOOTS, // 6 RIGHT_RING, // 7 LEFT_RING, // 8 RIGHT_HAND, // 9 LEFT_HAND, // 10 TWO_HAND, // 11 SKILL_1, // 12 SKILL_2, // 13 SKILL_3, // 14 END_SLOT // 15 } struct NftItem { address token; uint tokenId; } enum Race { UNKNOWN, // 0 HUMAN, // 1 UNDEAD, // 2 DAEMON, // 3 BEAST, // 4 END_SLOT // 5 } struct ChangeAttributesInfo { address heroToken; uint heroTokenId; int32[] changeAttributes; bool add; bool temporally; } struct BuffInfo { address heroToken; uint heroTokenId; uint32 heroLevel; address[] buffTokens; uint[] buffTokenIds; } /// @dev This struct is used inside event, so it's moved here from lib struct ActionInternalInfo { int32[] posAttributes; int32[] negAttributes; uint32 experience; int32 heal; int32 manaRegen; int32 lifeChancesRecovered; int32 damage; int32 manaConsumed; address[] mintedItems; } function initNewHero(address token, uint tokenId, uint heroClass) external; function heroAttributes(address token, uint tokenId) external view returns (int32[] memory); function heroAttribute(address token, uint tokenId, uint index) external view returns (int32); function heroAttributesLength(address token, uint tokenId) external view returns (uint); function heroBaseAttributes(address token, uint tokenId) external view returns (CoreAttributes memory); function heroCustomData(address token, uint tokenId, bytes32 index) external view returns (uint); function globalCustomData(bytes32 index) external view returns (uint); function heroStats(address token, uint tokenId) external view returns (ChangeableStats memory); function heroItemSlot(address token, uint64 tokenId, uint8 itemSlot) external view returns (bytes32 nftPacked); function heroItemSlots(address heroToken, uint heroTokenId) external view returns (uint8[] memory); function isHeroAlive(address heroToken, uint heroTokenId) external view returns (bool); function levelUp(address token, uint tokenId, uint heroClass, CoreAttributes memory change) external returns (uint newLvl); function changeHeroItemSlot( address heroToken, uint64 heroTokenId, uint itemType, uint8 itemSlot, address itemToken, uint itemTokenId, bool equip ) external; function changeCurrentStats( address token, uint tokenId, ChangeableStats memory change, bool increase ) external; function changeBonusAttributes(ChangeAttributesInfo memory info) external; function registerConsumableUsage(address heroToken, uint heroTokenId, address item) external; function clearUsedConsumables(address heroToken, uint heroTokenId) external; function clearTemporallyAttributes(address heroToken, uint heroTokenId) external; function buffHero(BuffInfo memory info) external view returns (int32[] memory attributes, int32 manaConsumed); function setHeroCustomData(address token, uint tokenId, bytes32 index, uint value) external; function setGlobalCustomData(bytes32 index, uint value) external; /// @notice Restore life and mana during reinforcement /// @dev Life and mana will be increased on ((current life/mana attr value) - (prev life/mana attr value)) /// @param prevAttributes Hero attributes before reinforcement function restoreLifeAndMana(address heroToken, uint heroTokenId, int32[] memory prevAttributes) external; function reborn(address heroToken, uint heroTokenId, uint heroClass) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "../interfaces/IGOC.sol"; import "../interfaces/IStatController.sol"; import "../interfaces/IItemController.sol"; import "./IController.sol"; import "./IOracle.sol"; import "./IHeroController.sol"; import "../openzeppelin/EnumerableSet.sol"; interface IStoryController { enum AnswerResultId { UNKNOWN, // 0 SUCCESS, // 1 ATTRIBUTE_FAIL, // 2 RANDOM_FAIL, // 3 DELAY_FAIL, // 4 HERO_CUSTOM_DATA_FAIL, // 5 GLOBAL_CUSTOM_DATA_FAIL, // 6 END_SLOT } enum CustomDataResult { UNKNOWN, // 0 HERO_SUCCESS, // 1 HERO_FAIL, // 2 GLOBAL_SUCCESS, // 3 GLOBAL_FAIL, // 4 END_SLOT } /// @custom:storage-location erc7201:story.controller.main struct MainState { // --- STORY REG INFO --- /// @dev Uniq story identification. mapping(uint32 => uint16) storyIds; /// @dev Revers mapping for stories for using in the next object rewrite logic. mapping(uint16 => uint32) idToStory; /// @dev Store used ids for stories. mapping(uint16 => bool) _usedStoryIds; /// @dev Prevent register the story twice mapping(uint32 => bool) registeredStories; // --- ANSWER MAPPING --- /// @dev storyId => all story pages. We need to have this mapping for properly remove meta info mapping(uint16 => EnumerableSet.UintSet) allStoryPages; /// @dev storyId => all possible answers. We need to have this mapping for properly remove meta info mapping(uint16 => EnumerableSet.Bytes32Set) allStoryAnswers; /// @dev storyId + pageId + heroClass (zero is default answers) => storyId + pageId + heroClass (zero is default answers) + answerId mapping(bytes32 => bytes32[]) answers; /// @dev answerUnPackedId + answerResultId => nextPageIds (will be chosen randomly from this array) /// where answerResultId is: /// 0 - unknown, /// 1 - success, /// 2 - attr fail /// 3 - random fail /// 4 - delay fail /// 5 - hero custom data fail /// 6 - global custom data fail /// see COUNT_ANSWER_RESULT_IDS mapping(bytes32 => uint16[]) nextPageIds; /// @dev story + pageId + heroClass (zero is default answers) => random nextObjs (adr + id, like packed nft id) mapping(bytes32 => uint32[]) nextObjectsRewrite; /// @dev answerPackedId => packed array of uint32[] /// 0 - random requirement(uint32, 1 - 99% success of this action, zero means no check) /// 1 - delay requirement(uint32, if time since the last call more than this value the check is fail, zero means no check) /// 2 - isFinalAnswer(uint8) mapping(bytes32 => bytes32) answerAttributes; // --- ANSWER REQUIREMENTS --- /// @dev answerPackedId => array of AttributeRequirementsPacked mapping(bytes32 => bytes32[]) attributeRequirements; /// @dev answerPackedId=> array of ItemRequirementsPacked mapping(bytes32 => bytes32[]) itemRequirements; /// @dev answerPackedId => array of TokenRequirementsPacked mapping(bytes32 => bytes32[]) tokenRequirements; /// @dev answerPackedId => custom data for hero mapping(bytes32 => CustomDataRequirementPacked[]) heroCustomDataRequirement; /// @dev answerPackedId => global custom data mapping(bytes32 => CustomDataRequirementPacked[]) globalCustomDataRequirement; // --- ANSWER RESULTS --- /// @dev answerPackedId => change attributes mapping(bytes32 => bytes32[]) successInfoAttributes; /// @dev answerPackedId => change stats mapping(bytes32 => bytes32) successInfoStats; /// @dev answerPackedId => mint items mapping(bytes32 => bytes32[]) successInfoMintItems; /// @dev answerPackedId => change attributes mapping(bytes32 => bytes32[]) failInfoAttributes; /// @dev answerPackedId => change stats mapping(bytes32 => bytes32) failInfoStats; /// @dev answerPackedId => mint items mapping(bytes32 => bytes32[]) failInfoMintItems; /// @dev answerUnPackedId + CustomDataResult => custom data array change /// where CustomDataResult is /// 1 - hero success /// 2 - hero fail /// 3 - global success /// 4 - global fail /// see COUNT_CUSTOM_DATA_RESULT_IDS mapping(bytes32 => bytes32[]) customDataResult; /// @notice answerPackedId => slot+chance+stopIfBurnt /// @dev Since SIP-003 the items are not burn but broke mapping(bytes32 => bytes32[]) burnItem; // --- GENERAL STORY REQUIREMENTS --- /// @dev story => Custom hero data requirements for a story. If exist and hero is not eligible should be not chose in a dungeon. mapping(uint => CustomDataRequirementRangePacked[]) storyRequiredHeroData; /// @dev story => Minimal level for the history. 0 means no requirements. mapping(uint => uint) storyRequiredLevel; // --- HERO STATES --- /// @dev hero + heroId + storyId => pageId + heroLastActionTS mapping(bytes32 => bytes32) heroState; // --- OTHER --- /// @dev storyId => build hash for the last update mapping(uint16 => uint) storyBuildHash; /// @notice Number of already minted items by the user within the given iteration of the story. /// Only minting of the given number of items is allowed per iteration (see MAX_MINTED_ITEMS_PER_ITERATION). /// @dev hero, heroId, story => mintedInIteration /// This map is not cleared: storyId:objectId is 1:1, each object has own sequence of iterations without duplicates mapping(bytes32 => mapping(uint iteration => uint countMintedItems)) mintedInIteration; } /// @dev We need to have flat structure coz Solidity can not handle arrays of structs properly struct StoryMetaInfo { uint16 storyId; // --- story reqs bytes32[] requiredCustomDataIndex; uint64[] requiredCustomDataMinValue; uint64[] requiredCustomDataMaxValue; bool[] requiredCustomDataIsHero; uint minLevel; // --- answer reqs AnswersMeta answersMeta; AnswerNextPageMeta answerNextPage; AnswerAttributeRequirementsMeta answerAttributeRequirements; AnswerItemRequirementsMeta answerItemRequirements; AnswerTokenRequirementsMeta answerTokenRequirements; AnswerAttributesMeta answerAttributes; AnswerCustomDataMeta answerHeroCustomDataRequirement; AnswerCustomDataMeta answerGlobalCustomDataRequirement; // --- answer results AnswerBurnRandomItemMeta answerBurnRandomItemMeta; NextObjRewriteMeta nextObjRewriteMeta; // --- story results AnswerResultMeta successInfo; AnswerResultMeta failInfo; AnswerCustomDataResultMeta successHeroCustomData; AnswerCustomDataResultMeta failHeroCustomData; AnswerCustomDataResultMeta successGlobalCustomData; AnswerCustomDataResultMeta failGlobalCustomData; } struct NextObjRewriteMeta { uint16[] nextObjPageIds; uint8[] nextObjHeroClasses; uint32[][] nextObjIds; } struct AnswersMeta { uint16[] answerPageIds; uint8[] answerHeroClasses; uint16[] answerIds; } struct AnswerNextPageMeta { uint16[] pageId; uint8[] heroClass; uint16[] answerId; uint8[] answerResultIds; uint16[][] answerNextPageIds; } struct AnswerAttributeRequirementsMeta { uint16[] pageId; uint8[] heroClass; uint16[] answerId; bool[][] cores; uint8[][] ids; int32[][] values; } struct AnswerItemRequirementsMeta { uint16[] pageId; uint8[] heroClass; uint16[] answerId; address[][] requireItems; bool[][] requireItemBurn; bool[][] requireItemEquipped; } struct AnswerTokenRequirementsMeta { uint16[] pageId; uint8[] heroClass; uint16[] answerId; address[][] requireToken; uint88[][] requireAmount; bool[][] requireTransfer; } struct AnswerAttributesMeta { uint16[] pageId; uint8[] heroClass; uint16[] answerId; uint32[] randomRequirements; uint32[] delayRequirements; bool[] isFinalAnswer; } struct AnswerCustomDataMeta { uint16[] pageId; uint8[] heroClass; uint16[] answerId; bytes32[][] dataIndexes; bool[][] mandatory; uint64[][] dataValuesMin; uint64[][] dataValuesMax; } struct AnswerResultMeta { uint16[] pageId; uint8[] heroClass; uint16[] answerId; uint8[][] attributeIds; /// @dev Max value is limitied by int24, see toBytes32ArrayWithIds impl int32[][] attributeValues; uint32[] experience; int32[] heal; int32[] manaRegen; int32[] lifeChancesRecovered; int32[] damage; int32[] manaConsumed; address[][] mintItems; uint32[][] mintItemsChances; } struct AnswerCustomDataResultMeta { uint16[] pageId; uint8[] heroClass; uint16[] answerId; bytes32[][] dataIndexes; int16[][] dataValues; } struct AnswerBurnRandomItemMeta { uint16[] pageId; uint8[] heroClass; uint16[] answerId; /// @notice 0 - random slot uint8[][] slots; /// @notice typical chances are [0..100] (no decimals here) uint64[][] chances; /// @notice Since SIP-003 the burning is replaced by breaking bu the name is kept as is bool[][] isStopIfBurnt; } struct CustomDataRequirementPacked { bytes32 index; /// @dev min(uint64) + max(uint64) + mandatory(uint8) bytes32 data; } struct CustomDataRequirementRangePacked { bytes32 index; /// @dev min(uint64) + max(uint64) + isHeroData(uint8) bytes32 data; } struct StatsChange { uint32 experience; int32 heal; int32 manaRegen; int32 lifeChancesRecovered; int32 damage; int32 manaConsumed; } struct StoryActionContext { uint stageId; uint iteration; bytes32 answerIdHash; bytes32 answerAttributes; address sender; address heroToken; IController controller; IStatController statController; IHeroController heroController; IOracle oracle; IItemController itemController; uint8 heroClass; uint8 heroClassFromAnswerHash; uint8 biome; uint16 storyId; uint16 storyIdFromAnswerHash; uint16 pageIdFromAnswerHash; uint16 answerNumber; uint16 pageId; uint32 objectId; uint64 dungeonId; uint40 heroLastActionTS; uint80 heroTokenId; IStatController.ChangeableStats heroStats; } // --- WRITE --- function storyAction( address sender, uint64 dungeonId, uint32 objectId, uint stageId, address heroToken, uint heroTokenId, uint8 biome, uint iteration, bytes memory data ) external returns (IGOC.ActionResult memory); // --- READ --- function isStoryAvailableForHero(uint32 objectId, address heroToken, uint heroTokenId) external view returns (bool); function idToStory(uint16 id) external view returns (uint32 objectId); function heroPage(address hero, uint80 heroId, uint16 storyId) external view returns (uint16 pageId); function storyIds(uint32 objectId) external view returns (uint16); function registeredStories(uint32 objectId) external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "../interfaces/IERC20.sol"; import "../interfaces/IAppErrors.sol"; import "../interfaces/IApplicationEvents.sol"; import "../interfaces/IProxyControlled.sol"; import "../interfaces/IGameToken.sol"; import "../openzeppelin/Math.sol"; library ControllerLib { //region ------------------------ Constants /// @dev keccak256(abi.encode(uint256(keccak256("controller.main")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant CONTROLLER_STORAGE_LOCATION = 0x4d96152d518acf5697a667aeb82f27b3218b679995afa077296a84fdcb65bb00; uint internal constant DEPLOYER_ELIGIBILITY_PERIOD = 7 days; uint internal constant DEFAULT_TOKEN_PRICE = 10e18; uint private constant _BURN_DENOMINATOR = 100e18; uint private constant _TOTAL_SUPPLY_BASE = 10_000_000e18; uint public constant HERO_PAYMENT_PART_BOSS_REWARDS_POOL = 80_000; uint public constant HERO_PAYMENT_PART_TREASURY_LAST_BIOME = 10_000; uint public constant HERO_PAYMENT_DENOMINATOR = 100_000; //endregion ------------------------ Constants //region ------------------------ Data types /// @custom:storage-location erc7201:controller.main struct MainState { address governance; address futureGovernance; address statController; address storyController; address oracle; address treasury; address dungeonFactory; address gameObjectController; address reinforcementController; address itemController; address heroController; address gameToken; mapping(address => bool) validTreasuryTokens; /// @dev EOA => eligibility time. We assume that deployer is fresh EOA and will be changed every deploy cycle for security reasons. mapping(address => uint) deployers; /// @dev In emergency case governance can pause all game bool onPause; address userController; address guildController; // some general relative price for the game token (how much game tokens need for 1 USD), 18 decimals, 10e18 by default uint gameTokenPrice; address rewardsPool; } //endregion ------------------------ Data types //region ------------------------ Restrictions function onlyGovernance() internal view { if (!_isGovernance(msg.sender)) revert IAppErrors.NotGovernance(msg.sender); } function onlyDeployer() internal view { if (!isDeployer(msg.sender)) revert IAppErrors.ErrorNotDeployer(msg.sender); } function onlyContractsAllowedToProcess(IController controller) internal view { if ( controller.heroController() != msg.sender && controller.userController() != msg.sender && controller.guildController() != msg.sender && controller.reinforcementController() != msg.sender && controller.itemController() != msg.sender && controller.storyController() != msg.sender ) { revert IAppErrors.ErrorNotAllowedSender(); } } //endregion ------------------------ Restrictions //region ------------------------ Views function _S() internal pure returns (MainState storage s) { assembly { s.slot := CONTROLLER_STORAGE_LOCATION } return s; } function isDeployer(address adr) internal view returns (bool) { uint t = _S().deployers[adr]; return (t != 0 && block.timestamp < t) || _isGovernance(adr); } function governance() internal view returns (address) {return _S().governance;} function futureGovernance() internal view returns (address) {return _S().futureGovernance;} function statController() internal view returns (address) {return _S().statController;} function storyController() internal view returns (address) {return _S().storyController;} function oracle() internal view returns (address) {return _S().oracle;} function treasury() internal view returns (address) {return _S().treasury;} function dungeonFactory() internal view returns (address) {return _S().dungeonFactory;} function gameObjectController() internal view returns (address) {return _S().gameObjectController;} function reinforcementController() internal view returns (address) {return _S().reinforcementController;} function itemController() internal view returns (address) {return _S().itemController;} function heroController() internal view returns (address) {return _S().heroController;} function gameToken() internal view returns (address) {return _S().gameToken;} function rewardsPool() internal view returns (address) {return _S().rewardsPool;} function validTreasuryTokens(address token) internal view returns (bool) { return _S().validTreasuryTokens[token]; } function onPause() internal view returns (bool) {return _S().onPause;} function userController() internal view returns (address) {return _S().userController;} function guildController() internal view returns (address) {return _S().guildController;} function gameTokenPrice() internal view returns (uint p) { p = _S().gameTokenPrice; if (p == 0) { p = DEFAULT_TOKEN_PRICE; } return p; } //endregion ------------------------ Views //region ------------------------ Gov actions - setters function changePause(bool value) internal { onlyDeployer(); _S().onPause = value; } function offerGovernance(address newGov) internal { onlyGovernance(); _S().futureGovernance = newGov; emit IApplicationEvents.OfferGovernance(newGov); } function acceptGovernance() internal { if (_S().futureGovernance != msg.sender) revert IAppErrors.NotFutureGovernance(msg.sender); _S().governance = msg.sender; delete _S().futureGovernance; emit IApplicationEvents.GovernanceAccepted(msg.sender); } function setStatController(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().statController = value; emit IApplicationEvents.StatControllerChanged(value); } function setStoryController(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().storyController = value; emit IApplicationEvents.StoryControllerChanged(value); } function setGameObjectController(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().gameObjectController = value; emit IApplicationEvents.GameObjectControllerChanged(value); } function setReinforcementController(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().reinforcementController = value; emit IApplicationEvents.ReinforcementControllerChanged(value); } function setOracle(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().oracle = value; emit IApplicationEvents.OracleChanged(value); } function setTreasury(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().treasury = value; emit IApplicationEvents.TreasuryChanged(value); } function setItemController(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().itemController = value; emit IApplicationEvents.ItemControllerChanged(value); } function setHeroController(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().heroController = value; emit IApplicationEvents.HeroControllerChanged(value); } function setGameToken(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().gameToken = value; emit IApplicationEvents.GameTokenChanged(value); } function setDungeonFactory(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().dungeonFactory = value; emit IApplicationEvents.DungeonFactoryChanged(value); } function changeDeployer(address eoa, bool remove) internal { onlyGovernance(); if (remove) { delete _S().deployers[eoa]; } else { _S().deployers[eoa] = block.timestamp + DEPLOYER_ELIGIBILITY_PERIOD; } } function setUserController(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().userController = value; emit IApplicationEvents.UserControllerChanged(value); } function setGuildController(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().guildController = value; emit IApplicationEvents.GuildControllerChanged(value); } function setRewardsPool(address value) internal { onlyGovernance(); if (value == address(0)) revert IAppErrors.ZeroAddress(); _S().rewardsPool = value; emit IApplicationEvents.RewardsPoolChanged(value); } function setGameTokenPrice(uint value) internal { onlyGovernance(); if (value == 0) revert IAppErrors.ZeroAmount(); _S().gameTokenPrice = value; emit IApplicationEvents.GameTokenPriceChanged(value); } //endregion ------------------------ Gov actions - setters //region ------------------------ Gov actions - others function updateProxies(address[] memory proxies, address newLogic) internal { onlyDeployer(); for (uint i; i < proxies.length; i++) { IProxyControlled(proxies[i]).upgrade(newLogic); emit IApplicationEvents.ProxyUpdated(proxies[i], newLogic); } } function claimToGovernance(address token) internal { onlyGovernance(); uint amount = IERC20(token).balanceOf(address(this)); if (amount != 0) { IERC20(token).transfer(_S().governance, amount); emit IApplicationEvents.Claimed(token, amount); } } //endregion ------------------------ Gov actions - others //region ------------------------ User actions /// @notice Transfer {amount} from {from}, divide it on three parts: to treasury, to governance, to burn /// User must approve given amount to the controller. /// @param amount Assume that this amount is approved by {from} to this contract function process(IController controller, address token, uint amount, address from) internal { onlyContractsAllowedToProcess(controller); (uint toBurn, uint toTreasury, uint toGov, uint toRewardsPool) = getProcessDetails(token, amount, controller.gameToken()); IERC20(token).transferFrom(from, address(this), amount); if (toRewardsPool != 0) { IERC20(token).transfer(controller.rewardsPool(), toRewardsPool); } if (toTreasury != 0) { IERC20(token).transfer(controller.treasury(), toTreasury); } if (toBurn != 0) { IGameToken(token).burn(toBurn); } // keep rest of the amount on balance of the controller (toGov) emit IApplicationEvents.Process(token, amount, from, toBurn, toTreasury, toGov); } function percentToBurn(uint totalSupply) internal pure returns (uint) { return Math.min(totalSupply * _BURN_DENOMINATOR / _TOTAL_SUPPLY_BASE, _BURN_DENOMINATOR); } function getProcessDetails(address token, uint amount, address gameToken_) internal pure returns ( uint toBurn, uint toTreasury, uint toGov, uint toRewardsPool ) { if (token == gameToken_) { // since SIP-005 we stop burn SACRA // toBurn = amount * percentToBurn(IERC20(token).totalSupply()) / _BURN_DENOMINATOR; toTreasury = (amount - toBurn) / 2; toGov = amount - toBurn - toTreasury; } else { toRewardsPool = amount * HERO_PAYMENT_PART_BOSS_REWARDS_POOL / HERO_PAYMENT_DENOMINATOR; toTreasury = amount * HERO_PAYMENT_PART_TREASURY_LAST_BIOME / HERO_PAYMENT_DENOMINATOR; toGov = amount - toRewardsPool - toTreasury; } return (toBurn, toTreasury, toGov, toRewardsPool); } //endregion ------------------------ User actions //region ------------------------ REGISTER ACTIONS function changeTreasuryTokenStatus(address token, bool status) internal { onlyGovernance(); _S().validTreasuryTokens[token] = status; emit IApplicationEvents.TokenStatusChanged(token, status); } //endregion ------------------------ REGISTER ACTIONS //region ------------------------ Internal logic function _isGovernance(address _value) internal view returns (bool) { return IController(address(this)).governance() == _value; } //endregion ------------------------ Internal logic }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; /// @title Library for setting / getting slot variables (used in upgradable proxy contracts) /// @author bogdoslav library SlotsLib { /// @notice Version of the contract /// @dev Should be incremented when contract changed string public constant SLOT_LIB_VERSION = "1.0.0"; // ************* GETTERS ******************* /// @dev Gets a slot as bytes32 function getBytes32(bytes32 slot) internal view returns (bytes32 result) { assembly { result := sload(slot) } } /// @dev Gets a slot as an address function getAddress(bytes32 slot) internal view returns (address result) { assembly { result := sload(slot) } } /// @dev Gets a slot as uint256 function getUint(bytes32 slot) internal view returns (uint result) { assembly { result := sload(slot) } } // ************* ARRAY GETTERS ******************* /// @dev Gets an array length function arrayLength(bytes32 slot) internal view returns (uint result) { assembly { result := sload(slot) } } /// @dev Gets a slot array by index as address /// @notice First slot is array length, elements ordered backward in memory /// @notice This is unsafe, without checking array length. function addressAt(bytes32 slot, uint index) internal view returns (address result) { bytes32 pointer = bytes32(uint(slot) - 1 - index); assembly { result := sload(pointer) } } // ************* SETTERS ******************* /// @dev Sets a slot with bytes32 /// @notice Check address for 0 at the setter function set(bytes32 slot, bytes32 value) internal { assembly { sstore(slot, value) } } /// @dev Sets a slot with address /// @notice Check address for 0 at the setter function set(bytes32 slot, address value) internal { assembly { sstore(slot, value) } } /// @dev Sets a slot with uint function set(bytes32 slot, uint value) internal { assembly { sstore(slot, value) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableMap.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. pragma solidity ^0.8.20; import {EnumerableSet} from "./EnumerableSet.sol"; /** * @dev Library for managing an enumerable variant of Solidity's * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] * type. * * Maps have the following properties: * * - Entries are added, removed, and checked for existence in constant time * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; * * // Declare a set state variable * EnumerableMap.UintToAddressMap private myMap; * } * ``` * * The following map types are supported: * * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0 * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0 * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0 * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableMap. * ==== */ library EnumerableMap { using EnumerableSet for EnumerableSet.Bytes32Set; // To implement this library for multiple types with as little code repetition as possible, we write it in // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions, // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map. // This means that we can only create new EnumerableMaps for types that fit in bytes32. /** * @dev Query for a nonexistent map key. */ error EnumerableMapNonexistentKey(bytes32 key); struct Bytes32ToBytes32Map { // Storage of keys EnumerableSet.Bytes32Set _keys; mapping(bytes32 key => bytes32) _values; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) { map._values[key] = value; return map._keys.add(key); } /** * @dev Removes a key-value pair from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { delete map._values[key]; return map._keys.remove(key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { return map._keys.contains(key); } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { return map._keys.length(); } /** * @dev Returns the key-value pair stored at position `index` in the map. O(1). * * Note that there are no guarantees on the ordering of entries inside the * array, and it may change when more entries are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { bytes32 key = map._keys.at(index); return (key, map._values[key]); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { bytes32 value = map._values[key]; if (value == bytes32(0)) { return (contains(map, key), bytes32(0)); } else { return (true, value); } } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { bytes32 value = map._values[key]; if (value == 0 && !contains(map, key)) { revert EnumerableMapNonexistentKey(key); } return value; } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { return map._keys.values(); } // UintToUintMap struct UintToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToUintMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(key))); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(UintToUintMap storage map) internal view returns (uint256[] memory) { bytes32[] memory store = keys(map._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintToAddressMap struct UintToAddressMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToAddressMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), address(uint160(uint256(value)))); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, address(uint160(uint256(value)))); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { return address(uint160(uint256(get(map._inner, bytes32(key))))); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) { bytes32[] memory store = keys(map._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressToUintMap struct AddressToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) { return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(AddressToUintMap storage map, address key) internal returns (bool) { return remove(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(AddressToUintMap storage map, address key) internal view returns (bool) { return contains(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns the number of elements in the map. O(1). */ function length(AddressToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (address(uint160(uint256(key))), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(AddressToUintMap storage map, address key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(uint256(uint160(key))))); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(AddressToUintMap storage map) internal view returns (address[] memory) { bytes32[] memory store = keys(map._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // Bytes32ToUintMap struct Bytes32ToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) { return set(map._inner, key, bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) { return remove(map._inner, key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) { return contains(map._inner, key); } /** * @dev Returns the number of elements in the map. O(1). */ function length(Bytes32ToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (key, uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, key); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) { return uint256(get(map._inner, key)); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) { bytes32[] memory store = keys(map._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.20; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._positions[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an success flag (no overflow). */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow). */ function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow). */ function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). */ function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // The following calculation ensures accurate ceiling division without overflow. // Since a is non-zero, (a - 1) / b will not overflow. // The largest possible result occurs when (a - 1) / b is type(uint256).max, // but the largest value we can obtain is type(uint256).max - 1, which happens // when a = type(uint256).max and b = 1. unchecked { return a == 0 ? 0 : (a - 1) / b + 1; } } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import "../openzeppelin/Initializable.sol"; import "../interfaces/IControllable.sol"; import "../interfaces/IController.sol"; import "../lib/SlotsLib.sol"; /// @title Implement basic functionality for any contract that require strict control /// @dev Can be used with upgradeable pattern. /// Require call __Controllable_init() in any case. /// @author belbix abstract contract Controllable is Initializable, IControllable { using SlotsLib for bytes32; /// @notice Version of the contract /// @dev Should be incremented when contract changed string public constant CONTROLLABLE_VERSION = "1.0.0"; bytes32 internal constant _CONTROLLER_SLOT = bytes32(uint256(keccak256("eip1967.controllable.controller")) - 1); bytes32 internal constant _CREATED_SLOT = bytes32(uint256(keccak256("eip1967.controllable.created")) - 1); bytes32 internal constant _CREATED_BLOCK_SLOT = bytes32(uint256(keccak256("eip1967.controllable.created_block")) - 1); bytes32 internal constant _REVISION_SLOT = bytes32(uint256(keccak256("eip1967.controllable.revision")) - 1); bytes32 internal constant _PREVIOUS_LOGIC_SLOT = bytes32(uint256(keccak256("eip1967.controllable.prev_logic")) - 1); event ContractInitialized(address controller, uint ts, uint block); event RevisionIncreased(uint value, address oldLogic); // init implementation contract constructor() initializer {} /// @notice Initialize contract after setup it as proxy implementation /// Save block.timestamp in the "created" variable /// @dev Use it only once after first logic setup /// @param controller_ Controller address function __Controllable_init(address controller_) internal onlyInitializing { _init(controller_); } function _init(address controller_) private { require(controller_ != address(0), "Zero controller"); _CONTROLLER_SLOT.set(controller_); _CREATED_SLOT.set(block.timestamp); _CREATED_BLOCK_SLOT.set(block.number); emit ContractInitialized(controller_, block.timestamp, block.number); } /// @dev Return true if given address is controller function isController(address value_) public override view returns (bool) { return value_ == controller(); } /// @notice Return true if given address is setup as governance in Controller function isGovernance(address value_) public override view returns (bool) { return IController(controller()).governance() == value_; } /// @dev Contract upgrade counter function revision() external view override returns (uint) { return _REVISION_SLOT.getUint(); } /// @dev Previous logic implementation function previousImplementation() external view override returns (address) { return _PREVIOUS_LOGIC_SLOT.getAddress(); } // ************* SETTERS/GETTERS ******************* /// @notice Return controller address saved in the contract slot function controller() public view override returns (address) { return _CONTROLLER_SLOT.getAddress(); } /// @notice Return creation timestamp /// @return Creation timestamp function created() external view override returns (uint256) { return _CREATED_SLOT.getUint(); } /// @notice Return creation block number /// @return Creation block number function createdBlock() external override view returns (uint256) { return _CREATED_BLOCK_SLOT.getUint(); } /// @dev Revision should be increased on each contract upgrade function increaseRevision(address oldLogic) external override { require(msg.sender == address(this), "Increase revision forbidden"); uint r = _REVISION_SLOT.getUint() + 1; _REVISION_SLOT.set(r); _PREVIOUS_LOGIC_SLOT.set(oldLogic); emit RevisionIncreased(r, oldLogic); } }
{ "evmVersion": "istanbul", "optimizer": { "enabled": true, "runs": 50 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"ErrorNotAllowedSender","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ErrorNotDeployer","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotFutureGovernance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotGovernance","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"controller","type":"address"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"block","type":"uint256"}],"name":"ContractInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"DungeonFactoryChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"GameObjectControllerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"GameTokenChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"GameTokenPriceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"gov","type":"address"}],"name":"GovernanceAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"GuildControllerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"HeroControllerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"ItemControllerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newGov","type":"address"}],"name":"OfferGovernance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"OracleChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"toBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTreasury","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toGov","type":"uint256"}],"name":"Process","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"proxy","type":"address"},{"indexed":false,"internalType":"address","name":"logic","type":"address"}],"name":"ProxyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"ReinforcementControllerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"address","name":"oldLogic","type":"address"}],"name":"RevisionIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"RewardsPoolChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"StatControllerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"StoryControllerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"TokenStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"TreasuryChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"UserControllerChanged","type":"event"},{"inputs":[],"name":"CONTROLLABLE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPLOYER_ELIGIBILITY_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"eoa","type":"address"},{"internalType":"bool","name":"remove","type":"bool"}],"name":"changeDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"value","type":"bool"}],"name":"changePause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"changeTreasuryTokenStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"claimToGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"created","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"createdBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dungeonFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"futureGovernance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameObjectController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameTokenPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getProcessDetails","outputs":[{"internalType":"uint256","name":"toBurn","type":"uint256"},{"internalType":"uint256","name":"toTreasury","type":"uint256"},{"internalType":"uint256","name":"toGov","type":"uint256"},{"internalType":"uint256","name":"toRewardsPool","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guildController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"heroController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"oldLogic","type":"address"}],"name":"increaseRevision","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"governance_","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value_","type":"address"}],"name":"isController","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"adr","type":"address"}],"name":"isDeployer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"value_","type":"address"}],"name":"isGovernance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"itemController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newGov","type":"address"}],"name":"offerGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"onPause","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"percentToBurn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"previousImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"from","type":"address"}],"name":"process","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reinforcementController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"revision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setDungeonFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setGameObjectController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setGameToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setGameTokenPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setGuildController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setHeroController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setItemController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setReinforcementController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setRewardsPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setStatController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setStoryController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setUserController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"statController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"storyController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"proxies","type":"address[]"},{"internalType":"address","name":"newLogic","type":"address"}],"name":"updateProxies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"userController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"validTreasuryTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b507ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff1615906001600160401b03166000811580156200005d5750825b90506000826001600160401b031660011480156200007a5750303b155b90508115801562000089575080155b15620000a85760405163f92ee8a960e01b815260040160405180910390fd5b84546001600160401b03191660011785558315620000d757845460ff60401b1916680100000000000000001785555b83156200011e57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050506127e280620001336000396000f3fe608060405234801561001057600080fd5b50600436106102ac5760003560e01c806368321eb7116101735780639d0bcca0116100d45780639d0bcca01461055f578063b1bc419514610567578063b429afeb1461056f578063bcb384fa14610582578063c3dfdae614610595578063c81529c61461059d578063d11d1861146105b0578063dee1f0e4146105ba578063e4ce0871146105cd578063f0f44260146105e0578063f2c7b2eb146105f3578063f6914cfa14610606578063f77c479114610619578063ffa1ad741461062157600080fd5b806368321eb71461044e578063683fedf7146104815780637262bb2d146104895780637405bab81461049c5780637adbf973146104af5780637c000293146104c25780637c66b452146104d55780637cc96380146104e85780637dc0d1d0146104f05780638070c503146104f857806380d29e6614610500578063822f804c1461051357806389dd9f1314610526578063936725ec1461052e57600080fd5b8063359a7d8f1161021d578063359a7d8f1461037b578063361e4b271461038e5780633c8f1bbe146103a15780634453bd89146103b45780634576dc52146103c75780634593144c146103da578063490fb76a146103e25780634fac6ccd146103ea57806350c358a4146103fd578063524a562f146104105780635aa6e675146104185780635d4fead314610420578063605918ae1461043357806361d027b31461044657600080fd5b80628e9691146102b1578063016dff5d146102cf5780630359fea9146102d757806308ac0fd7146102df57806311b0aebe146102f457806318d928311461031557806319ab453c1461032d5780631ec4760014610340578063238efcbc1461035357806325eb1c871461035b5780632f91ede91461036357806331423c261461036b578063325a19f114610373575b600080fd5b6102b9610645565b6040516102c69190612418565b60405180910390f35b6102b9610654565b6102b961065e565b6102f26102ed366004612451565b610668565b005b61030761030236600461246e565b610674565b6040519081526020016102c6565b61031d610685565b60405190151581526020016102c6565b6102f261033b366004612451565b61068f565b6102f261034e366004612451565b6107b2565b6102f26107bb565b6102b96107c5565b6102b96107cf565b6102b96107d9565b6103076107e3565b6102f2610389366004612451565b610817565b6102f261039c366004612451565b610820565b6102f26103af366004612487565b610829565b6102f26103c2366004612451565b61083a565b6102f26103d53660046124df565b610843565b610307610851565b6102b9610881565b6102f26103f8366004612451565b61088b565b61031d61040b366004612451565b61099d565b6102b96109a8565b6102b96109b2565b6102f261042e3660046125c4565b6109bc565b6102f2610441366004612451565b6109c5565b6102b96109ce565b61046161045c3660046125e1565b6109d8565b6040805194855260208501939093529183015260608201526080016102c6565b6102b9610a5a565b6102f261049736600461260d565b610a64565b6102f26104aa366004612451565b610a6e565b6102f26104bd366004612451565b610a77565b6102f26104d0366004612451565b610a80565b61031d6104e3366004612451565b610a89565b610307610a94565b6102b9610ab2565b6102b9610abc565b6102f261050e366004612451565b610ac6565b6102f2610521366004612451565b610acf565b6102b9610ad8565b610552604051806040016040528060058152602001640312e302e360dc1b81525081565b6040516102c69190612646565b6102b9610ae2565b610307610b12565b61031d61057d366004612451565b610b1c565b6102f2610590366004612451565b610b41565b6102b9610b4a565b6102f26105ab366004612451565b610b54565b61030762093a8081565b61031d6105c8366004612451565b610b5d565b6102f26105db366004612451565b610be2565b6102f26105ee366004612451565b610beb565b6102f261060136600461246e565b610bf4565b6102f261061436600461260d565b610bfd565b6102b9610c07565b61055260405180604001604052806005815260200164312e302e3360d81b81525081565b600061064f610c37565b905090565b600061064f610c53565b600061064f610c6f565b61067181610c8b565b50565b600061067f82610d1f565b92915050565b600061064f610d5c565b6000610699610d72565b805490915060ff600160401b820416159067ffffffffffffffff166000811580156106c15750825b905060008267ffffffffffffffff1660011480156106de5750303b155b9050811580156106ec575080155b1561070a5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561073457845460ff60401b1916600160401b1785555b61073d30610d96565b85610746610da7565b80546001600160a01b0319166001600160a01b039290921691909117905583156107aa57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b61067181610dcb565b6107c3610e2d565b565b600061064f610edd565b600061064f610ef9565b600061064f610f15565b600061064f61081360017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b6126ab565b5490565b61067181610f31565b61067181610fbf565b61083530848484611048565b505050565b610671816113b0565b61084d8282611439565b5050565b600061064f61081360017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f16126ab565b600061064f611533565b3330146108dd5760405162461bcd60e51b815260206004820152601b60248201527a24b731b932b0b9b2903932bb34b9b4b7b7103337b93134b23232b760291b60448201526064015b60405180910390fd5b60006108fb610813600160008051602061278d8339815191526126ab565b6109069060016126be565b905061092881610925600160008051602061278d8339815191526126ab565b55565b6109578261092560017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e46126ab565b604080518281526001600160a01b03841660208201527ff27e2ef832a4eb8ed8ec553b875eecd44764cda95b1c24170e281539e0a869c891015b60405180910390a15050565b600061067f82611554565b600061064f6115a2565b600061064f6115be565b610671816115d7565b610671816115fd565b600061064f611686565b600080600080610a4a8686306001600160a01b031663c3dfdae66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4591906126d1565b6116a2565b9299919850965090945092505050565b600061064f61174f565b61084d828261176b565b610671816117d8565b61067181611861565b610671816118ea565b600061067f82611973565b600061064f610813600160008051602061278d8339815191526126ab565b600061064f6119a2565b600061064f6119be565b610671816119da565b61067181611a63565b600061064f611aec565b600061064f61081360017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e46126ab565b600061064f611b08565b6000610b26610c07565b6001600160a01b0316826001600160a01b0316149050919050565b61067181611b2e565b600061064f611c67565b61067181611c83565b6000816001600160a01b0316610b71610c07565b6001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd291906126d1565b6001600160a01b03161492915050565b61067181611d0c565b61067181611d95565b61067181611e1e565b61084d8282611e84565b600061064f61081360017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c36186126ab565b6000610c41610da7565b600201546001600160a01b0316919050565b6000610c5d610da7565b600a01546001600160a01b0316919050565b6000610c79610da7565b601101546001600160a01b0316919050565b610c93611efc565b6001600160a01b038116610cba5760405163d92e233d60e01b815260040160405180910390fd5b80610cc3610da7565b60060180546001600160a01b0319166001600160a01b03929092169190911790556040517f5d77c617926cd1f4106de1bae23b2eb1a9d6e84911f701858a0b1d831e92816590610d14908390612418565b60405180910390a150565b600061067f6a084595161401484a000000610d4368056bc75e2d63100000856126ee565b610d4d9190612705565b68056bc75e2d63100000611f24565b6000610d66610da7565b600e015460ff16919050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0090565b610d9e611f3a565b61067181611f5f565b7f4d96152d518acf5697a667aeb82f27b3218b679995afa077296a84fdcb65bb0090565b610dd3611efc565b80610ddc610da7565b60010180546001600160a01b0319166001600160a01b03929092169190911790556040517f93a15bbe6d7cb67fff86738ed92efd14e9fe04e7d30042086570034a2f2eb3c290610d14908390612418565b33610e36610da7565b600101546001600160a01b031614610e63573360405163ba18f1e160e01b81526004016108d49190612418565b33610e6c610da7565b80546001600160a01b0319166001600160a01b0392909216919091179055610e92610da7565b60010180546001600160a01b03191690556040517fb1476cf38ac36ee528f1ad1ae81bdb46de8807d42475e16078426bce6001396190610ed3903390612418565b60405180910390a1565b6000610ee7610da7565b600f01546001600160a01b0316919050565b6000610f03610da7565b600801546001600160a01b0316919050565b6000610f1f610da7565b600901546001600160a01b0316919050565b610f39611efc565b6001600160a01b038116610f605760405163d92e233d60e01b815260040160405180910390fd5b80610f69610da7565b600e0160016101000a8154816001600160a01b0302191690836001600160a01b031602179055507fd86fc86ebea7a7d81c1a9fa7e0977cdafcfccf0cc35295a095231a7b28274e4981604051610d149190612418565b610fc7611efc565b6001600160a01b038116610fee5760405163d92e233d60e01b815260040160405180910390fd5b80610ff7610da7565b60030180546001600160a01b0319166001600160a01b03929092169190911790556040517fecbc0f0d903f1b9964d257a8043a5ecdf9c55a8e3d0060fb920b40c4009a257d90610d14908390612418565b6110518461207c565b60008060008061109a87878a6001600160a01b031663c3dfdae66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a21573d6000803e3d6000fd5b6040516323b872dd60e01b81526001600160a01b038a81166004830152306024830152604482018c90529498509296509094509250908816906323b872dd906064016020604051808303816000875af11580156110fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111f9190612727565b5080156111fa57866001600160a01b031663a9059cbb896001600160a01b0316630359fea96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611173573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119791906126d1565b836040518363ffffffff1660e01b81526004016111b5929190612744565b6020604051808303816000875af11580156111d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f89190612727565b505b82156112d457866001600160a01b031663a9059cbb896001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561124d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127191906126d1565b856040518363ffffffff1660e01b815260040161128f929190612744565b6020604051808303816000875af11580156112ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d29190612727565b505b831561134757604051630852cd8d60e31b8152600481018590526001600160a01b038816906342966c68906024016020604051808303816000875af1158015611321573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113459190612727565b505b604080516001600160a01b03898116825260208201899052871681830152606081018690526080810185905260a0810184905290517f1fd334c200f7b34cefbcb9762981e99dea5bdff9c149c5e4a279a1f55e8c97729181900360c00190a15050505050505050565b6113b8611efc565b6001600160a01b0381166113df5760405163d92e233d60e01b815260040160405180910390fd5b806113e8610da7565b600f0180546001600160a01b0319166001600160a01b03929092169190911790556040517f0d1f076dd618d44fc1ed0ae909dcb5a875262080a1fb3386f155e47003323ed790610d14908390612418565b61144161238c565b60005b82518110156108355782818151811061145f5761145f61275d565b60200260200101516001600160a01b0316630900f010836040518263ffffffff1660e01b81526004016114929190612418565b600060405180830381600087803b1580156114ac57600080fd5b505af11580156114c0573d6000803e3d6000fd5b505050507fd32d24edea94f55e932d9a008afc425a8561462d1b1f57bc6e508e9a6b9509e18382815181106114f7576114f761275d565b6020026020010151836040516115239291906001600160a01b0392831681529116602082015260400190565b60405180910390a1600101611444565b600061153d610da7565b600e015461010090046001600160a01b0316919050565b60008061155f610da7565b6001600160a01b0384166000908152600d9190910160205260409020549050801580159061158c57508042105b8061159b575061159b836123b4565b9392505050565b60006115ac610da7565b600301546001600160a01b0316919050565b60006115c8610da7565b546001600160a01b0316919050565b6115df61238c565b806115e8610da7565b600e01805460ff191691151591909117905550565b611605611efc565b6001600160a01b03811661162c5760405163d92e233d60e01b815260040160405180910390fd5b80611635610da7565b60020180546001600160a01b0319166001600160a01b03929092169190911790556040517f573b0be2ffc8c66825968c4e3b38a0af5edb18ce20f9a516e0f8a04867d2638990610d14908390612418565b6000611690610da7565b600501546001600160a01b0316919050565b600080600080846001600160a01b0316876001600160a01b0316036116f55760026116cd85886126ab565b6116d79190612705565b9250826116e485886126ab565b6116ee91906126ab565b9150611746565b620186a061170662013880886126ee565b6117109190612705565b9050620186a0611722612710886126ee565b61172c9190612705565b92508261173982886126ab565b61174391906126ab565b91505b93509350935093565b6000611759610da7565b600601546001600160a01b0316919050565b611773611efc565b80156117a257611781610da7565b6001600160a01b0383166000908152600d9190910160205260408120555050565b6117af62093a80426126be565b6117b7610da7565b6001600160a01b0384166000908152600d9190910160205260409020555050565b6117e0611efc565b6001600160a01b0381166118075760405163d92e233d60e01b815260040160405180910390fd5b80611810610da7565b60090180546001600160a01b0319166001600160a01b03929092169190911790556040517fedcd6ea89a41d21f1bafa9a7cc32e754079d18642839a1a48c938447d2a740eb90610d14908390612418565b611869611efc565b6001600160a01b0381166118905760405163d92e233d60e01b815260040160405180910390fd5b80611899610da7565b60040180546001600160a01b0319166001600160a01b03929092169190911790556040517f0e05ae75e8b926552cf6fcd744d19f422561e3ced1e426868730852702dbe41890610d14908390612418565b6118f2611efc565b6001600160a01b0381166119195760405163d92e233d60e01b815260040160405180910390fd5b80611922610da7565b60110180546001600160a01b0319166001600160a01b03929092169190911790556040517f657bb19de5473f7be7de9ccbcfa6d9aabcb3cfd199aef85e949a1d8570c290ab90610d14908390612418565b600061197d610da7565b6001600160a01b039092166000908152600c9290920160205250604090205460ff1690565b60006119ac610da7565b600401546001600160a01b0316919050565b60006119c8610da7565b600101546001600160a01b0316919050565b6119e2611efc565b6001600160a01b038116611a095760405163d92e233d60e01b815260040160405180910390fd5b80611a12610da7565b600b0180546001600160a01b0319166001600160a01b03929092169190911790556040517f035bee136adcafe288762d810fef741bc236d20bb1b469acb4c23e5357f0856790610d14908390612418565b611a6b611efc565b6001600160a01b038116611a925760405163d92e233d60e01b815260040160405180910390fd5b80611a9b610da7565b60070180546001600160a01b0319166001600160a01b03929092169190911790556040517ffa195fffb4bf4e5339e2e98fb090f0d634c64261640c07c1ee6ee43d5f23516190610d14908390612418565b6000611af6610da7565b600701546001600160a01b0316919050565b6000611b12610da7565b60100154905080600003611b2b5750678ac7230489e800005b90565b611b36611efc565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190611b65903090600401612418565b602060405180830381865afa158015611b82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba69190612773565b9050801561084d57816001600160a01b031663a9059cbb611bc5610da7565b546040516001600160e01b031960e084901b168152611bf2916001600160a01b0316908590600401612744565b6020604051808303816000875af1158015611c11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c359190612727565b507fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a8282604051610991929190612744565b6000611c71610da7565b600b01546001600160a01b0316919050565b611c8b611efc565b6001600160a01b038116611cb25760405163d92e233d60e01b815260040160405180910390fd5b80611cbb610da7565b600a0180546001600160a01b0319166001600160a01b03929092169190911790556040517fd1e9a4ae1231531a757f1e31a2ff8a1db9d359a194436efe40bccb972cde86f090610d14908390612418565b611d14611efc565b6001600160a01b038116611d3b5760405163d92e233d60e01b815260040160405180910390fd5b80611d44610da7565b60080180546001600160a01b0319166001600160a01b03929092169190911790556040517f29fdde0e067ae34f44ca706fd84ea4b9dabb69557e7e935d379c932ba023b2be90610d14908390612418565b611d9d611efc565b6001600160a01b038116611dc45760405163d92e233d60e01b815260040160405180910390fd5b80611dcd610da7565b60050180546001600160a01b0319166001600160a01b03929092169190911790556040517fc714d22a2f08b695f81e7c707058db484aa5b4d6b4c9fd64beb10fe85832f60890610d14908390612418565b611e26611efc565b80600003611e4757604051631f2a200560e01b815260040160405180910390fd5b80611e50610da7565b601001556040518181527f867c590cfc1b2ba6732d5d876a96733ad5cde9c836a978d6107517c00cf3f44590602001610d14565b611e8c611efc565b80611e95610da7565b6001600160a01b0384166000818152600c929092016020908152604092839020805460ff1916941515949094179093558151908152831515928101929092527f0de9c5667496fd561ff9dfa59efdc1c76f7dbf3844adae3d14a3a14d563321b19101610991565b611f05336123b4565b6107c3573360405163988d1f0360e01b81526004016108d49190612418565b6000818310611f33578161159b565b5090919050565b611f426123fe565b6107c357604051631afcd79f60e31b815260040160405180910390fd5b6001600160a01b038116611fa75760405162461bcd60e51b815260206004820152600f60248201526e2d32b9379031b7b73a3937b63632b960891b60448201526064016108d4565b611fd68161092560017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c36186126ab565b6120054261092560017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b6126ab565b6120344361092560017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f16126ab565b604080516001600160a01b038316815242602082015243918101919091527f1a2dd071001ebf6e03174e3df5b305795a4ad5d41d8fdb9ba41dbbe23671342690606001610d14565b336001600160a01b0316816001600160a01b031663016dff5d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e891906126d1565b6001600160a01b0316141580156121725750336001600160a01b0316816001600160a01b031663490fb76a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612142573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216691906126d1565b6001600160a01b031614155b80156121f15750336001600160a01b0316816001600160a01b03166325eb1c876040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e591906126d1565b6001600160a01b031614155b80156122705750336001600160a01b0316816001600160a01b0316632f91ede96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612240573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226491906126d1565b6001600160a01b031614155b80156122ef5750336001600160a01b0316816001600160a01b03166331423c266040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e391906126d1565b6001600160a01b031614155b801561236e5750336001600160a01b0316816001600160a01b031663524a562f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561233e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236291906126d1565b6001600160a01b031614155b156106715760405163f20e063760e01b815260040160405180910390fd5b61239533611554565b6107c3573360405163451cea1760e11b81526004016108d49190612418565b6000816001600160a01b0316306001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bae573d6000803e3d6000fd5b6000612408610d72565b54600160401b900460ff16919050565b6001600160a01b0391909116815260200190565b6001600160a01b038116811461067157600080fd5b803561244c8161242c565b919050565b60006020828403121561246357600080fd5b813561159b8161242c565b60006020828403121561248057600080fd5b5035919050565b60008060006060848603121561249c57600080fd5b83356124a78161242c565b92506020840135915060408401356124be8161242c565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156124f257600080fd5b823567ffffffffffffffff8082111561250a57600080fd5b818501915085601f83011261251e57600080fd5b8135602082821115612532576125326124c9565b8160051b604051601f19603f83011681018181108682111715612557576125576124c9565b60405292835281830193508481018201928984111561257557600080fd5b948201945b8386101561259a5761258b86612441565b8552948201949382019361257a565b96506125a99050878201612441565b9450505050509250929050565b801515811461067157600080fd5b6000602082840312156125d657600080fd5b813561159b816125b6565b600080604083850312156125f457600080fd5b82356125ff8161242c565b946020939093013593505050565b6000806040838503121561262057600080fd5b823561262b8161242c565b9150602083013561263b816125b6565b809150509250929050565b60006020808352835180602085015260005b8181101561267457858101830151858201604001528201612658565b506000604082860101526040601f19601f8301168501019250505092915050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561067f5761067f612695565b8082018082111561067f5761067f612695565b6000602082840312156126e357600080fd5b815161159b8161242c565b808202811582820484141761067f5761067f612695565b60008261272257634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561273957600080fd5b815161159b816125b6565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561278557600080fd5b505191905056fe22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bda26469706673582212206f25c454bd01e796e628a65df9d6c48265ee123b26df9cf95ec4cfa71a5163a164736f6c63430008170033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102ac5760003560e01c806368321eb7116101735780639d0bcca0116100d45780639d0bcca01461055f578063b1bc419514610567578063b429afeb1461056f578063bcb384fa14610582578063c3dfdae614610595578063c81529c61461059d578063d11d1861146105b0578063dee1f0e4146105ba578063e4ce0871146105cd578063f0f44260146105e0578063f2c7b2eb146105f3578063f6914cfa14610606578063f77c479114610619578063ffa1ad741461062157600080fd5b806368321eb71461044e578063683fedf7146104815780637262bb2d146104895780637405bab81461049c5780637adbf973146104af5780637c000293146104c25780637c66b452146104d55780637cc96380146104e85780637dc0d1d0146104f05780638070c503146104f857806380d29e6614610500578063822f804c1461051357806389dd9f1314610526578063936725ec1461052e57600080fd5b8063359a7d8f1161021d578063359a7d8f1461037b578063361e4b271461038e5780633c8f1bbe146103a15780634453bd89146103b45780634576dc52146103c75780634593144c146103da578063490fb76a146103e25780634fac6ccd146103ea57806350c358a4146103fd578063524a562f146104105780635aa6e675146104185780635d4fead314610420578063605918ae1461043357806361d027b31461044657600080fd5b80628e9691146102b1578063016dff5d146102cf5780630359fea9146102d757806308ac0fd7146102df57806311b0aebe146102f457806318d928311461031557806319ab453c1461032d5780631ec4760014610340578063238efcbc1461035357806325eb1c871461035b5780632f91ede91461036357806331423c261461036b578063325a19f114610373575b600080fd5b6102b9610645565b6040516102c69190612418565b60405180910390f35b6102b9610654565b6102b961065e565b6102f26102ed366004612451565b610668565b005b61030761030236600461246e565b610674565b6040519081526020016102c6565b61031d610685565b60405190151581526020016102c6565b6102f261033b366004612451565b61068f565b6102f261034e366004612451565b6107b2565b6102f26107bb565b6102b96107c5565b6102b96107cf565b6102b96107d9565b6103076107e3565b6102f2610389366004612451565b610817565b6102f261039c366004612451565b610820565b6102f26103af366004612487565b610829565b6102f26103c2366004612451565b61083a565b6102f26103d53660046124df565b610843565b610307610851565b6102b9610881565b6102f26103f8366004612451565b61088b565b61031d61040b366004612451565b61099d565b6102b96109a8565b6102b96109b2565b6102f261042e3660046125c4565b6109bc565b6102f2610441366004612451565b6109c5565b6102b96109ce565b61046161045c3660046125e1565b6109d8565b6040805194855260208501939093529183015260608201526080016102c6565b6102b9610a5a565b6102f261049736600461260d565b610a64565b6102f26104aa366004612451565b610a6e565b6102f26104bd366004612451565b610a77565b6102f26104d0366004612451565b610a80565b61031d6104e3366004612451565b610a89565b610307610a94565b6102b9610ab2565b6102b9610abc565b6102f261050e366004612451565b610ac6565b6102f2610521366004612451565b610acf565b6102b9610ad8565b610552604051806040016040528060058152602001640312e302e360dc1b81525081565b6040516102c69190612646565b6102b9610ae2565b610307610b12565b61031d61057d366004612451565b610b1c565b6102f2610590366004612451565b610b41565b6102b9610b4a565b6102f26105ab366004612451565b610b54565b61030762093a8081565b61031d6105c8366004612451565b610b5d565b6102f26105db366004612451565b610be2565b6102f26105ee366004612451565b610beb565b6102f261060136600461246e565b610bf4565b6102f261061436600461260d565b610bfd565b6102b9610c07565b61055260405180604001604052806005815260200164312e302e3360d81b81525081565b600061064f610c37565b905090565b600061064f610c53565b600061064f610c6f565b61067181610c8b565b50565b600061067f82610d1f565b92915050565b600061064f610d5c565b6000610699610d72565b805490915060ff600160401b820416159067ffffffffffffffff166000811580156106c15750825b905060008267ffffffffffffffff1660011480156106de5750303b155b9050811580156106ec575080155b1561070a5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561073457845460ff60401b1916600160401b1785555b61073d30610d96565b85610746610da7565b80546001600160a01b0319166001600160a01b039290921691909117905583156107aa57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b61067181610dcb565b6107c3610e2d565b565b600061064f610edd565b600061064f610ef9565b600061064f610f15565b600061064f61081360017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b6126ab565b5490565b61067181610f31565b61067181610fbf565b61083530848484611048565b505050565b610671816113b0565b61084d8282611439565b5050565b600061064f61081360017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f16126ab565b600061064f611533565b3330146108dd5760405162461bcd60e51b815260206004820152601b60248201527a24b731b932b0b9b2903932bb34b9b4b7b7103337b93134b23232b760291b60448201526064015b60405180910390fd5b60006108fb610813600160008051602061278d8339815191526126ab565b6109069060016126be565b905061092881610925600160008051602061278d8339815191526126ab565b55565b6109578261092560017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e46126ab565b604080518281526001600160a01b03841660208201527ff27e2ef832a4eb8ed8ec553b875eecd44764cda95b1c24170e281539e0a869c891015b60405180910390a15050565b600061067f82611554565b600061064f6115a2565b600061064f6115be565b610671816115d7565b610671816115fd565b600061064f611686565b600080600080610a4a8686306001600160a01b031663c3dfdae66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4591906126d1565b6116a2565b9299919850965090945092505050565b600061064f61174f565b61084d828261176b565b610671816117d8565b61067181611861565b610671816118ea565b600061067f82611973565b600061064f610813600160008051602061278d8339815191526126ab565b600061064f6119a2565b600061064f6119be565b610671816119da565b61067181611a63565b600061064f611aec565b600061064f61081360017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e46126ab565b600061064f611b08565b6000610b26610c07565b6001600160a01b0316826001600160a01b0316149050919050565b61067181611b2e565b600061064f611c67565b61067181611c83565b6000816001600160a01b0316610b71610c07565b6001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd291906126d1565b6001600160a01b03161492915050565b61067181611d0c565b61067181611d95565b61067181611e1e565b61084d8282611e84565b600061064f61081360017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c36186126ab565b6000610c41610da7565b600201546001600160a01b0316919050565b6000610c5d610da7565b600a01546001600160a01b0316919050565b6000610c79610da7565b601101546001600160a01b0316919050565b610c93611efc565b6001600160a01b038116610cba5760405163d92e233d60e01b815260040160405180910390fd5b80610cc3610da7565b60060180546001600160a01b0319166001600160a01b03929092169190911790556040517f5d77c617926cd1f4106de1bae23b2eb1a9d6e84911f701858a0b1d831e92816590610d14908390612418565b60405180910390a150565b600061067f6a084595161401484a000000610d4368056bc75e2d63100000856126ee565b610d4d9190612705565b68056bc75e2d63100000611f24565b6000610d66610da7565b600e015460ff16919050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0090565b610d9e611f3a565b61067181611f5f565b7f4d96152d518acf5697a667aeb82f27b3218b679995afa077296a84fdcb65bb0090565b610dd3611efc565b80610ddc610da7565b60010180546001600160a01b0319166001600160a01b03929092169190911790556040517f93a15bbe6d7cb67fff86738ed92efd14e9fe04e7d30042086570034a2f2eb3c290610d14908390612418565b33610e36610da7565b600101546001600160a01b031614610e63573360405163ba18f1e160e01b81526004016108d49190612418565b33610e6c610da7565b80546001600160a01b0319166001600160a01b0392909216919091179055610e92610da7565b60010180546001600160a01b03191690556040517fb1476cf38ac36ee528f1ad1ae81bdb46de8807d42475e16078426bce6001396190610ed3903390612418565b60405180910390a1565b6000610ee7610da7565b600f01546001600160a01b0316919050565b6000610f03610da7565b600801546001600160a01b0316919050565b6000610f1f610da7565b600901546001600160a01b0316919050565b610f39611efc565b6001600160a01b038116610f605760405163d92e233d60e01b815260040160405180910390fd5b80610f69610da7565b600e0160016101000a8154816001600160a01b0302191690836001600160a01b031602179055507fd86fc86ebea7a7d81c1a9fa7e0977cdafcfccf0cc35295a095231a7b28274e4981604051610d149190612418565b610fc7611efc565b6001600160a01b038116610fee5760405163d92e233d60e01b815260040160405180910390fd5b80610ff7610da7565b60030180546001600160a01b0319166001600160a01b03929092169190911790556040517fecbc0f0d903f1b9964d257a8043a5ecdf9c55a8e3d0060fb920b40c4009a257d90610d14908390612418565b6110518461207c565b60008060008061109a87878a6001600160a01b031663c3dfdae66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a21573d6000803e3d6000fd5b6040516323b872dd60e01b81526001600160a01b038a81166004830152306024830152604482018c90529498509296509094509250908816906323b872dd906064016020604051808303816000875af11580156110fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111f9190612727565b5080156111fa57866001600160a01b031663a9059cbb896001600160a01b0316630359fea96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611173573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119791906126d1565b836040518363ffffffff1660e01b81526004016111b5929190612744565b6020604051808303816000875af11580156111d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f89190612727565b505b82156112d457866001600160a01b031663a9059cbb896001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561124d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127191906126d1565b856040518363ffffffff1660e01b815260040161128f929190612744565b6020604051808303816000875af11580156112ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d29190612727565b505b831561134757604051630852cd8d60e31b8152600481018590526001600160a01b038816906342966c68906024016020604051808303816000875af1158015611321573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113459190612727565b505b604080516001600160a01b03898116825260208201899052871681830152606081018690526080810185905260a0810184905290517f1fd334c200f7b34cefbcb9762981e99dea5bdff9c149c5e4a279a1f55e8c97729181900360c00190a15050505050505050565b6113b8611efc565b6001600160a01b0381166113df5760405163d92e233d60e01b815260040160405180910390fd5b806113e8610da7565b600f0180546001600160a01b0319166001600160a01b03929092169190911790556040517f0d1f076dd618d44fc1ed0ae909dcb5a875262080a1fb3386f155e47003323ed790610d14908390612418565b61144161238c565b60005b82518110156108355782818151811061145f5761145f61275d565b60200260200101516001600160a01b0316630900f010836040518263ffffffff1660e01b81526004016114929190612418565b600060405180830381600087803b1580156114ac57600080fd5b505af11580156114c0573d6000803e3d6000fd5b505050507fd32d24edea94f55e932d9a008afc425a8561462d1b1f57bc6e508e9a6b9509e18382815181106114f7576114f761275d565b6020026020010151836040516115239291906001600160a01b0392831681529116602082015260400190565b60405180910390a1600101611444565b600061153d610da7565b600e015461010090046001600160a01b0316919050565b60008061155f610da7565b6001600160a01b0384166000908152600d9190910160205260409020549050801580159061158c57508042105b8061159b575061159b836123b4565b9392505050565b60006115ac610da7565b600301546001600160a01b0316919050565b60006115c8610da7565b546001600160a01b0316919050565b6115df61238c565b806115e8610da7565b600e01805460ff191691151591909117905550565b611605611efc565b6001600160a01b03811661162c5760405163d92e233d60e01b815260040160405180910390fd5b80611635610da7565b60020180546001600160a01b0319166001600160a01b03929092169190911790556040517f573b0be2ffc8c66825968c4e3b38a0af5edb18ce20f9a516e0f8a04867d2638990610d14908390612418565b6000611690610da7565b600501546001600160a01b0316919050565b600080600080846001600160a01b0316876001600160a01b0316036116f55760026116cd85886126ab565b6116d79190612705565b9250826116e485886126ab565b6116ee91906126ab565b9150611746565b620186a061170662013880886126ee565b6117109190612705565b9050620186a0611722612710886126ee565b61172c9190612705565b92508261173982886126ab565b61174391906126ab565b91505b93509350935093565b6000611759610da7565b600601546001600160a01b0316919050565b611773611efc565b80156117a257611781610da7565b6001600160a01b0383166000908152600d9190910160205260408120555050565b6117af62093a80426126be565b6117b7610da7565b6001600160a01b0384166000908152600d9190910160205260409020555050565b6117e0611efc565b6001600160a01b0381166118075760405163d92e233d60e01b815260040160405180910390fd5b80611810610da7565b60090180546001600160a01b0319166001600160a01b03929092169190911790556040517fedcd6ea89a41d21f1bafa9a7cc32e754079d18642839a1a48c938447d2a740eb90610d14908390612418565b611869611efc565b6001600160a01b0381166118905760405163d92e233d60e01b815260040160405180910390fd5b80611899610da7565b60040180546001600160a01b0319166001600160a01b03929092169190911790556040517f0e05ae75e8b926552cf6fcd744d19f422561e3ced1e426868730852702dbe41890610d14908390612418565b6118f2611efc565b6001600160a01b0381166119195760405163d92e233d60e01b815260040160405180910390fd5b80611922610da7565b60110180546001600160a01b0319166001600160a01b03929092169190911790556040517f657bb19de5473f7be7de9ccbcfa6d9aabcb3cfd199aef85e949a1d8570c290ab90610d14908390612418565b600061197d610da7565b6001600160a01b039092166000908152600c9290920160205250604090205460ff1690565b60006119ac610da7565b600401546001600160a01b0316919050565b60006119c8610da7565b600101546001600160a01b0316919050565b6119e2611efc565b6001600160a01b038116611a095760405163d92e233d60e01b815260040160405180910390fd5b80611a12610da7565b600b0180546001600160a01b0319166001600160a01b03929092169190911790556040517f035bee136adcafe288762d810fef741bc236d20bb1b469acb4c23e5357f0856790610d14908390612418565b611a6b611efc565b6001600160a01b038116611a925760405163d92e233d60e01b815260040160405180910390fd5b80611a9b610da7565b60070180546001600160a01b0319166001600160a01b03929092169190911790556040517ffa195fffb4bf4e5339e2e98fb090f0d634c64261640c07c1ee6ee43d5f23516190610d14908390612418565b6000611af6610da7565b600701546001600160a01b0316919050565b6000611b12610da7565b60100154905080600003611b2b5750678ac7230489e800005b90565b611b36611efc565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190611b65903090600401612418565b602060405180830381865afa158015611b82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba69190612773565b9050801561084d57816001600160a01b031663a9059cbb611bc5610da7565b546040516001600160e01b031960e084901b168152611bf2916001600160a01b0316908590600401612744565b6020604051808303816000875af1158015611c11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c359190612727565b507fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a8282604051610991929190612744565b6000611c71610da7565b600b01546001600160a01b0316919050565b611c8b611efc565b6001600160a01b038116611cb25760405163d92e233d60e01b815260040160405180910390fd5b80611cbb610da7565b600a0180546001600160a01b0319166001600160a01b03929092169190911790556040517fd1e9a4ae1231531a757f1e31a2ff8a1db9d359a194436efe40bccb972cde86f090610d14908390612418565b611d14611efc565b6001600160a01b038116611d3b5760405163d92e233d60e01b815260040160405180910390fd5b80611d44610da7565b60080180546001600160a01b0319166001600160a01b03929092169190911790556040517f29fdde0e067ae34f44ca706fd84ea4b9dabb69557e7e935d379c932ba023b2be90610d14908390612418565b611d9d611efc565b6001600160a01b038116611dc45760405163d92e233d60e01b815260040160405180910390fd5b80611dcd610da7565b60050180546001600160a01b0319166001600160a01b03929092169190911790556040517fc714d22a2f08b695f81e7c707058db484aa5b4d6b4c9fd64beb10fe85832f60890610d14908390612418565b611e26611efc565b80600003611e4757604051631f2a200560e01b815260040160405180910390fd5b80611e50610da7565b601001556040518181527f867c590cfc1b2ba6732d5d876a96733ad5cde9c836a978d6107517c00cf3f44590602001610d14565b611e8c611efc565b80611e95610da7565b6001600160a01b0384166000818152600c929092016020908152604092839020805460ff1916941515949094179093558151908152831515928101929092527f0de9c5667496fd561ff9dfa59efdc1c76f7dbf3844adae3d14a3a14d563321b19101610991565b611f05336123b4565b6107c3573360405163988d1f0360e01b81526004016108d49190612418565b6000818310611f33578161159b565b5090919050565b611f426123fe565b6107c357604051631afcd79f60e31b815260040160405180910390fd5b6001600160a01b038116611fa75760405162461bcd60e51b815260206004820152600f60248201526e2d32b9379031b7b73a3937b63632b960891b60448201526064016108d4565b611fd68161092560017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c36186126ab565b6120054261092560017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b6126ab565b6120344361092560017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f16126ab565b604080516001600160a01b038316815242602082015243918101919091527f1a2dd071001ebf6e03174e3df5b305795a4ad5d41d8fdb9ba41dbbe23671342690606001610d14565b336001600160a01b0316816001600160a01b031663016dff5d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e891906126d1565b6001600160a01b0316141580156121725750336001600160a01b0316816001600160a01b031663490fb76a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612142573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216691906126d1565b6001600160a01b031614155b80156121f15750336001600160a01b0316816001600160a01b03166325eb1c876040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e591906126d1565b6001600160a01b031614155b80156122705750336001600160a01b0316816001600160a01b0316632f91ede96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612240573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226491906126d1565b6001600160a01b031614155b80156122ef5750336001600160a01b0316816001600160a01b03166331423c266040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e391906126d1565b6001600160a01b031614155b801561236e5750336001600160a01b0316816001600160a01b031663524a562f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561233e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236291906126d1565b6001600160a01b031614155b156106715760405163f20e063760e01b815260040160405180910390fd5b61239533611554565b6107c3573360405163451cea1760e11b81526004016108d49190612418565b6000816001600160a01b0316306001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bae573d6000803e3d6000fd5b6000612408610d72565b54600160401b900460ff16919050565b6001600160a01b0391909116815260200190565b6001600160a01b038116811461067157600080fd5b803561244c8161242c565b919050565b60006020828403121561246357600080fd5b813561159b8161242c565b60006020828403121561248057600080fd5b5035919050565b60008060006060848603121561249c57600080fd5b83356124a78161242c565b92506020840135915060408401356124be8161242c565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156124f257600080fd5b823567ffffffffffffffff8082111561250a57600080fd5b818501915085601f83011261251e57600080fd5b8135602082821115612532576125326124c9565b8160051b604051601f19603f83011681018181108682111715612557576125576124c9565b60405292835281830193508481018201928984111561257557600080fd5b948201945b8386101561259a5761258b86612441565b8552948201949382019361257a565b96506125a99050878201612441565b9450505050509250929050565b801515811461067157600080fd5b6000602082840312156125d657600080fd5b813561159b816125b6565b600080604083850312156125f457600080fd5b82356125ff8161242c565b946020939093013593505050565b6000806040838503121561262057600080fd5b823561262b8161242c565b9150602083013561263b816125b6565b809150509250929050565b60006020808352835180602085015260005b8181101561267457858101830151858201604001528201612658565b506000604082860101526040601f19601f8301168501019250505092915050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561067f5761067f612695565b8082018082111561067f5761067f612695565b6000602082840312156126e357600080fd5b815161159b8161242c565b808202811582820484141761067f5761067f612695565b60008261272257634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561273957600080fd5b815161159b816125b6565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561278557600080fd5b505191905056fe22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bda26469706673582212206f25c454bd01e796e628a65df9d6c48265ee123b26df9cf95ec4cfa71a5163a164736f6c63430008170033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.