Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
SnuggeryManager
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 2000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "openzeppelin-contracts/contracts/token/ERC721/IERC721.sol";
import "../interfaces/IAccountManager.sol";
import "../interfaces/INFTAttributesManager.sol";
import "../interfaces/IBonusManager.sol";
import "../interfaces/IRNGProxy.sol";
import "../interfaces/ISnuggeryManager.sol";
import "../interfaces/IClaimManager.sol";
import "../interfaces/IMunchNFT.sol";
import "../interfaces/INFTOverlord.sol";
import "./BaseBlastManagerUpgradeable.sol";
contract SnuggeryManager is BaseBlastManagerUpgradeable, ISnuggeryManager {
uint16 DEFAULT_SNUGGERY_SIZE;
uint16 MAX_SNUGGERY_SIZE;
uint256 PET_TOTAL_SCHNIBBLES;
uint256 NEW_SLOT_COST;
mapping(address => MunchablesCommonLib.SnuggeryNFT[]) snuggeries;
uint256 totalGlobalChonk;
mapping(address => uint256) playerChonks;
address munchNFT;
IClaimManager claimManager;
INFTAttributesManager nftAttributesManager;
IAccountManager accountManager;
IBonusManager bonusManager;
INFTOverlord nftOverlord;
modifier chonkUpdated() {
(address _player, ) = _getMainAccountRequireRegistered(msg.sender);
claimManager.forceClaimPoints(_player);
_;
_recalculateChonks(_player);
}
constructor() {
_disableInitializers();
}
function initialize(address _configStorage) public override initializer {
BaseBlastManagerUpgradeable.initialize(_configStorage);
_reconfigure();
}
function _reconfigure() internal {
// load config from the config storage contract and configure myself
accountManager = IAccountManager(
configStorage.getAddress(StorageKey.AccountManager)
);
claimManager = IClaimManager(
configStorage.getAddress(StorageKey.ClaimManager)
);
munchNFT = configStorage.getAddress(StorageKey.MunchNFT);
nftAttributesManager = INFTAttributesManager(
configStorage.getAddress(StorageKey.NFTAttributesManager)
);
bonusManager = IBonusManager(
configStorage.getAddress(StorageKey.BonusManager)
);
nftOverlord = INFTOverlord(
configStorage.getAddress(StorageKey.NFTOverlord)
);
DEFAULT_SNUGGERY_SIZE = uint16(
configStorage.getSmallInt(StorageKey.DefaultSnuggerySize)
); // 6
MAX_SNUGGERY_SIZE = uint16(
configStorage.getSmallInt(StorageKey.MaxSnuggerySize)
); // 12
PET_TOTAL_SCHNIBBLES = configStorage.getUint(
StorageKey.PetTotalSchnibbles
); // 10e18 / 72
NEW_SLOT_COST = configStorage.getUint(StorageKey.NewSlotCost); // 1000e18 = 1000 munch points
super.__BaseBlastManager_reconfigure();
}
function configUpdated() external override onlyConfigStorage {
_reconfigure();
}
/// @inheritdoc ISnuggeryManager
function importMunchable(uint256 _tokenId) external notPaused chonkUpdated {
if (_tokenId < 1) revert InvalidTokenIDError();
(
address _caller,
MunchablesCommonLib.Player memory _player
) = _getMainAccountRequireRegistered(msg.sender);
// transfer nft to contract
IERC721 erc721Token = IERC721(munchNFT);
// chech main account is actually owner
if (erc721Token.ownerOf(_tokenId) != _caller)
revert InvalidOwnerError();
// Check for approval
if (
!erc721Token.isApprovedForAll(_caller, address(this)) &&
erc721Token.getApproved(_tokenId) != address(this)
) revert NotApprovedError();
erc721Token.transferFrom(_caller, address(this), _tokenId);
// add to the snuggery
if (snuggeries[_caller].length >= _player.maxSnuggerySize)
revert SnuggeryFullError();
snuggeries[_caller].push(
MunchablesCommonLib.SnuggeryNFT(_tokenId, uint32(block.timestamp))
);
emit MunchableImported(_caller, _tokenId);
}
/// @inheritdoc ISnuggeryManager
function exportMunchable(uint256 _tokenId) external notPaused chonkUpdated {
(address _caller, ) = _getMainAccountRequireRegistered(msg.sender);
IERC721 erc721Token = IERC721(munchNFT);
// send nft back
if (erc721Token.ownerOf(_tokenId) != address(this))
revert MunchableNotInSnuggeryError();
erc721Token.transferFrom(address(this), _caller, _tokenId);
// check we have the correct token
(bool _found, uint256 _index) = _findSnuggeryIndex(_caller, _tokenId);
if (!_found) revert MunchableNotInSnuggeryError();
// remove item in snuggery
uint256 snuggeryLength = snuggeries[_caller].length;
for (uint256 i = _index; i < snuggeryLength - 1; i++) {
snuggeries[_caller][i] = snuggeries[_caller][i + 1];
}
snuggeries[_caller].pop();
emit MunchableExported(_caller, _tokenId);
}
/// @inheritdoc ISnuggeryManager
function feed(
uint256 _tokenId,
uint256 _schnibbles
) external notPaused chonkUpdated {
(
address _mainAccount,
MunchablesCommonLib.Player memory _player
) = _getMainAccountRequireRegistered(msg.sender);
if (_player.unfedSchnibbles < _schnibbles)
revert InsufficientSchnibblesError(_player.unfedSchnibbles);
// find token in snuggery
(bool found, ) = _findSnuggeryIndex(_mainAccount, _tokenId);
if (!found) revert TokenNotFoundInSnuggeryError();
int256 bonusPercent = bonusManager.getFeedBonus(_mainAccount, _tokenId);
int256 bonusSchnibbles = (int256(_schnibbles) * bonusPercent) / 1e18;
// Set new attributes
MunchablesCommonLib.NFTAttributes
memory currentAttributes = nftAttributesManager.getAttributes(
_tokenId
);
currentAttributes.chonks += uint256(
int256(_schnibbles) + bonusSchnibbles
);
nftAttributesManager.setAttributes(_tokenId, currentAttributes);
// deduct from unfed
_player.unfedSchnibbles -= _schnibbles;
accountManager.updatePlayer(_mainAccount, _player);
// notify nftOverlord
nftOverlord.munchableFed(_tokenId, _mainAccount);
emit MunchableFed(_mainAccount, _tokenId, _schnibbles, bonusSchnibbles);
}
/// @inheritdoc ISnuggeryManager
function increaseSnuggerySize(uint8 _quantity) external notPaused {
(
address _mainAccount,
MunchablesCommonLib.Player memory _player
) = _getMainAccountRequireRegistered(msg.sender);
if (NEW_SLOT_COST == 0) revert NotConfiguredError();
uint16 previousSize = _player.maxSnuggerySize;
if (previousSize >= MAX_SNUGGERY_SIZE) revert SnuggeryMaxSizeError();
uint256 pointsCost = NEW_SLOT_COST * uint256(_quantity);
claimManager.spendPoints(_mainAccount, pointsCost);
_player.maxSnuggerySize += uint16(_quantity);
accountManager.updatePlayer(_mainAccount, _player);
emit SnuggerySizeIncreased(
_mainAccount,
previousSize,
_player.maxSnuggerySize
);
}
/// @inheritdoc ISnuggeryManager
function pet(address _pettedOwner, uint256 _tokenId) external notPaused {
(
address _petterMainAccount,
MunchablesCommonLib.Player memory _petterPlayer
) = _getMainAccountRequireRegistered(msg.sender);
(
address _pettedMainAccount,
MunchablesCommonLib.Player memory _pettedPlayer
) = _getMainAccountRequireRegistered(_pettedOwner);
if (_pettedMainAccount != _pettedOwner) revert PettedIsSubAccount();
(bool _found, ) = _findSnuggeryIndex(_pettedOwner, _tokenId);
if (!_found) revert TokenNotFoundInSnuggeryError();
MunchablesCommonLib.NFTAttributes
memory pettedAttributes = nftAttributesManager.getAttributes(
_tokenId
);
if (_pettedMainAccount == _petterMainAccount)
revert CannotPetOwnError();
if (pettedAttributes.lastPettedTime + 6 hours > block.timestamp)
revert PettedTooSoonError();
if (_petterPlayer.lastPetMunchable + 1 hours > block.timestamp)
revert PetTooSoonError();
// give out total of 11 per pet, 5 to petter and 6 to petted, boosted by the petter having locked tokens
uint256 bonusPercent = bonusManager.getPetBonus(_petterMainAccount);
uint256 bonusSchnibbles = (PET_TOTAL_SCHNIBBLES * bonusPercent) / 1e18;
uint256 totalSchnibbles = PET_TOTAL_SCHNIBBLES +
uint256(bonusSchnibbles);
uint256 petterSchnibbles = ((totalSchnibbles * 5) / 11) * 1e18;
uint256 pettedSchnibbles = ((totalSchnibbles * 6) / 11) * 1e18;
_pettedPlayer.unfedSchnibbles += pettedSchnibbles;
accountManager.updatePlayer(_pettedMainAccount, _pettedPlayer);
_petterPlayer.unfedSchnibbles += petterSchnibbles;
_petterPlayer.lastPetMunchable = uint32(block.timestamp);
accountManager.updatePlayer(_petterMainAccount, _petterPlayer);
// updated petted nft attributes
pettedAttributes.lastPettedTime = uint32(block.timestamp);
nftAttributesManager.setAttributes(_tokenId, pettedAttributes);
emit MunchablePetted(
_petterMainAccount,
_pettedMainAccount,
_tokenId,
petterSchnibbles,
pettedSchnibbles
);
}
function getSnuggery(
address _account
)
external
view
returns (MunchablesCommonLib.SnuggeryNFT[] memory _snuggery)
{
(address _player, ) = accountManager.getPlayer(_account);
uint256 _snuggerySize = snuggeries[_player].length;
_snuggery = new MunchablesCommonLib.SnuggeryNFT[](_snuggerySize);
for (uint256 i = 0; i < _snuggerySize; i++) {
MunchablesCommonLib.SnuggeryNFT memory snuggeryNFT = snuggeries[
_player
][i];
_snuggery[i].tokenId = snuggeryNFT.tokenId;
_snuggery[i].importedDate = snuggeryNFT.importedDate;
}
}
/// @inheritdoc ISnuggeryManager
function getTotalChonk(
address _player
) external view returns (uint256 _totalChonk) {
MunchablesCommonLib.SnuggeryNFT[] memory snuggery = snuggeries[_player];
for (uint8 i; i < snuggery.length; i++) {
_totalChonk += nftAttributesManager
.getAttributes(snuggery[i].tokenId)
.chonks;
}
}
/// @inheritdoc ISnuggeryManager
function getGlobalTotalChonk()
external
view
returns (uint256 _totalGlobalChonk)
{
_totalGlobalChonk = totalGlobalChonk;
}
function _findSnuggeryIndex(
address _player,
uint256 _tokenId
) internal view returns (bool _found, uint256 _index) {
uint256 snuggeryLength = snuggeries[_player].length;
for (uint256 i; i < snuggeryLength; i++) {
if (_tokenId == snuggeries[_player][i].tokenId) {
_found = true;
_index = i;
break;
}
}
}
function _getMainAccountRequireRegistered(
address _account
)
internal
view
returns (
address _mainAccount,
MunchablesCommonLib.Player memory _player
)
{
(_mainAccount, _player) = accountManager.getPlayer(_account);
if (_player.registrationDate == 0) revert PlayerNotRegisteredError();
}
function _recalculateChonks(address _player) internal {
uint256 previousChonks = playerChonks[_player];
uint256 _playerChonks;
for (uint256 i; i < snuggeries[_player].length; i++) {
_playerChonks += nftAttributesManager
.getAttributes(snuggeries[_player][i].tokenId)
.chonks;
}
playerChonks[_player] = _playerChonks;
if (previousChonks != _playerChonks) {
totalGlobalChonk += _playerChonks;
totalGlobalChonk -= previousChonks;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "../libraries/MunchablesCommonLib.sol";
/// @title Interface for the Account Manager
/// @notice This interface manages player accounts including their snuggery, schibbles, chonks, and sub-accounts
interface IAccountManager {
/// @notice Struct representing a "Squirt", which is a distribution of schnibbles to a player
struct Squirt {
address player; // The address of the player receiving schnibbles
uint256 schnibbles; // The amount of schnibbles being distributed to that player
}
/// @notice Struct representing a proposal to spray schnibbles across multiple accounts
struct SprayProposal {
uint32 proposedDate; // The date the proposal was made
Squirt[] squirts; // Array of "Squirt" structs detailing the distribution
}
/// @notice Register a new account, create a new Player record, and set snuggery and referrer
/// @dev This should be the first function called when onboarding a new user
/// @param _snuggeryRealm The realm of the new snuggery, which cannot be changed later
/// @param _referrer The account referring this user, use the null address if there is no referrer
/// @custom:frontend Register a new account
function register(
MunchablesCommonLib.Realm _snuggeryRealm,
address _referrer
) external;
/// @notice Calculate schnibbles to distribute and credit to unfedSchnibbles, set lastHarvestDate
/// @custom:frontend Harvest schnibbles
function harvest() external returns (uint256 _harvested);
/// @notice Used when a user adds to their lock to force claim at the previous locked value
/// @param _player Address of the player whose harvest to force
function forceHarvest(address _player) external;
/// @notice Propose a spray of schnibbles to multiple accounts
/// @param _players Array of player addresses
/// @param _schnibbles Array of schnibbles amounts corresponding to each player
function spraySchnibblesPropose(
address[] calldata _players,
uint256[] calldata _schnibbles
) external;
/// @notice Approve a proposed spray of schnibbles
/// @param _proposer Address of the proposer of the spray
function execSprayProposal(address _proposer) external;
/// @notice Remove a proposed spray of schnibbles
/// @param _proposer Address of the proposer of the spray to remove
function removeSprayProposal(address _proposer) external;
/// @notice Add a sub-account for a player
/// @param _subAccount The sub-account to add
/// @custom:frontend Use to add a new sub-account
function addSubAccount(address _subAccount) external;
/// @notice Remove a previously added sub-account
/// @param _subAccount The sub-account to remove
/// @custom:frontend Use to remove an existing sub-account
function removeSubAccount(address _subAccount) external;
/// @notice Restricted to the Munchable Manager only
function updatePlayer(
address _account,
MunchablesCommonLib.Player memory _player
) external;
/// @notice Look up the main account associated with a potentially sub-account
/// @param _maybeSubAccount Account to check
/// @return _mainAccount Main account associated, or the input if not a sub-account
function getMainAccount(
address _maybeSubAccount
) external view returns (address _mainAccount);
/// @notice Get a list of sub-accounts associated with a main account
/// @param _player Main account to check
/// @param _start Index to start pagination
/// @return _subAccounts List of sub-accounts
/// @return _more Whether there are more sub-accounts beyond the returned list
/// @custom:frontend Use this to populate a UI for managing sub accounts
function getSubAccounts(
address _player,
uint256 _start
) external view returns (address[20] memory _subAccounts, bool _more);
/// @notice Retrieve player data for a given account
/// @param _account Account to retrieve data for
/// @return _mainAccount Main account associated, or the input if not a sub-account
/// @return _player Player data structure
/// @custom:frontend Call this straight after log in to get the data about this player. The account
/// logging in may be a sub account and in this case the _mainAccount parameter
/// will be different from the logged in user. In this case the UI should show only
/// functions available to a sub-account
function getPlayer(
address _account
)
external
view
returns (
address _mainAccount,
MunchablesCommonLib.Player memory _player
);
/// @notice Retrieve detailed player and snuggery data
/// @param _account Address of the player
/// @return _mainAccount Main account associated
/// @return _player Player data
/// @return _snuggery List of snuggery NFTs
/// @custom:frontend Use this to fetch player and snuggery data
function getFullPlayerData(
address _account
)
external
view
returns (
address _mainAccount,
MunchablesCommonLib.Player memory _player,
MunchablesCommonLib.SnuggeryNFT[] memory _snuggery
);
/// @notice Get daily schnibbles that an account is accrueing
/// @param _player The address of the player
function getDailySchnibbles(
address _player
) external view returns (uint256 _dailySchnibbles, uint256 _bonus);
/// @notice Emitted when a player registers for a new account
/// @param _player The address of the player who registered
/// @param _snuggeryRealm The realm associated with the new snuggery chosen by the player
/// @param _referrer The address of the referrer, if any; otherwise, the zero address
/// @custom:frontend You should only receive this event once and only if you are onboarding a new user
/// safe to ignore if you are in the onboarding process
event PlayerRegistered(
address indexed _player,
MunchablesCommonLib.Realm _snuggeryRealm,
address _referrer
);
/// @notice Emitted when a player's schnibbles are harvested
/// @param _player The address of the player who harvested schnibbles
/// @param _harvestedSchnibbles The total amount of schnibbles that were harvested
/// @custom:frontend Listen for events where _player is your mainAccount and update unfedSchnibbles total
event Harvested(address indexed _player, uint256 _harvestedSchnibbles);
/// @notice Emitted when a sub-account is added to a player's account
/// @param _player The address of the main account to which a sub-account was added
/// @param _subAccount The address of the sub-account that was added
/// @custom:frontend If you are managing sub accounts (ie the logged in user is not a subAccount), then use this
/// event to reload your cache of sub accounts
event SubAccountAdded(address indexed _player, address _subAccount);
/// @notice Emitted when a sub-account is removed from a player's account
/// @param _player The address of the main account from which a sub-account was removed
/// @param _subAccount The address of the sub-account that was removed
/// @custom:frontend If you are managing sub accounts (ie the logged in user is not a subAccount), then use this
/// event to reload your cache of sub accounts
event SubAccountRemoved(address indexed _player, address _subAccount);
/// @notice Emitted when a proposal to spray schnibbles is made
/// @param _proposer The address of the player who proposed the spray
/// @param _squirts An array of "Squirt" details defining the proposed schnibble distribution
/// @custom:admin
event ProposedScnibblesSpray(address indexed _proposer, Squirt[] _squirts);
/// @notice Emitted when a schnibble spray is executed for each player
/// @param _player The player receiving schnibbles
/// @param _schnibbles The amount of schnibbles received
event SchnibblesSprayed(address indexed _player, uint256 _schnibbles);
/// @notice Emitted when schnibbles are removed. This is used to reverse a schnibble spray in the case of some being improperly sent.
/// @param _player The schnibbles remove
/// @param _schnibbles The amount of schnibbles removed
event SchnibblesSprayedRemoved(
address indexed _player,
uint256 _schnibbles
);
/// @notice Emitted when a spray proposal is executed
/// @param _proposer The account which proposed the spray
event SprayProposalExecuted(address indexed _proposer);
/// @notice Emitted when a spray proposal is removed
/// @param _proposer Account that proposed the proposal
event SprayProposalRemoved(address indexed _proposer);
// Errors
/// @notice Error thrown when a player is already registered and attempts to register again
error PlayerAlreadyRegisteredError();
/// @notice Error thrown when an action is attempted that requires the player to be registered, but they are not
error PlayerNotRegisteredError();
/// @notice Error thrown when the main account of a player is not registered
error MainAccountNotRegisteredError(address _mainAccount);
/// @notice Error thrown when there are no pending reveals for a player
error NoPendingRevealError();
/// @notice Error thrown when a sub-account is already registered and an attempt is made to register it again
error SubAccountAlreadyRegisteredError();
/// @notice Error thrown when a sub-account attempts to register as a main account
error SubAccountCannotRegisterError();
/// @notice Error thrown when a spray proposal already exists and another one is attempted
error ExistingProposalError();
/// @notice Error thrown when the parameters provided to a function do not match in quantity or type
error UnMatchedParametersError();
/// @notice Error thrown when too many entries are attempted to be processed at once
error TooManyEntriesError();
/// @notice Error thrown when an expected parameter is empty
error EmptyParameterError();
/// @notice Error thrown when a realm is invalid
error InvalidRealmError();
/// @notice Error thrown when a sub-account is not registered and is tried to be removed
error SubAccountNotRegisteredError();
/// @notice Error thrown when a proposal is attempted to be executed, but none exists
error EmptyProposalError();
/// @notice Error thrown when a player attempts to refer themselves
error SelfReferralError();
/// @notice Error thrown when the same sprayer gets added twice in a proposal
error DuplicateSprayerError();
/// @notice When a user tries to create too many sub accounts (currently 5 max)
error TooManySubAccountsError();
error TooHighSprayAmountError();
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "../libraries/MunchablesCommonLib.sol";
/// @title Interface for NFT Attributes Manager V1
/// @notice This interface manages the attributes and metadata of NFTs within the Munch ecosystem.
interface INFTAttributesManager {
/// @notice Called from MunchableManager to initialise a new record
function createWithImmutable(
uint256 _tokenId,
MunchablesCommonLib.NFTImmutableAttributes memory _immutableAttributes
) external;
/// @notice Sets dynamic attributes for a specific NFT, typically called after feeding or interaction events
/// @param _tokenId The ID of the NFT
/// @param _attributes Struct of new attributes
function setAttributes(
uint256 _tokenId,
MunchablesCommonLib.NFTAttributes calldata _attributes
) external;
/// @notice Sets game attributes for a specific NFT, typically called after level up
/// @param _tokenId The ID of the NFT
/// @param _attributes Array of new game attributes
function setGameAttributes(
uint256 _tokenId,
MunchablesCommonLib.NFTGameAttribute[] calldata _attributes
) external;
/// @notice Retrieves all data associated with an NFT in a single call
/// @param _tokenId The ID of the NFT
/// @return _nftData A struct containing all attributes (dynamic, immutable, and game-specific)
// function getFullNFTData(
// uint256 _tokenId
// ) external view returns (NFTFull memory _nftData);
/// @notice Retrieves dynamic attributes for a specific token
/// @param _tokenId The ID of the NFT
/// @return _attributes Struct of the NFT's dynamic attributes
function getAttributes(
uint256 _tokenId
)
external
view
returns (MunchablesCommonLib.NFTAttributes memory _attributes);
/// @notice Retrieves immutable attributes for a specific token
/// @param _tokenId The ID of the NFT
/// @return _immutableAttributes Struct of the NFT's immutable attributes
function getImmutableAttributes(
uint256 _tokenId
)
external
view
returns (
MunchablesCommonLib.NFTImmutableAttributes
memory _immutableAttributes
);
/// @notice Retrieves game-specific attributes for a specific token
/// @param _tokenId The ID of the NFT
/// @param _requestedIndexes Array of GameAttributeIndex to define subset of attributes to include in the result
/// @return _gameAttributes Struct of the NFT's game attributes
function getGameAttributes(
uint256 _tokenId,
MunchablesCommonLib.GameAttributeIndex[] calldata _requestedIndexes
)
external
view
returns (MunchablesCommonLib.NFTGameAttribute[] memory _gameAttributes);
function getGameAttributeDataType(
uint8 _index
) external pure returns (MunchablesCommonLib.GameAttributeType _dataType);
event CreatedWithImmutable(
uint256 _tokenId,
MunchablesCommonLib.NFTImmutableAttributes _immutableAttributes
);
/// @notice Event emitted when NFT attributes are updated
event AttributesUpdated(uint256 indexed _tokenId);
/// @notice Event emitted when NFT game attributes are updated
event GameAttributesUpdated(uint256 indexed _tokenId);
/// @notice Error when the owner of the NFT does not match the expected address
error IncorrectOwnerError();
/// @notice Error when the 'from' level specified is invalid
error InvalidLevelFromError();
/// @notice Error when the oracle recovering the signature is invalid
/// @param _recoveredSigner The address of the invalid signer
error InvalidOracleError(address _recoveredSigner);
/// @notice Error when a call is made by a non-authorized migration manager
error NotAuthorizedMigrationManagerError();
/// @notice When user tries to set attributes when the record hasnt been created
error NotCreatedError();
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
/// @title Interface for the Bonus Manager
/// @notice This interface defines the functions that the Bonus Manager contract should implement. Each function is a getter responsible for returning a percentage multiplier
interface IBonusManager {
function getFeedBonus(
address _caller,
uint256 _tokenId
) external view returns (int256 _amount);
function getHarvestBonus(
address _caller
) external view returns (uint256 _amount);
function getPetBonus(
address _petter
) external view returns (uint256 _amount);
function getReferralBonus() external view returns (uint256 _amount);
error InvalidRarityError(uint256 _rarity);
error InvalidRealmBonus(uint256 _realmIndex);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
interface IRNGProxy {
/// @notice Request a random number to be provided back to the contract specified
/// @param _contract The contract that will receive the data
/// @param _selector The function on the contract to call
/// @param _index A unique identifier which the contract can use to identify the target for the data
function requestRandom(
address _contract,
bytes4 _selector,
uint256 _index
) external;
event RandomRequested(
address indexed _target,
bytes4 _selector,
uint256 indexed _index
);
event RandomRequestComplete(
uint256 indexed _index,
bool _success,
bytes _data
);
error NoRequestError();
error CallbackFailedError();
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "../libraries/MunchablesCommonLib.sol";
/// @title Interface for the Account Manager
/// @notice This interface manages player accounts including their snuggery, schibbles, chonks, and sub-accounts
interface ISnuggeryManager {
/// @notice Imports a munchable to the player's snuggery
/// @dev Check that the NFT is approved to transfer by this contract
/// @param _tokenId The token ID to import
/// @custom:frontend Import a munchable
function importMunchable(uint256 _tokenId) external;
/// @notice Exports a munchable from the player's snuggery, the munchable will be returned directly
/// @param _tokenId The token ID to export
/// @custom:frontend Export a munchable
function exportMunchable(uint256 _tokenId) external;
/// @notice Feed a munchable to increase its chonks, chonks will be schnibbles multiplied by any feed bonus
/// @param _tokenId Token ID of the munchable to feed
/// @param _schnibbles Amount of schnibbles to feed
/// @custom:frontend Feed a munchable, use event data to show how much chonk was added
function feed(uint256 _tokenId, uint256 _schnibbles) external;
/// @notice Increase the number of slots in a player's snuggery
/// @param _quantity Quantity to increase the snuggery size by
function increaseSnuggerySize(uint8 _quantity) external;
/// @notice Pet another player's munchable to give both petter and petted some schnibbles
/// @param _pettedOwner The owner of the token being petted (the token must be in that player's snuggery)
/// @param _tokenId Token ID of the munchable to pet
/// @custom:frontend Pet another user's munchable. Check last pet and petted times to see if this function
/// should be available
function pet(address _pettedOwner, uint256 _tokenId) external;
/// @notice Retrieve the total schnibbles count for a player's snuggery
/// @param _player Address of the player
/// @return _totalChonk Total schnibbles count
function getTotalChonk(
address _player
) external view returns (uint256 _totalChonk);
/// @notice Retrieve the global total schnibbles count across all snuggeries
function getGlobalTotalChonk()
external
view
returns (uint256 _totalGlobalChonk);
/// @notice Gets a snuggery (array of SnuggeryNFT)
/// @param _player Address of the player to get snuggery for
/// @return _snuggery Array of SnuggeryNFT items
function getSnuggery(
address _player
)
external
view
returns (MunchablesCommonLib.SnuggeryNFT[] memory _snuggery);
/// @notice Emitted when a munchable is imported into a player's snuggery
/// @param _player The address of the player who imported the munchable
/// @param _tokenId The token ID of the munchable that was imported
/// @custom:frontend Listen for events for the mainAccount, when it is received update your snuggery data
event MunchableImported(address indexed _player, uint256 _tokenId);
/// @notice Emitted when a munchable is exported from a player's snuggery
/// @param _player The address of the player who exported the munchable
/// @param _tokenId The token ID of the munchable that was exported
/// @custom:frontend Listen for events for the mainAccount, when it is received update your snuggery data
event MunchableExported(address indexed _player, uint256 _tokenId);
/// @notice Emitted when a munchable is fed schnibbles
/// @param _player The address of the player who fed the munchable
/// @param _tokenId The token ID of the munchable that was fed
/// @param _baseChonks The base amount of chonks that were gained by feeding, will be equal to the schnibbles fed
/// @param _bonusChonks The additional bonus chonks that were awarded during the feeding
/// @custom:frontend Listen for events for your mainAccount and when this is received update the particular token
/// in the snuggery by reloading the NFT data
event MunchableFed(
address indexed _player,
uint256 _tokenId,
uint256 _baseChonks,
int256 _bonusChonks
);
/// @notice Emitted when a munchable is petted, distributing schnibbles to both the petter and the petted
/// @param _petter The address of the player who petted the munchable
/// @param _petted The address of the player who owns the petted munchable
/// @param _tokenId The token ID of the munchable that was petted
/// @param _petterSchnibbles The amount of schnibbles awarded to the petter
/// @param _pettedSchnibbles The amount of schnibbles awarded to the owner of the petted munchable
/// @custom:frontend Listen for events where your mainAccount petted and where it was pet
/// - If your mainAccount was petted, update the unfedMunchables total
/// - If your account was petted then, update the unfedMunchables total, also optionally load the
/// lastPetTime for the munchable if you use that
event MunchablePetted(
address indexed _petter,
address indexed _petted,
uint256 _tokenId,
uint256 _petterSchnibbles,
uint256 _pettedSchnibbles
);
/// @notice Event emitted when a snuggery size is increased
event SnuggerySizeIncreased(
address _player,
uint16 _previousSize,
uint16 _newSize
);
/// @notice Error thrown when a token ID is not found in the snuggery
error TokenNotFoundInSnuggeryError();
/// @notice Error thrown when a player's snuggery is already full and cannot accept more munchables
error SnuggeryFullError();
/// @notice Someone tries to import a munchable they do not own
error IncorrectOwnerError();
/// @notice Error if user tries to import someone else's NFT
error InvalidOwnerError();
/// @notice Error thrown when an action is attempted that requires the player to be registered, but they are not
error PlayerNotRegisteredError();
/// @notice Error thrown when a munchable is not found in a player's snuggery
error MunchableNotInSnuggeryError();
/// @notice Error thrown when a player attempts to pet their own munchable
error CannotPetOwnError();
/// @notice Error thrown when a munchable is petted too soon after the last petting
error PettedTooSoonError();
/// @notice Error thrown when a player attempts to pet too soon after their last petting action
error PetTooSoonError();
/// @notice Error thrown when a player tries to feed a munchable but does not have enough schnibbles
/// @param _currentUnfedSchnibbles The current amount of unfed schnibbles available to the player
error InsufficientSchnibblesError(uint256 _currentUnfedSchnibbles);
/// @notice Error thrown when a player attempts swap a primordial but they dont have one
error NoPrimordialInSnuggeryError();
/// @notice Invalid token id passed (normally if 0)
error InvalidTokenIDError();
/// @notice Contract is not approved to transfer NFT on behalf of user
error NotApprovedError();
/// @notice Something not configured
error NotConfiguredError();
/// @notice This is thrown by the claim manager but we need it here to decode selector
error NotEnoughPointsError();
/// @notice When petting the user petting must supply the main account being petted
error PettedIsSubAccount();
/// @notice Player tries to increase their snuggery size beyond global max size
error SnuggeryMaxSizeError();
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "../libraries/MunchablesCommonLib.sol";
interface IClaimManager {
struct Period {
uint32 id;
uint32 startTime;
uint32 endTime;
uint256 available;
uint256 claimed;
uint256 globalTotalChonk;
}
/// @notice Starts a new periods
/// @dev This will start a new period if the previous one has ended
function newPeriod() external; // onlyRole(NEW_PERIOD_ROLE)
/// @notice Claims points for the current period
/// @dev This will claim the sender's points for the current period
function claimPoints() external; // onlyValidPeriod
/// @notice Used by the account manager to force a claim before doing anything which would affect the total chonks
/// for the player
function forceClaimPoints(address _player) external; // onlyValidPeriod only SnuggeryManager.sol
/// @notice Spends points for the _player
/// @dev This will spend the _player's points
/// @param _player The player to spend the points for
/// @param _spendPoints The number of points to spend
function spendPoints(address _player, uint256 _spendPoints) external; // only SnuggeryManager.sol
/// @notice Convert accumulated points to tokens
/// @dev This will convert the sender's accumulated points to tokens
/// @param _points The number of points to convert
function convertPointsToTokens(uint256 _points) external; // onlySwapEnabled
// @notice If the player chooses to not migrate over their NFTs, they can burn them for points
/// @dev This will burn the player's NFTs for points. Can only be called by Migration Manager
/// @param _player The player to burn the NFTs for
/// @param _tokenIdsByRarity List of token IDs separated by rarity
function burnNFTsForPoints(
address _player,
uint8[] memory _tokenIdsByRarity
) external returns (uint256 _receivedPoints); // OnlyMigrationManager
/// @notice Called by MigrationManager to give the player points from their unrevealed NFTs
/// @param _player The address of the player
/// @param _unrevealed Number of unrevealed NFTs which are being swapped
function burnUnrevealedForPoints(
address _player,
uint256 _unrevealed
) external returns (uint256 _receivedPoints); // OnlyMigrationManager
/// @notice Gets the current period data
/// @return _period The current period data
function getCurrentPeriod() external view returns (Period memory _period);
/// @notice Gets the current points for a player
/// @param _player The player to get the points for
function getPoints(address _player) external view returns (uint256 _points);
event Claimed(
address indexed _sender,
address indexed _player,
uint32 _periodId,
uint256 _pointsClaimed,
address indexed _referrer,
uint256 _referralBonus
);
event PointsPerPeriodSet(uint256 _oldPoints, uint256 _newPoints);
event AccountManagerSet(
address _oldAccountManager,
address _newAccountManager
);
event LockManagerSet(address _oldLockManager, address _newLockManager);
event NewPeriodStarted(
uint32 _periodId,
uint32 _startTime,
uint32 _endTime,
uint256 _availablePoints,
uint256 _prevPeriodPointsClaimed,
uint256 _excessPoints,
uint256 _totalGlobalChonk
);
event ClaimModuleSet(address _claimModule, bool _isValid);
event YieldClaimed(
address _claimModule,
address _tokenContract,
uint256 _yieldClaimed
);
event SwapEnabled(bool _enabled);
event PointsPerTokenSet(
uint256 _oldPointsPerToken,
uint256 _newPointsPerToken
);
event MunchTokenSet(address _oldMunchToken, address _newMunchToken);
event PointsConverted(
address indexed _player,
uint256 _points,
uint256 _tokens
);
event ReferralBonusSet(uint256 _oldReferralBonus, uint256 _referralBonus);
event PointsSpent(address indexed _player, uint256 _pointsSpent);
event NFTsBurnedForPoints(
address indexed _player,
uint8[] _tokenIdsByRarity,
uint256 _points
);
event UnrevealedSwappedForPoints(
address indexed _player,
uint256 _unrevealed,
uint256 _points
);
event ClaimPeriodHit(
address indexed _player,
uint32 _lastClaimPeriod,
uint32 _currentPeriod
);
error InvalidSnapshotDataError();
error SnapshotIsFinalizedError();
error SnapshotIsNotFinalizedError();
error NotAccountManagerError();
error InvalidPeriodError(uint32 _now, uint32 _startTime, uint32 _endTime);
error CurrentPeriodNotEndedError();
error AlreadyClaimedError();
error NoClaimablePointsError();
error NotEnoughPointsError();
error SwapDisabledError();
error PointsPerTokenNotSetError();
error NoSnapshotDataError();
error PointAmountToSmallError();
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
interface IMunchNFT {
/// @notice Get the next token ID
/// @return The next token ID
function nextTokenId() external view returns (uint256);
/// @notice Mint a new, empty token. Restrict access to only the NFTOverlord
/// @param _owner The owner of the newly minted NFT
function mint(address _owner) external returns (uint256 _tokenId);
/// @notice Update the token URL, restricted to off-chain role
/// @param _tokenId The token ID to update
/// @param _tokenURI The new URI, will be an IPFS hash
function setTokenURI(uint256 _tokenId, string memory _tokenURI) external;
/// @notice Blacklist an account from transferring tokens
/// @param _account The account to blacklist
function blAccount(address _account) external;
/// @notice Blacklist an token from being transferred
/// @param _tokenId The token ID to blacklist
function blToken(uint256 _tokenId) external;
/// @notice Remove blacklist for an account
/// @param _account The account to remove from the blacklist
function removeBlAccount(address _account) external;
/// @notice Remove blacklist on a token
/// @param _tokenId The token ID to remove from the blacklist
function removeBlToken(uint256 _tokenId) external;
/// @notice Error when a blacklisted account/token tries to transfer
error ForbiddenTransferError();
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "../libraries/MunchablesCommonLib.sol";
/// @title Interface for the NFT Overlord
/// @notice This interface manages NFT minting and level up functions which rely on the RNGProxy. The implementation
/// contract will also handle notification from the LockManager contract when a player has earned
interface INFTOverlord {
/// @notice Stored between level up requests for a specific token id
struct LevelUpRequest {
address owner;
uint256 tokenId;
uint16 fromLevel;
uint16 toLevel;
}
/// @notice Struct to define mint probabilities based on percentage and species array
struct MintProbability {
uint32 percentage; // Probability percentage
uint8[] species; // Array of species IDs that can be minted under this probability
}
/// @notice Deduct one from Player.unrevealedNFTs and add one to AccountManager.revealQueue
/// @custom:frontend Use to reveal an NFT, listen for the events to see when it was minted
function startReveal() external;
/// @notice Add to Player.unrevealedNFTs, function only callable by lock manager
/// @param _player Address of the player
/// @param _quantity Quantity of reveals to add
function addReveal(address _player, uint16 _quantity) external;
/// @notice Reveals an NFT based on provided player ID and signature, decrementing the reveal queue
/// @param _player The player ID for whom the NFT will be revealed
/// @param _signature The signature to validate the reveal process
/// @return _tokenId The ID of the minted NFT
/// @dev This function should be called after RNG process
function reveal(
uint256 _player,
bytes memory _signature
) external returns (uint256 _tokenId);
/// @notice Called by PrimordialManager when a primordial has reached level 0 and can be hatched into a Munchable
/// @param _player The player address
function mintFromPrimordial(address _player) external; // only PrimordialManager
/// @notice Reveals an NFT based on provided player ID and signature, this is from a primordial hatching
/// @param _player The player ID whom the NFT will be revealed
/// @param _signature The signature to validate the reveal process
/// @return _tokenId The ID of the minted NFT
/// @dev This function should be called after RNG process
function revealFromPrimordial(
uint256 _player,
bytes memory _signature
) external returns (uint256 _tokenId);
/// @notice Mints an NFT for migration from V1 to V2, preserving attributes
/// @param _player The address of the player receiving the NFT
/// @param _attributes The dynamic attributes of the NFT
/// @param _immutableAttributes The immutable attributes of the NFT
/// @param _gameAttributes The game attributes of the NFT
/// @return _tokenId The token ID of the newly minted NFT
/// @dev Only callable by the migration manager
function mintForMigration(
address _player,
MunchablesCommonLib.NFTAttributes memory _attributes,
MunchablesCommonLib.NFTImmutableAttributes memory _immutableAttributes,
MunchablesCommonLib.NFTGameAttribute[] memory _gameAttributes
) external returns (uint256 _tokenId);
/// @notice Called post-level-up to randomly adjust game attributes based on transaction hash and signature
/// @param _requestId The ID of the RNG request
/// @param _rng Random bytes from the RNGProxy
/// @dev Only can be called by the RNGProxy
function levelUp(uint256 _requestId, bytes memory _rng) external;
/// @notice Called by SnuggeryManager when a player feeds a Munchable, it will check if level up is needed and
/// request randomness to update game attributes
/// @param _tokenId The token ID which was fed
/// @param _owner The eventual owner of the NFT at the time of the level up
function munchableFed(uint256 _tokenId, address _owner) external; // onlySnuggeryManager
/// @notice Get a player's unrevealed NFTs
/// @param _player The player to query, if a sub account is provided the main account unrevealedNFTs will be returned
function getUnrevealedNFTs(
address _player
) external view returns (uint16 _unrevealed);
/// @notice Get the current level and the next level threshold for a NFT given its schnibbles count
/// @param _chonks Quantity of schnibbles
/// @return _currentLevel Current level of the NFT
/// @return _nextLevelThreshold Schnibbles threshold for the next level
function getLevelUpData(
uint256 _chonks
) external view returns (uint16 _currentLevel, uint256 _nextLevelThreshold);
/// @notice Emitted when a player requests to reveal a munchable
/// @param _player The address of the player who initiated the reveal
event MunchableRevealRequested(address indexed _player);
/// @notice Emitted when a munchable levels up and requires an update to its attributes by an off-chain process
/// @param _player The address of the player whose munchable is leveling up
/// @param _tokenId The token ID of the munchable leveling up
/// @param _levelFrom The current level of the munchable
/// @param _levelTo The new level that the munchable should be updated to
event MunchableLevelUpRequest(
address indexed _player,
uint256 _tokenId,
uint16 _levelFrom,
uint16 _levelTo
);
/// @notice Event emitted when an NFT is revealed
event Revealed(
address indexed _owner,
uint256 _tokenId,
MunchablesCommonLib.NFTImmutableAttributes _immutableAttributes
);
/// @notice Event emitted when an NFT is leveled up
event LevelledUp(
address _owner,
uint256 _tokenId,
uint16 _fromLevel,
uint16 _toLevel,
MunchablesCommonLib.NFTGameAttribute[] _gameAttributes
);
/// @notice Emitted when a primordial is hatched into a munchable
event PrimordialHatched(
address indexed _player,
MunchablesCommonLib.NFTImmutableAttributes _immutableAttributes
);
/// @notice Event emitted when an NFT is minted for migration
event MintedForMigration(
address _player,
uint256 indexed _tokenId,
MunchablesCommonLib.NFTImmutableAttributes _immutableAttributes,
MunchablesCommonLib.NFTAttributes _attributes,
MunchablesCommonLib.NFTGameAttribute[] _gameAttributes
);
/// @notice Error thrown when there are no unrevealed munchables available for a player
error NoUnrevealedMunchablesError();
/// @notice Error thrown when a player's reveal queue is full and cannot handle more reveals
error RevealQueueFullError();
/// @notice Error thrown when a player's reveal queue is empty and there is nothing to reveal
error RevealQueueEmptyError();
/// @notice Error when a level up request either doesn't exist or the fromLevel is invalid
error InvalidLevelUpRequest();
/// @notice Error when no species is found for a given rarity during NFT creation
/// @param _rarity The rarity level that failed to produce a species
error NoSpeciesFoundError(MunchablesCommonLib.Rarity _rarity);
/// @notice Error if reveal cannot find species in realmLookup
/// @param _speciesId The species that failed
error NoRealmFoundError(uint16 _speciesId);
/// @notice Error thrown when a player attempts to claim a primordial while not being eligible
error PrimordialNotEligibleError();
/// @notice Error thrown when an action is attempted that requires the player to be registered, but they are not
error PlayerNotRegisteredError();
/// @notice Retrigger level rng
event RetriggeredLevelRNG(uint256[] tokenIds);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IConfigStorage.sol";
import "../interfaces/IConfigNotifiable.sol";
import "../config/BaseConfigStorageUpgradeable.sol";
import "../interfaces/IBaseBlastManager.sol";
import "../interfaces/IHoldsGovernorship.sol";
import "../interfaces/IBlast.sol";
import "./BaseBlastManager.sol";
abstract contract BaseBlastManagerUpgradeable is
BaseBlastManager,
BaseConfigStorageUpgradeable
{
function initialize(
address _configStorage
) public virtual override initializer {
BaseConfigStorageUpgradeable.initialize(_configStorage);
}
function __BaseBlastManagerUpgradeable_reconfigure() internal {
__BaseBlastManager_reconfigure();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
library MunchablesCommonLib {
enum Rarity {
Primordial,
Common,
Rare,
Epic,
Legendary,
Mythic,
Invalid
}
enum Realm {
Everfrost,
Drench,
Moltania,
Arridia,
Verdentis,
Invalid
}
struct NFTImmutableAttributes {
Rarity rarity;
uint16 species;
Realm realm;
uint8 generation;
uint32 hatchedDate;
}
struct NFTAttributes {
uint256 chonks;
uint16 level;
uint16 evolution;
uint256 lastPettedTime;
}
struct NFTGameAttribute {
GameAttributeType dataType;
bytes value;
}
struct Munchadex {
mapping(Realm => uint256) numInRealm;
mapping(Rarity => uint256) numInRarity;
mapping(bytes32 => uint256) unique;
uint256 numUnique;
}
enum GameAttributeIndex {
Strength,
Agility,
Stamina,
Defence,
Voracity,
Cuteness,
Charisma,
Trustworthiness,
Leadership,
Empathy,
Intelligence,
Cunning,
Creativity,
Adaptability,
Wisdom,
IsOriginal,
IndexCount // Do not use and keep at the end to detect number of indexes
}
enum GameAttributeType {
NotSet,
Bool,
String,
SmallInt,
BigUInt,
Bytes
}
struct PrimordialData {
uint256 chonks;
uint32 createdDate;
int8 level;
bool hatched;
}
struct SnuggeryNFT {
uint256 tokenId;
uint32 importedDate;
}
struct NFTFull {
uint256 tokenId;
NFTImmutableAttributes immutableAttributes;
NFTAttributes attributes;
NFTGameAttribute[] gameAttributes;
}
struct Player {
uint32 registrationDate;
uint32 lastPetMunchable;
uint32 lastHarvestDate;
Realm snuggeryRealm;
uint16 maxSnuggerySize;
uint256 unfedSchnibbles;
address referrer;
}
// Pure Functions
/// @notice Error when insufficient random data is provided for operations
error NotEnoughRandomError();
function calculateRaritySpeciesPercentage(
bytes memory randomBytes
) internal pure returns (uint32, uint32) {
if (randomBytes.length < 5) revert NotEnoughRandomError();
uint32 rarityBytes;
uint8 speciesByte;
uint32 rarityPercentage;
uint32 speciesPercent;
rarityBytes =
(uint32(uint8(randomBytes[0])) << 24) |
(uint32(uint8(randomBytes[1])) << 16) |
(uint32(uint8(randomBytes[2])) << 8) |
uint32(uint8(randomBytes[3]));
speciesByte = uint8(randomBytes[4]);
uint256 rarityPercentageTmp = (uint256(rarityBytes) * 1e6) /
uint256(4294967295);
uint256 speciesPercentTmp = (uint256(speciesByte) * 1e6) / uint256(255);
rarityPercentage = uint32(rarityPercentageTmp);
speciesPercent = uint32(speciesPercentTmp);
return (rarityPercentage, speciesPercent);
}
function getLevelThresholds(
uint256[] memory levelThresholds,
uint256 _chonk
)
internal
pure
returns (uint16 _currentLevel, uint256 _currentLevelThreshold)
{
if (_chonk >= levelThresholds[99]) {
return (101, levelThresholds[99]);
}
if (_chonk < levelThresholds[0]) {
return (1, 0);
}
uint256 low = 0;
uint256 high = levelThresholds.length;
uint256 mid = 0;
uint16 answer = 0;
while (low < high) {
mid = (low + high) / 2;
if (levelThresholds[mid] <= _chonk) {
low = mid + 1;
} else {
answer = uint16(mid);
high = mid;
}
}
_currentLevel = answer + 1;
_currentLevelThreshold = levelThresholds[uint256(answer - 1)];
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
enum StorageKey {
Many,
Paused,
LockManager,
AccountManager,
ClaimManager,
MigrationManager,
NFTOverlord,
SnuggeryManager,
PrimordialManager,
MunchadexManager,
MunchNFT,
MunchToken,
RewardsManager,
YieldDistributor,
GasFeeDistributor,
BlastContract,
BlastPointsContract,
BlastPointsOperator,
USDBContract,
WETHContract,
RNGProxyContract,
NFTAttributesManager,
Treasury,
OldMunchNFT,
MaxLockDuration,
DefaultSnuggerySize,
MaxSnuggerySize,
MaxRevealQueue,
MaxSchnibbleSpray,
PetTotalSchnibbles,
NewSlotCost,
PrimordialsEnabled,
BonusManager,
ReferralBonus,
RealmBonuses,
RarityBonuses,
LevelThresholds,
PrimordialLevelThresholds,
TotalMunchables,
MunchablesPerRealm,
MunchablesPerRarity,
RaritySetBonuses,
PointsPerPeriod,
PointsPerToken,
SwapEnabled,
PointsPerMigratedNFT,
PointsPerUnrevealedNFT,
MinETHPetBonus,
MaxETHPetBonus,
PetBonusMultiplier,
RealmLookups,
// Species & Probabilities
CommonSpecies,
RareSpecies,
EpicSpecies,
LegendarySpecies,
MythicSpecies,
CommonPercentage,
RarePercentage,
EpicPercentage,
LegendaryPercentage,
MythicPercentage,
MigrationBonus,
MigrationBonusEndTime,
MigrationDiscountFactor
}
enum Role {
Admin,
Social_1,
Social_2,
Social_3,
Social_4,
Social_5,
SocialApproval_1,
SocialApproval_2,
SocialApproval_3,
SocialApproval_4,
SocialApproval_5,
PriceFeed_1,
PriceFeed_2,
PriceFeed_3,
PriceFeed_4,
PriceFeed_5,
Snapshot,
NewPeriod,
ClaimYield,
Minter,
NFTOracle
}
enum StorageType {
Uint,
SmallUintArray,
UintArray,
SmallInt,
SmallIntArray,
Bool,
Address,
AddressArray,
Bytes32
}
interface IConfigStorage {
// Manual notify
function manualNotify(uint8 _index, uint8 _length) external;
// Manual notify for a specific contract
function manualNotifyAddress(address _contract) external;
// Setters
function setRole(Role _role, address _contract, address _addr) external;
function setUniversalRole(Role _role, address _addr) external;
function setUint(StorageKey _key, uint256 _value, bool _notify) external;
function setUintArray(
StorageKey _key,
uint256[] memory _value,
bool _notify
) external;
function setSmallUintArray(
StorageKey _key,
uint8[] calldata _smallUintArray,
bool _notify
) external;
function setSmallInt(StorageKey _key, int16 _value, bool _notify) external;
function setSmallIntArray(
StorageKey _key,
int16[] memory _value,
bool _notify
) external;
function setBool(StorageKey _key, bool _value, bool _notify) external;
function setAddress(StorageKey _key, address _value, bool _notify) external;
function setAddresses(
StorageKey[] memory _keys,
address[] memory _values,
bool _notify
) external;
function setAddressArray(
StorageKey _key,
address[] memory _value,
bool _notify
) external;
function setBytes32(StorageKey _key, bytes32 _value, bool _notify) external;
// Getters
function getRole(Role _role) external view returns (address);
function getContractRole(
Role _role,
address _contract
) external view returns (address);
function getUniversalRole(Role _role) external view returns (address);
function getUint(StorageKey _key) external view returns (uint256);
function getUintArray(
StorageKey _key
) external view returns (uint256[] memory);
function getSmallUintArray(
StorageKey _key
) external view returns (uint8[] memory _smallUintArray);
function getSmallInt(StorageKey _key) external view returns (int16);
function getSmallIntArray(
StorageKey _key
) external view returns (int16[] memory);
function getBool(StorageKey _key) external view returns (bool);
function getAddress(StorageKey _key) external view returns (address);
function getAddressArray(
StorageKey _key
) external view returns (address[] memory);
function getBytes32(StorageKey _key) external view returns (bytes32);
// Notification Address Management
function addNotifiableAddress(address _addr) external;
function addNotifiableAddresses(address[] memory _addresses) external;
function removeNotifiableAddress(address _addr) external;
function getNotifiableAddresses()
external
view
returns (address[] memory _addresses);
error ArrayTooLongError();
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
import "./IConfigStorage.sol";
interface IConfigNotifiable {
function configUpdated() external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol";
import "openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
import "../interfaces/IConfigStorage.sol";
import {BaseConfigStorage} from "./BaseConfigStorage.sol";
abstract contract BaseConfigStorageUpgradeable is
Initializable,
BaseConfigStorage,
UUPSUpgradeable
{
function _authorizeUpgrade(address _input) internal override onlyAdmin {}
function initialize(address _configStorage) public virtual initializer {
__BaseConfigStorage_setConfigStorage(_configStorage);
}
function __BaseConfigStorageUpgradable_reconfigure() internal {
__BaseConfigStorage_reconfigure();
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
interface IBaseBlastManager {
function getConfiguredGovernor() external view returns (address _governor);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
/// @notice Contracts which implement this interface will be the governor for other contracts and
/// give it up on request from the contract
interface IHoldsGovernorship {
function reassignBlastGovernor(address _newAddress) external;
function isGovernorOfContract(
address _contract
) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
enum GasMode {
VOID,
CLAIMABLE
}
interface IBlastPoints {
function configurePointsOperator(address operator) external;
}
interface IERC20Rebasing {
function configure(YieldMode) external returns (uint256);
function claim(
address recipient,
uint256 amount
) external returns (uint256);
function getClaimableAmount(
address account
) external view returns (uint256);
}
interface IBlast {
// configure
function configureContract(
address contractAddress,
YieldMode _yield,
GasMode gasMode,
address governor
) external;
function configure(
YieldMode _yield,
GasMode gasMode,
address governor
) external;
// base configuration options
function configureClaimableYield() external;
function configureClaimableYieldOnBehalf(address contractAddress) external;
function configureAutomaticYield() external;
function configureAutomaticYieldOnBehalf(address contractAddress) external;
function configureVoidYield() external;
function configureVoidYieldOnBehalf(address contractAddress) external;
function configureClaimableGas() external;
function configureClaimableGasOnBehalf(address contractAddress) external;
function configureVoidGas() external;
function configureVoidGasOnBehalf(address contractAddress) external;
function configureGovernor(address _governor) external;
function configureGovernorOnBehalf(
address _newGovernor,
address contractAddress
) external;
// claim yield
function claimYield(
address contractAddress,
address recipientOfYield,
uint256 amount
) external returns (uint256);
function claimAllYield(
address contractAddress,
address recipientOfYield
) external returns (uint256);
// claim gas
function claimAllGas(
address contractAddress,
address recipientOfGas
) external returns (uint256);
function claimGasAtMinClaimRate(
address contractAddress,
address recipientOfGas,
uint256 minClaimRateBips
) external returns (uint256);
function claimMaxGas(
address contractAddress,
address recipientOfGas
) external returns (uint256);
function claimGas(
address contractAddress,
address recipientOfGas,
uint256 gasToClaim,
uint256 gasSecondsToConsume
) external returns (uint256);
// read functions
function readClaimableYield(
address contractAddress
) external view returns (uint256);
function readYieldConfiguration(
address contractAddress
) external view returns (uint8);
function readGasParams(
address contractAddress
)
external
view
returns (
uint256 etherSeconds,
uint256 etherBalance,
uint256 lastUpdated,
GasMode
);
/**
* @notice Checks if the caller is authorized
* @param contractAddress The address of the contract
* @return A boolean indicating if the caller is authorized
*/
function isAuthorized(address contractAddress) external view returns (bool);
function isGovernor(address contractAddress) external view returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IConfigStorage.sol";
import "../interfaces/IConfigNotifiable.sol";
import "../config/BaseConfigStorage.sol";
import "../interfaces/IBaseBlastManager.sol";
import "../interfaces/IHoldsGovernorship.sol";
import "../interfaces/IERC20YieldClaimable.sol";
import "../interfaces/IBlast.sol";
abstract contract BaseBlastManager is
IBaseBlastManager,
IERC20YieldClaimable,
BaseConfigStorage
{
IBlast public blastContract;
IBlastPoints public blastPointsContract;
address private _governorConfigured;
address private _pointsOperatorConfigured;
bool private _blastClaimableConfigured;
IERC20 public USDB;
IERC20 public WETH;
error InvalidGovernorError();
function __BaseBlastManager_reconfigure() internal {
// load config from the config storage contract and configure myself
address blastAddress = configStorage.getAddress(
StorageKey.BlastContract
);
if (blastAddress != address(blastContract)) {
blastContract = IBlast(blastAddress);
if (blastContract.isAuthorized(address(this))) {
blastContract.configureClaimableGas();
// fails on cloned networks
(bool success, ) = blastAddress.call(
abi.encodeWithSelector(
bytes4(keccak256("configureClaimableYield()"))
)
);
if (success) {
// not on a cloned network and no compiler error!
}
}
}
address pointsContractAddress = configStorage.getAddress(
StorageKey.BlastPointsContract
);
if (pointsContractAddress != address(blastPointsContract)) {
blastPointsContract = IBlastPoints(pointsContractAddress);
address pointsOperator = configStorage.getAddress(
StorageKey.BlastPointsOperator
);
if (_pointsOperatorConfigured == address(0)) {
// Reassignment must be called from the point operator itself
blastPointsContract.configurePointsOperator(pointsOperator);
_pointsOperatorConfigured = pointsOperator;
}
}
address usdbAddress = configStorage.getAddress(StorageKey.USDBContract);
address wethAddress = configStorage.getAddress(StorageKey.WETHContract);
if (usdbAddress != address(USDB)) {
USDB = IERC20(usdbAddress);
IERC20Rebasing _USDB = IERC20Rebasing(usdbAddress);
_USDB.configure(YieldMode.CLAIMABLE);
}
if (wethAddress != address(WETH)) {
WETH = IERC20(wethAddress);
IERC20Rebasing _WETH = IERC20Rebasing(wethAddress);
_WETH.configure(YieldMode.CLAIMABLE);
}
address rewardsManagerAddress = configStorage.getAddress(
StorageKey.RewardsManager
);
if (rewardsManagerAddress != address(0)) {
setBlastGovernor(rewardsManagerAddress);
}
super.__BaseConfigStorage_reconfigure();
}
function setBlastGovernor(address _governor) internal {
if (_governor == address(0)) revert InvalidGovernorError();
if (address(blastContract) == address(0)) return;
if (_governorConfigured == address(0)) {
// if this contract is the governor then it should claim its own yield/gas
if (_governor != address(this)) {
// Once this is called the governor will be the only account allowed to configure
blastContract.configureGovernor(_governor);
}
} else {
IHoldsGovernorship(_governorConfigured).reassignBlastGovernor(
_governor
);
}
_governorConfigured = _governor;
}
function claimERC20Yield(
address _tokenContract,
uint256 _amount
) external onlyConfiguredContract(StorageKey.RewardsManager) {
IERC20Rebasing(_tokenContract).claim(
configStorage.getAddress(StorageKey.RewardsManager),
_amount
);
}
function getConfiguredGovernor() external view returns (address _governor) {
_governor = _governorConfigured;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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: UNLICENSED
pragma solidity 0.8.25;
import "../interfaces/IConfigStorage.sol";
abstract contract BaseConfigStorage {
IConfigStorage public configStorage;
bool _paused;
modifier onlyConfigStorage() {
if (msg.sender != address(configStorage)) revert OnlyStorageError();
_;
}
modifier onlyConfiguredContract(StorageKey _key) {
address configuredContract = configStorage.getAddress(_key);
if (configuredContract == address(0)) revert UnconfiguredError(_key);
if (configuredContract != msg.sender) revert UnauthorisedError();
_;
}
modifier onlyConfiguredContract2(StorageKey _key, StorageKey _key2) {
address configuredContract = configStorage.getAddress(_key);
address configuredContract2 = configStorage.getAddress(_key2);
if (
configuredContract != msg.sender &&
configuredContract2 != msg.sender
) {
if (configuredContract == address(0))
revert UnconfiguredError(_key);
if (configuredContract2 == address(0))
revert UnconfiguredError(_key2);
revert UnauthorisedError();
}
_;
}
modifier onlyConfiguredContract3(
StorageKey _key,
StorageKey _key2,
StorageKey _key3
) {
address configuredContract = configStorage.getAddress(_key);
address configuredContract2 = configStorage.getAddress(_key2);
address configuredContract3 = configStorage.getAddress(_key3);
if (
configuredContract != msg.sender &&
configuredContract2 != msg.sender &&
configuredContract3 != msg.sender
) {
if (configuredContract == address(0))
revert UnconfiguredError(_key);
if (configuredContract2 == address(0))
revert UnconfiguredError(_key2);
if (configuredContract3 == address(0))
revert UnconfiguredError(_key3);
revert UnauthorisedError();
}
_;
}
modifier onlyOneOfRoles(Role[5] memory roles) {
for (uint256 i = 0; i < roles.length; i++) {
if (msg.sender == configStorage.getRole(roles[i])) {
_;
return;
}
}
revert InvalidRoleError();
}
modifier onlyRole(Role role) {
if (msg.sender != configStorage.getRole(role))
revert InvalidRoleError();
_;
}
modifier onlyUniversalRole(Role role) {
if (msg.sender != configStorage.getUniversalRole(role))
revert InvalidRoleError();
_;
}
modifier onlyAdmin() {
if (msg.sender != configStorage.getUniversalRole(Role.Admin))
revert InvalidRoleError();
_;
}
modifier notPaused() {
if (_paused) revert ContractsPausedError();
_;
}
error UnconfiguredError(StorageKey _key);
error UnauthorisedError();
error OnlyStorageError();
error InvalidRoleError();
error ContractsPausedError();
function configUpdated() external virtual;
function __BaseConfigStorage_setConfigStorage(
address _configStorage
) internal {
configStorage = IConfigStorage(_configStorage);
}
function __BaseConfigStorage_reconfigure() internal {
_paused = configStorage.getBool(StorageKey.Paused);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
/// @notice Contracts which implement this interface can be instructed by Rewards Manager to claim their yield for
/// ERC20 tokens and send the yield back to the rewards manager
interface IERC20YieldClaimable {
function claimERC20Yield(address _tokenContract, uint256 _amount) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}{
"remappings": [
"@api3/=node_modules/@api3/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 2000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"CannotPetOwnError","type":"error"},{"inputs":[],"name":"ContractsPausedError","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"IncorrectOwnerError","type":"error"},{"inputs":[{"internalType":"uint256","name":"_currentUnfedSchnibbles","type":"uint256"}],"name":"InsufficientSchnibblesError","type":"error"},{"inputs":[],"name":"InvalidGovernorError","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidOwnerError","type":"error"},{"inputs":[],"name":"InvalidRoleError","type":"error"},{"inputs":[],"name":"InvalidTokenIDError","type":"error"},{"inputs":[],"name":"MunchableNotInSnuggeryError","type":"error"},{"inputs":[],"name":"NoPrimordialInSnuggeryError","type":"error"},{"inputs":[],"name":"NotApprovedError","type":"error"},{"inputs":[],"name":"NotConfiguredError","type":"error"},{"inputs":[],"name":"NotEnoughPointsError","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OnlyStorageError","type":"error"},{"inputs":[],"name":"PetTooSoonError","type":"error"},{"inputs":[],"name":"PettedIsSubAccount","type":"error"},{"inputs":[],"name":"PettedTooSoonError","type":"error"},{"inputs":[],"name":"PlayerNotRegisteredError","type":"error"},{"inputs":[],"name":"SnuggeryFullError","type":"error"},{"inputs":[],"name":"SnuggeryMaxSizeError","type":"error"},{"inputs":[],"name":"TokenNotFoundInSnuggeryError","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[],"name":"UnauthorisedError","type":"error"},{"inputs":[{"internalType":"enum StorageKey","name":"_key","type":"uint8"}],"name":"UnconfiguredError","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_player","type":"address"},{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MunchableExported","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_player","type":"address"},{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_baseChonks","type":"uint256"},{"indexed":false,"internalType":"int256","name":"_bonusChonks","type":"int256"}],"name":"MunchableFed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_player","type":"address"},{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MunchableImported","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_petter","type":"address"},{"indexed":true,"internalType":"address","name":"_petted","type":"address"},{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_petterSchnibbles","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_pettedSchnibbles","type":"uint256"}],"name":"MunchablePetted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_player","type":"address"},{"indexed":false,"internalType":"uint16","name":"_previousSize","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"_newSize","type":"uint16"}],"name":"SnuggerySizeIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDB","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blastContract","outputs":[{"internalType":"contract IBlast","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blastPointsContract","outputs":[{"internalType":"contract IBlastPoints","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenContract","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"claimERC20Yield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"configStorage","outputs":[{"internalType":"contract IConfigStorage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"configUpdated","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"exportMunchable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_schnibbles","type":"uint256"}],"name":"feed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getConfiguredGovernor","outputs":[{"internalType":"address","name":"_governor","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalTotalChonk","outputs":[{"internalType":"uint256","name":"_totalGlobalChonk","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getSnuggery","outputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint32","name":"importedDate","type":"uint32"}],"internalType":"struct MunchablesCommonLib.SnuggeryNFT[]","name":"_snuggery","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"getTotalChonk","outputs":[{"internalType":"uint256","name":"_totalChonk","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"importMunchable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_quantity","type":"uint8"}],"name":"increaseSnuggerySize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_configStorage","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pettedOwner","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"pet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]Contract Creation Code
60a0806040523460c857306080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff8260401c1660b957506001600160401b036002600160401b0319828216016075575b60405161354890816100ce823960805181818161140d01526115040152f35b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a13880806056565b63f92ee8a960e01b8152600490fd5b600080fdfe608080604052600436101561001357600080fd5b600090813560e01c9081630659b1881461209e5750806312c3448b14611ba357806326342d0b14611a6857806331a0edec14611a415780633cdad82c14611a1a578063443b1786146119f45780634b03eeb4146117eb5780634f1ef2861461148757806352d1902d146113f257806362eb1e22146111f35780636d6aa5bb14610d8e57806375eeac141461092a5780638da52e93146108d6578063ad3cb1cc1461083f578063ad5c464814610818578063b930b482146107f1578063c4d66de814610500578063f1f5852514610144578063f63ed21e146101265763fce14af6146100fd57600080fd5b3461012357806003193601126101235760206001600160a01b0360015416604051908152f35b80fd5b50346101235780600319360112610123576020600a54604051908152f35b5034610123576020806003193601126104fc576004359060ff835460a01c166104d25782610171336125a0565b50916001600160a01b039384600d5416803b1561045857836040518092631abb7b0b60e01b825288881660048301528160249a8b925af180156104c7579084916104af575b50506101c1336125a0565b509480600c54166040517f6352211e00000000000000000000000000000000000000000000000000000000815283600482015284818a81855afa9081156104a457869161046b575b50823091160361041a57803b15610467576040517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0388166024820152604481018490529085908290606490829084905af1801561045c57908591610444575b5050610284828761268e565b96901561041a5716938484526009916009845260408520547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081810190811198895b610407578181101561037257888852858752604088206001908183019081841161035f57906102f5916123f5565b50908a8a5287895261030a8360408c206123f5565b91909161034d57908291600194938203610329575b50505001896102c7565b8063ffffffff9284548155019201541663ffffffff1982541617905538808061031f565b8d8b634e487b7160e01b815280600452fd5b8d8b634e487b7160e01b81526011600452fd5b8688868b878f88838652600987526040862090815480156103f457019161039983836123f5565b9190916103e35750917ffdcb4d15d6978e5c2ea4fac76eeaa6a98e65ca72c0ec349ed335f4cc61f744b4939187600185826103e09b9c9755015555604051908152a261270b565b80f35b87634e487b7160e01b815280600452fd5b8388634e487b7160e01b81526031600452fd5b8a88634e487b7160e01b81526011600452fd5b60046040517f4df67f2d000000000000000000000000000000000000000000000000000000008152fd5b61044d90612297565b610458578338610278565b8380fd5b6040513d87823e3d90fd5b8480fd5b90508481813d831161049d575b61048281836122c7565b810103126104995761049390612306565b38610209565b8580fd5b503d610478565b6040513d88823e3d90fd5b6104b890612297565b6104c35782386101b6565b8280fd5b6040513d86823e3d90fd5b60046040517f8f85eea2000000000000000000000000000000000000000000000000000000008152fd5b5080fd5b50346101235760206003193601126101235761051a61224f565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0080549160ff8360401c16159067ffffffffffffffff808516948515806107ea575b600180971490816107e0575b1590816107d7575b50610739577fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009084878383161787556107b8575b5084549260ff8460401c16159383811688811591826107b0575b1490816107a6575b15908161079d575b5061073957848884831617885561077e575b50855460ff8160401c16159381168881159182610776575b14908161076c575b159081610763575b506107395783886001600160a01b0394831617885561071a575b501673ffffffffffffffffffffffffffffffffffffffff198754161786556106db575b61069c575b610652612800565b61065a578280f35b7fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2918168ff00000000000000001960209354169055604051908152a138808280f35b68ff00000000000000001982541682557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d26020604051858152a161064a565b68ff00000000000000001983541683557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d26020604051868152a1610645565b68ffffffffffffffffff19166801000000000000000117865538610622565b60046040517ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b90501538610608565b303b159150610600565b8692506105f8565b68ffffffffffffffffff191668010000000000000001178655386105e0565b905015386105ce565b303b1591506105c6565b8792506105be565b68ffffffffffffffffff191668010000000000000001178555386105a4565b90501538610570565b303b159150610568565b508361055c565b503461012357806003193601126101235760206001600160a01b0360025416604051908152f35b503461012357806003193601126101235760206001600160a01b0360065416604051908152f35b503461012357806003193601126101235760405161085c81612265565b6005815260207f352e302e30000000000000000000000000000000000000000000000000000000602083015260405192839160208352835193846020850152825b8581106108bf57505050601f83601f1992604080968601015201168101030190f35b81810183015187820160400152869450820161089d565b50346101235780600319360112610123576001600160a01b038154163303610900576103e0612800565b60046040517fe1010280000000000000000000000000000000000000000000000000000000008152fd5b503461012357602090816003193601126101235760043560ff825460a01c166104d257610956336125a0565b50906001600160a01b039081600d5416803b15610467578490816040518092631abb7b0b60e01b825286881660048301528160249586925af180156104a457908691610d7a575b505060018210610d50576109b0336125a0565b9084600c5416906040517f6352211e00000000000000000000000000000000000000000000000000000000815285600482015289818681865afa908115610d45579087918a91610d09575b508183169788911603610cdf576040517fe985e9c500000000000000000000000000000000000000000000000000000000815287600482015230868201528a81604481875afa908115610ca7578a91610cb2575b50159081610c1d575b50610bf357813b15610bef576040517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b03919091166004820152306024820152604481018590529087908290606490829084905af18015610be457908791610bd0575b508490526009875261ffff60806040882054920151161115610ba65782855260098652604085209063ffffffff90604051610afe81612265565b84815288810193834216855280549068010000000000000000821015610b935790610b2e916001820181556123f5565b929092610b8257509160016103e0989994927f821585ec6e57e9f9456596c323af52550f2edd5b3ac8b1c541727e2f89acba3296945181550191511663ffffffff19825416179055604051908152a261270b565b88634e487b7160e01b815280600452fd5b838a634e487b7160e01b81526041600452fd5b60046040517f141091bc000000000000000000000000000000000000000000000000000000008152fd5b610bd990612297565b610499578538610ac4565b6040513d89823e3d90fd5b8780fd5b60046040517f6a307d79000000000000000000000000000000000000000000000000000000008152fd5b9050604051907f081812fc0000000000000000000000000000000000000000000000000000000082528660048301528a828781875afa918215610ca7578a92610c6c575b501630141538610a58565b9091508a81813d8311610ca0575b610c8481836122c7565b81010312610c9c57610c9590612306565b9038610c61565b8980fd5b503d610c7a565b6040513d8c823e3d90fd5b610cd291508b3d8d11610cd8575b610cca81836122c7565b810190612588565b38610a4f565b503d610cc0565b60046040517f18bbd964000000000000000000000000000000000000000000000000000000008152fd5b8092508b8092503d8311610d3e575b610d2281836122c7565b81010312610d3a57610d348791612306565b386109fb565b8880fd5b503d610d18565b6040513d8b823e3d90fd5b60046040517f7ac5e436000000000000000000000000000000000000000000000000000000008152fd5b610d8390612297565b61046757843861099d565b503461012357604060031936011261012357600435602480359060ff845460a01c166104d257610dbd336125a0565b50916001600160a01b03908582600d5416803b156104fc578180918660405180948193631abb7b0b60e01b8352898c1660048401525af180156110a5576111df575b5050610e0a336125a0565b929060a084019384518481106111af5750610e25888361268e565b5015611185576010546040517fc04907220000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602481018a905295906020908790604490829088165afa958615610ca7578a96611151575b508585028a8612967f80000000000000000000000000000000000000000000000000000000000000008114881661113e57868205148615171561112b57670de0b6b3a764000090059584600e541660405191634378a6e360e01b83528b60048401526080838b81855afa928315611120578d936110ef575b508888019089821280158216911516176110dc5790610f2683928e9897969594516124bc565b8252803b156110d857604080517fd4e403b8000000000000000000000000000000000000000000000000000000008152600481018e905283516024820152602084015161ffff908116604483015291840151909116606482015260609092015160848301528690829060a490829084905af19081156104a45786916110c4575b5050610fb386825161257b565b905282600f5416803b1561046757610fe68592918392604051948580948193630bcaacd960e21b835289600484016124f2565b03925af19081156104c75784916110b0575b5050816011541690813b156104585760448985809460405196879586947fc7301a84000000000000000000000000000000000000000000000000000000008652600486015216809b8401525af180156110a557611091575b50506103e0947f4cf5773b4c75ae2ed0de627f7f8bfdb27407d753f74feb57fb859fb0f8eec4c99260609260405192835260208301526040820152a261270b565b61109a90612297565b610499578538611050565b6040513d84823e3d90fd5b6110b990612297565b6104c3578238610ff8565b6110cd90612297565b610467578438610fa6565b8680fd5b898d634e487b7160e01b81526011600452fd5b61111291935060803d608011611119575b61110a81836122c7565b81019061245f565b9138610f00565b503d611100565b6040513d8f823e3d90fd5b878b634e487b7160e01b81526011600452fd5b888c634e487b7160e01b81526011600452fd5b9095506020813d60201161117d575b8161116d602093836122c7565b81010312610c9c57519438610e88565b3d9150611160565b60046040517f693f635f000000000000000000000000000000000000000000000000000000008152fd5b8690604051907fa369efb60000000000000000000000000000000000000000000000000000000082526004820152fd5b6111e890612297565b610499578538610dff565b50346101235760206003193601126101235760043560ff81168091036104fc5760ff825460a01c166104d257611228336125a0565b9160085480156113c8576080840161ffff9485825116928660065460b01c1684101561139e5784611258916124df565b93876001600160a01b039586600d5416803b156104c3576040517f918d24280000000000000000000000000000000000000000000000000000000081526001600160a01b038a166004820152602481019290925282908290604490829084905af180156110a55761138a575b50508683511601868111611376579086889216835284600f5416803b156104c35761130a8392918392604051948580948193630bcaacd960e21b83528d600484016124f2565b03925af180156110a55761135a575b507f19dd07f4ceafd05150e1d94374a580ecb781172acb3a528da61f6a41d5f03fa460608686868a875116916040519316835260208301526040820152a180f35b611368909594939295612297565b610499579091928538611319565b602488634e487b7160e01b81526011600452fd5b61139390612297565b610bef5787386112c4565b60046040517fc460755e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fa303b7dd000000000000000000000000000000000000000000000000000000008152fd5b50346101235780600319360112610123576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361145d5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b60046040517fe07c8dba000000000000000000000000000000000000000000000000000000008152fd5b5060406003193601126101235761149c61224f565b602491823567ffffffffffffffff81116104fc57366023820112156104fc578060040135926114ca846122ea565b6114d760405191826122c7565b848152602094858201933688838301011161049957818692898993018737830101526001600160a01b03807f0000000000000000000000000000000000000000000000000000000000000000168030149081156117bd575b5061145d57868682875416604051928380927fd91078070000000000000000000000000000000000000000000000000000000082528a60048301525afa9081156104a4579082918791611785575b5016330361175b57821694604051907f52d1902d00000000000000000000000000000000000000000000000000000000825280826004818a5afa918291879361172b575b50506115f7578686604051907f4c9c8ce30000000000000000000000000000000000000000000000000000000082526004820152fd5b8590877f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc918281036116fd5750843b156116ce5750805473ffffffffffffffffffffffffffffffffffffffff1916821790556040518592917fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a281511561169857506116949382915190845af461168e613306565b9161347f565b5080f35b9350505050346116a6575080f35b807fb398979f0000000000000000000000000000000000000000000000000000000060049252fd5b82604051907f4c9c8ce30000000000000000000000000000000000000000000000000000000082526004820152fd5b604051907faa1d49a40000000000000000000000000000000000000000000000000000000082526004820152fd5b9080929350813d8311611754575b61174381836122c7565b8101031261049957519038806115c1565b503d611739565b60046040517ff7aa0316000000000000000000000000000000000000000000000000000000008152fd5b809250888092503d83116117b6575b61179e81836122c7565b81010312610499576117b08291612306565b3861157d565b503d611794565b9050817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541614153861152f565b50346101235760406003193601126101235761180561224f565b6001600160a01b0380835416604051927fbcaa0c5500000000000000000000000000000000000000000000000000000000808552600c60048601526020948581602481875afa8015610be457859188916119bc575b5016801561198b5733036119615784906024604051809581938252600c60048301525afa801561045c5784928691611925575b506040517faad3ec960000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024803590820152928391908290879082604481015b0393165af1801561191a576118ed578280f35b813d8311611913575b61190081836122c7565b8101031261190e5738808280f35b600080fd5b503d6118f6565b6040513d85823e3d90fd5b8381939492503d831161195a575b61193d81836122c7565b810103126104675783916119536118da92612306565b909161188d565b503d611933565b60046040517f1a48f084000000000000000000000000000000000000000000000000000000008152fd5b60246040517f92bc2cd0000000000000000000000000000000000000000000000000000000008152600c6004820152fd5b809250878092503d83116119ed575b6119d581836122c7565b810103126110d8576119e78591612306565b3861185a565b503d6119cb565b50346101235780600319360112610123576001600160a01b036020915416604051908152f35b503461012357806003193601126101235760206001600160a01b0360035416604051908152f35b503461012357806003193601126101235760206001600160a01b0360055416604051908152f35b503461012357602090816003193601126101235790611a8561224f565b9180926001600160a01b0380911682526009835260408220928354611aa9816123dd565b94611ab760405196876122c7565b818652845281842084908387015b838310611b7e57505050508291600e5416945b845160ff841690811015611b7557611af0908661244b565b515160405190634378a6e360e01b8252600482015260809081816024818b5afa9182156104a45790611b2e9392918792611b58575b505051906124bc565b9160ff809116908114611b445760010191611ad8565b602484634e487b7160e01b81526011600452fd5b611b6e9250803d106111195761110a81836122c7565b3880611b25565b50604051908152f35b600285600192611b91859c999b9c612427565b81520192019201919097969497611ac5565b503461012357604060031936011261012357611bbd61224f565b60ff825460a01c166104d257611bd2336125a0565b9091611bdd816125a0565b90916001600160a01b0381166001600160a01b0384160361207457611c05906024359061268e565b501561118557602460806001600160a01b03600e541660405192838092634378a6e360e01b8252823560048301525afa9081156104a4578691612055575b506001600160a01b0385166001600160a01b0384161461202b5760608101516154608101809111611f8f57421061200157610e1063ffffffff6020860151160163ffffffff8111611f8f5763ffffffff42911611611fd757602460206001600160a01b0360105416604051928380927fdf89ff780000000000000000000000000000000000000000000000000000000082526001600160a01b038b1660048301525afa8015610be4578790611fa3575b611d159150670de0b6b3a7640000611d0e60075492836124df565b04906124bc565b9384600581020460051485151715611f8f57600b6005860204670de0b6b3a76400008082028290041490151715611f8f57600685028581046006148615171561137657600b90049283670de0b6b3a7640000810204670de0b6b3a76400001484151715611376578060a0899201611d97670de0b6b3a7640000870282516124bc565b90526001600160a01b03600f541690813b156104c3578291611dd091604051948580948193630bcaacd960e21b83528c600484016124f2565b03925af18015611f8457611f6f575b50908160a0889301611e02670de0b6b3a7640000600b60058a02040282516124bc565b905263ffffffff4216908160208201526001600160a01b03600f5416803b1561046757611e499185918a83604051809681958294630bcaacd960e21b8452600484016124f2565b03925af19081156104c7578491611f5b575b505060608201526001600160a01b03600e5416803b156104c357604080517fd4e403b8000000000000000000000000000000000000000000000000000000008152602480356004830152845190820152602084015161ffff908116604483015291840151909116606482015260609092015160848301528290829060a490829084905af180156110a557611f47575b50506001600160a01b03807f89689ae04e5ef625e51d8d11b7135e0c63aad6b927fe1826384fc51e0c86a4ec93670de0b6b3a764000060609481600b60056040519a6024358c52020402602089015202604087015216941692a380f35b611f5090612297565b610467578438611eea565b611f6490612297565b6104c3578238611e5b565b611f7c9097919297612297565b959038611ddf565b6040513d8a823e3d90fd5b602487634e487b7160e01b81526011600452fd5b506020813d602011611fcf575b81611fbd602093836122c7565b810103126110d857611d159051611cf3565b3d9150611fb0565b60046040517ff07010d0000000000000000000000000000000000000000000000000000000008152fd5b60046040517faf13d42b000000000000000000000000000000000000000000000000000000008152fd5b60046040517f4bc676a9000000000000000000000000000000000000000000000000000000008152fd5b61206e915060803d6080116111195761110a81836122c7565b38611c43565b60046040517f762b3b47000000000000000000000000000000000000000000000000000000008152fd5b9050346104fc57602090816003193601126104c3576120bb61224f565b90806001600160a01b03928380600f5416917f5c12cd4b0000000000000000000000000000000000000000000000000000000084521660048301528160246101009485935afa91821561045c578592612221575b5050168083526009808352604084205490612129826123dd565b9261213760405194856122c7565b828452601f19612146846123dd565b01865b8181106121f9575050855b8381106121aa57505050506040519180830190808452825180925280604085019301945b8281106121855784840385f35b85518051855282015163ffffffff168483015294810194604090930192600101612178565b600190828896985283875263ffffffff876121d16121cb8460408b206123f5565b50612427565b80516121dd858d61244b565b5152015116876121ed838b61244b565b51015201959395612154565b869060409896985161220a81612265565b878152878382015282828b01015201969496612149565b6122409250803d10612248575b61223881836122c7565b81019061233a565b50388061210f565b503d61222e565b600435906001600160a01b038216820361190e57565b6040810190811067ffffffffffffffff82111761228157604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff811161228157604052565b60e0810190811067ffffffffffffffff82111761228157604052565b90601f601f19910116810190811067ffffffffffffffff82111761228157604052565b67ffffffffffffffff811161228157601f01601f191660200190565b51906001600160a01b038216820361190e57565b519063ffffffff8216820361190e57565b519061ffff8216820361190e57565b8092910391610100831261190e5760e0601f1961235683612306565b94011261190e576040519061236a826122ab565b6123766020820161231a565b82526123846040820161231a565b60208301526123956060820161231a565b60408301526080810151600681101561190e576123d59160e09160608501526123c060a0820161232b565b608085015260c081015160a085015201612306565b60c082015290565b67ffffffffffffffff81116122815760051b60200190565b80548210156124115760005260206000209060011b0190600090565b634e487b7160e01b600052603260045260246000fd5b9060405161243481612265565b602063ffffffff6001839580548552015416910152565b80518210156124115760209160051b010190565b9081608091031261190e5760405190608082019082821067ffffffffffffffff831117612281576060916040528051835261249c6020820161232b565b60208401526124ad6040820161232b565b60408401520151606082015290565b919082018092116124c957565b634e487b7160e01b600052601160045260246000fd5b818102929181159184041417156124c957565b9092916101008201936001600160a01b03809116835263ffffffff8083511660208501528060208401511660408501526040830151166060840152606082015160068110156125655760e09260c091608086015261ffff60808201511660a086015260a081015182860152015116910152565b634e487b7160e01b600052602160045260246000fd5b919082039182116124c957565b9081602091031261190e5751801515810361190e5790565b9060c0906040516125b0816122ab565b60009281848093528260208201528260408201528260608201528260808201528260a082015201526001600160a01b039283600f54166040519485927f5c12cd4b0000000000000000000000000000000000000000000000000000000084521660048301528160246101009687935afa93841561191a57839461266b575b505063ffffffff83929351161561264157565b60046040517f3e3a049f000000000000000000000000000000000000000000000000000000008152fd5b80919294506126869350903d106122485761223881836122c7565b91388061262e565b90916000926000906001600160a01b03829416918281526009906020916009602052604092604083205495835b8781106126cd575b5050505050505050565b8185528383526126df818787206123f5565b505487146126ef576001016126bb565b99505050505050505090506001919038808080808080806126c3565b906001600160a01b0380921691600092808452602092600b60205260409160408620549186928795600e5416935b8389526009885285892080548810156127ac5787612756916123f5565b5054865190634378a6e360e01b8252600482015260809081816024818a5afa918b83156127a15792612797926009959260019592611b5857505051906124bc565b9701969050612739565b8951903d90823e3d90fd5b50965094509590859350604092508152600b60205220558181036127ce575050565b6127dd6127e292600a546124bc565b61257b565b600a55565b9081602091031261190e57518060010b810361190e5790565b60006001600160a01b03808254169060409081517fbcaa0c55000000000000000000000000000000000000000000000000000000009384825260049460038684015260209260249284828581845afa9182156132fc5789926132c5575b508573ffffffffffffffffffffffffffffffffffffffff19921682600f541617600f558651838152888082015285818681855afa9081156130f3579087918b9161328d575b501682600d541617600d558651838152600a8982015285818681855afa9081156130f3579087918b91613255575b501682600c541617600c55865183815260158982015285818681855afa9081156130f3579087918b9161321d575b501682600e541617600e558651838152858982015285818681855afa9081156130f3579087918b916131e5575b5016826010541617601055865190838252600691828a82015286818781855afa908115612df7579088918c916131ad575b501683601154161760115587517fc4c379cd0000000000000000000000000000000000000000000000000000000080825260198b83015287828881865afa918215612f6d578c9261318e575b5075ffff000000000000000000000000000000000000000084549260a01b1690817fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff84161785558a51908152601a8c82015288818981875afa908115613184577fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9177ffff00000000000000000000000000000000000000000000918f91613157575b5060b01b1692161717825587517f42ab14dd0000000000000000000000000000000000000000000000000000000090818152601d8b82015287818881865afa908115612f6d578c9161312a575b506007558851908152601e8a82015286818781855afa908115612df7578b916130fd575b5060085585600f868b8b5194859384928a84528301525afa9081156130f3578a916130be575b5060015487821690848982168303612fac575b5050505085895416875184815260108a82015286818781855afa908115612df7578b91612f77575b50876002549116908881168203612e7a575b50505085895416875184815260128a82015286818781855afa908115612df7578b91612e45575b50866013878c8c5195869384928b84528301525afa918215612df757918793918c95938692612e01575b50878c8b6005549316928c81168403612d6d575b505050508882549116928982168403612ce9575b50505050908590541691838751809481938252600c8b8301525afa908115612cdf57908392918891612ca4575b5090818560019316612c95575b50875496865195869384927ff2aac76c00000000000000000000000000000000000000000000000000000000845283015288165afa928315612c8c57509174ff0000000000000000000000000000000000000000917fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff938692612c6f575b5050151560a01b169116179055565b612c859250803d10610cd857610cca81836122c7565b3880612c60565b513d86823e3d90fd5b612c9e90613336565b38612be2565b8381939492503d8311612cd8575b612cbc81836122c7565b810103126110d8578291612cd1600192612306565b9091612bd5565b503d612cb2565b85513d89823e3d90fd5b839116179055848851809481937f1a33757d00000000000000000000000000000000000000000000000000000000835260028d8401525af18015612d6357908491612d3a575b908180808b94612ba8565b813d8311612d5c575b612d4d81836122c7565b8101031261190e578238612d2f565b503d612d43565b86513d8a823e3d90fd5b978387600295979996989a16176005558d5195869485937f1a33757d0000000000000000000000000000000000000000000000000000000085528401525af18015612df757918793918c9593612dc6575b878c82612b94565b9093809295503d8311612df0575b612dde81836122c7565b8101031261190e578992869238612dbe565b503d612dd4565b89513d8d823e3d90fd5b929483919496508092503d8311612e3e575b612e1d81836122c7565b81010312612e3a57918a9391612e338894612306565b9038612b80565b8a80fd5b503d612e13565b90508681813d8311612e73575b612e5c81836122c7565b81010312612e3a57612e6d90612306565b38612b56565b503d612e52565b8185821617600255876011888d8d5196879384928c84528301525afa928315612f6d57908c918294612f2f575b50898c541615612eb8575b50612b2f565b161790813b15612e3a57908a88878c94838d5195869485937f36b91f2b0000000000000000000000000000000000000000000000000000000085521680988401525af18015612df757908b91612f1b575b50508289541617885538808a81612eb2565b612f2490612297565b610c9c578938612f09565b89809295508193503d8311612f66575b612f4981836122c7565b81010312612f6257612f5b8c91612306565b9238612ea7565b8b80fd5b503d612f3f565b8a513d8e823e3d90fd5b90508681813d8311612fa5575b612f8e81836122c7565b81010312612e3a57612f9f90612306565b38612b1d565b503d612f84565b16811760015588517ffe9fbb80000000000000000000000000000000000000000000000000000000008152308b82015287818881855afa908115612f6d578c916130a1575b50612ffe575b8084612af5565b803b15612e3a578a80918b8b51809481937f4e606c470000000000000000000000000000000000000000000000000000000083525af18015612df75761308e575b50898091895182898201917ff098767a0000000000000000000000000000000000000000000000000000000083528d815261307981612265565b51925af150613086613306565b503880612ff7565b61309a909a919a612297565b983861303f565b6130b89150883d8a11610cd857610cca81836122c7565b38612ff1565b90508581813d83116130ec575b6130d581836122c7565b81010312610c9c576130e690612306565b38612ae2565b503d6130cb565b88513d8c823e3d90fd5b90508681813d8311613123575b61311481836122c7565b81010312612e3a575138612abc565b503d61310a565b90508781813d8311613150575b61314181836122c7565b81010312612f62575138612a98565b503d613137565b61317791508b3d8d1161317d575b61316f81836122c7565b8101906127e7565b38612a4b565b503d613165565b8b513d8f823e3d90fd5b6131a6919250883d8a1161317d5761316f81836122c7565b90386129a8565b809250888092503d83116131de575b6131c681836122c7565b81010312612e3a576131d88891612306565b3861295c565b503d6131bc565b809250878092503d8311613216575b6131fe81836122c7565b81010312610c9c576132108791612306565b3861292b565b503d6131f4565b809250878092503d831161324e575b61323681836122c7565b81010312610c9c576132488791612306565b386128fe565b503d61322c565b809250878092503d8311613286575b61326e81836122c7565b81010312610c9c576132808791612306565b386128d0565b503d613264565b809250878092503d83116132be575b6132a681836122c7565b81010312610c9c576132b88791612306565b386128a2565b503d61329c565b9091508481813d83116132f5575b6132dd81836122c7565b81010312610d3a576132ee90612306565b903861285d565b503d6132d3565b87513d8b823e3d90fd5b3d15613331573d90613317826122ea565b9161332560405193846122c7565b82523d6000602084013e565b606090565b6001600160a01b0380911690811561345557806001541615613451576003548116806133f05750308203613387575b505b73ffffffffffffffffffffffffffffffffffffffff196003541617600355565b60015416803b1561190e57600080916024604051809481937feb8646980000000000000000000000000000000000000000000000000000000083528760048401525af180156133e45715613365576133de90612297565b38613365565b6040513d6000823e3d90fd5b8091503b1561190e57600080916024604051809481937f3a74bfd70000000000000000000000000000000000000000000000000000000083528760048401525af180156133e457613442575b50613367565b61344b90612297565b3861343c565b5050565b60046040517f05d8ce3d000000000000000000000000000000000000000000000000000000008152fd5b906134be575080511561349457805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580613509575b6134cf575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156134c756fea2646970667358221220eac657888a11f945c3d28c1cfa635e6a3c73413502330d3e631155e87a61258464736f6c63430008190033
Deployed Bytecode
0x608080604052600436101561001357600080fd5b600090813560e01c9081630659b1881461209e5750806312c3448b14611ba357806326342d0b14611a6857806331a0edec14611a415780633cdad82c14611a1a578063443b1786146119f45780634b03eeb4146117eb5780634f1ef2861461148757806352d1902d146113f257806362eb1e22146111f35780636d6aa5bb14610d8e57806375eeac141461092a5780638da52e93146108d6578063ad3cb1cc1461083f578063ad5c464814610818578063b930b482146107f1578063c4d66de814610500578063f1f5852514610144578063f63ed21e146101265763fce14af6146100fd57600080fd5b3461012357806003193601126101235760206001600160a01b0360015416604051908152f35b80fd5b50346101235780600319360112610123576020600a54604051908152f35b5034610123576020806003193601126104fc576004359060ff835460a01c166104d25782610171336125a0565b50916001600160a01b039384600d5416803b1561045857836040518092631abb7b0b60e01b825288881660048301528160249a8b925af180156104c7579084916104af575b50506101c1336125a0565b509480600c54166040517f6352211e00000000000000000000000000000000000000000000000000000000815283600482015284818a81855afa9081156104a457869161046b575b50823091160361041a57803b15610467576040517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0388166024820152604481018490529085908290606490829084905af1801561045c57908591610444575b5050610284828761268e565b96901561041a5716938484526009916009845260408520547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081810190811198895b610407578181101561037257888852858752604088206001908183019081841161035f57906102f5916123f5565b50908a8a5287895261030a8360408c206123f5565b91909161034d57908291600194938203610329575b50505001896102c7565b8063ffffffff9284548155019201541663ffffffff1982541617905538808061031f565b8d8b634e487b7160e01b815280600452fd5b8d8b634e487b7160e01b81526011600452fd5b8688868b878f88838652600987526040862090815480156103f457019161039983836123f5565b9190916103e35750917ffdcb4d15d6978e5c2ea4fac76eeaa6a98e65ca72c0ec349ed335f4cc61f744b4939187600185826103e09b9c9755015555604051908152a261270b565b80f35b87634e487b7160e01b815280600452fd5b8388634e487b7160e01b81526031600452fd5b8a88634e487b7160e01b81526011600452fd5b60046040517f4df67f2d000000000000000000000000000000000000000000000000000000008152fd5b61044d90612297565b610458578338610278565b8380fd5b6040513d87823e3d90fd5b8480fd5b90508481813d831161049d575b61048281836122c7565b810103126104995761049390612306565b38610209565b8580fd5b503d610478565b6040513d88823e3d90fd5b6104b890612297565b6104c35782386101b6565b8280fd5b6040513d86823e3d90fd5b60046040517f8f85eea2000000000000000000000000000000000000000000000000000000008152fd5b5080fd5b50346101235760206003193601126101235761051a61224f565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0080549160ff8360401c16159067ffffffffffffffff808516948515806107ea575b600180971490816107e0575b1590816107d7575b50610739577fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009084878383161787556107b8575b5084549260ff8460401c16159383811688811591826107b0575b1490816107a6575b15908161079d575b5061073957848884831617885561077e575b50855460ff8160401c16159381168881159182610776575b14908161076c575b159081610763575b506107395783886001600160a01b0394831617885561071a575b501673ffffffffffffffffffffffffffffffffffffffff198754161786556106db575b61069c575b610652612800565b61065a578280f35b7fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2918168ff00000000000000001960209354169055604051908152a138808280f35b68ff00000000000000001982541682557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d26020604051858152a161064a565b68ff00000000000000001983541683557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d26020604051868152a1610645565b68ffffffffffffffffff19166801000000000000000117865538610622565b60046040517ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b90501538610608565b303b159150610600565b8692506105f8565b68ffffffffffffffffff191668010000000000000001178655386105e0565b905015386105ce565b303b1591506105c6565b8792506105be565b68ffffffffffffffffff191668010000000000000001178555386105a4565b90501538610570565b303b159150610568565b508361055c565b503461012357806003193601126101235760206001600160a01b0360025416604051908152f35b503461012357806003193601126101235760206001600160a01b0360065416604051908152f35b503461012357806003193601126101235760405161085c81612265565b6005815260207f352e302e30000000000000000000000000000000000000000000000000000000602083015260405192839160208352835193846020850152825b8581106108bf57505050601f83601f1992604080968601015201168101030190f35b81810183015187820160400152869450820161089d565b50346101235780600319360112610123576001600160a01b038154163303610900576103e0612800565b60046040517fe1010280000000000000000000000000000000000000000000000000000000008152fd5b503461012357602090816003193601126101235760043560ff825460a01c166104d257610956336125a0565b50906001600160a01b039081600d5416803b15610467578490816040518092631abb7b0b60e01b825286881660048301528160249586925af180156104a457908691610d7a575b505060018210610d50576109b0336125a0565b9084600c5416906040517f6352211e00000000000000000000000000000000000000000000000000000000815285600482015289818681865afa908115610d45579087918a91610d09575b508183169788911603610cdf576040517fe985e9c500000000000000000000000000000000000000000000000000000000815287600482015230868201528a81604481875afa908115610ca7578a91610cb2575b50159081610c1d575b50610bf357813b15610bef576040517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b03919091166004820152306024820152604481018590529087908290606490829084905af18015610be457908791610bd0575b508490526009875261ffff60806040882054920151161115610ba65782855260098652604085209063ffffffff90604051610afe81612265565b84815288810193834216855280549068010000000000000000821015610b935790610b2e916001820181556123f5565b929092610b8257509160016103e0989994927f821585ec6e57e9f9456596c323af52550f2edd5b3ac8b1c541727e2f89acba3296945181550191511663ffffffff19825416179055604051908152a261270b565b88634e487b7160e01b815280600452fd5b838a634e487b7160e01b81526041600452fd5b60046040517f141091bc000000000000000000000000000000000000000000000000000000008152fd5b610bd990612297565b610499578538610ac4565b6040513d89823e3d90fd5b8780fd5b60046040517f6a307d79000000000000000000000000000000000000000000000000000000008152fd5b9050604051907f081812fc0000000000000000000000000000000000000000000000000000000082528660048301528a828781875afa918215610ca7578a92610c6c575b501630141538610a58565b9091508a81813d8311610ca0575b610c8481836122c7565b81010312610c9c57610c9590612306565b9038610c61565b8980fd5b503d610c7a565b6040513d8c823e3d90fd5b610cd291508b3d8d11610cd8575b610cca81836122c7565b810190612588565b38610a4f565b503d610cc0565b60046040517f18bbd964000000000000000000000000000000000000000000000000000000008152fd5b8092508b8092503d8311610d3e575b610d2281836122c7565b81010312610d3a57610d348791612306565b386109fb565b8880fd5b503d610d18565b6040513d8b823e3d90fd5b60046040517f7ac5e436000000000000000000000000000000000000000000000000000000008152fd5b610d8390612297565b61046757843861099d565b503461012357604060031936011261012357600435602480359060ff845460a01c166104d257610dbd336125a0565b50916001600160a01b03908582600d5416803b156104fc578180918660405180948193631abb7b0b60e01b8352898c1660048401525af180156110a5576111df575b5050610e0a336125a0565b929060a084019384518481106111af5750610e25888361268e565b5015611185576010546040517fc04907220000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602481018a905295906020908790604490829088165afa958615610ca7578a96611151575b508585028a8612967f80000000000000000000000000000000000000000000000000000000000000008114881661113e57868205148615171561112b57670de0b6b3a764000090059584600e541660405191634378a6e360e01b83528b60048401526080838b81855afa928315611120578d936110ef575b508888019089821280158216911516176110dc5790610f2683928e9897969594516124bc565b8252803b156110d857604080517fd4e403b8000000000000000000000000000000000000000000000000000000008152600481018e905283516024820152602084015161ffff908116604483015291840151909116606482015260609092015160848301528690829060a490829084905af19081156104a45786916110c4575b5050610fb386825161257b565b905282600f5416803b1561046757610fe68592918392604051948580948193630bcaacd960e21b835289600484016124f2565b03925af19081156104c75784916110b0575b5050816011541690813b156104585760448985809460405196879586947fc7301a84000000000000000000000000000000000000000000000000000000008652600486015216809b8401525af180156110a557611091575b50506103e0947f4cf5773b4c75ae2ed0de627f7f8bfdb27407d753f74feb57fb859fb0f8eec4c99260609260405192835260208301526040820152a261270b565b61109a90612297565b610499578538611050565b6040513d84823e3d90fd5b6110b990612297565b6104c3578238610ff8565b6110cd90612297565b610467578438610fa6565b8680fd5b898d634e487b7160e01b81526011600452fd5b61111291935060803d608011611119575b61110a81836122c7565b81019061245f565b9138610f00565b503d611100565b6040513d8f823e3d90fd5b878b634e487b7160e01b81526011600452fd5b888c634e487b7160e01b81526011600452fd5b9095506020813d60201161117d575b8161116d602093836122c7565b81010312610c9c57519438610e88565b3d9150611160565b60046040517f693f635f000000000000000000000000000000000000000000000000000000008152fd5b8690604051907fa369efb60000000000000000000000000000000000000000000000000000000082526004820152fd5b6111e890612297565b610499578538610dff565b50346101235760206003193601126101235760043560ff81168091036104fc5760ff825460a01c166104d257611228336125a0565b9160085480156113c8576080840161ffff9485825116928660065460b01c1684101561139e5784611258916124df565b93876001600160a01b039586600d5416803b156104c3576040517f918d24280000000000000000000000000000000000000000000000000000000081526001600160a01b038a166004820152602481019290925282908290604490829084905af180156110a55761138a575b50508683511601868111611376579086889216835284600f5416803b156104c35761130a8392918392604051948580948193630bcaacd960e21b83528d600484016124f2565b03925af180156110a55761135a575b507f19dd07f4ceafd05150e1d94374a580ecb781172acb3a528da61f6a41d5f03fa460608686868a875116916040519316835260208301526040820152a180f35b611368909594939295612297565b610499579091928538611319565b602488634e487b7160e01b81526011600452fd5b61139390612297565b610bef5787386112c4565b60046040517fc460755e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fa303b7dd000000000000000000000000000000000000000000000000000000008152fd5b50346101235780600319360112610123576001600160a01b037f0000000000000000000000008d4ce02f9166f05bd7a7da90acfcbdc6c26b76a716300361145d5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b60046040517fe07c8dba000000000000000000000000000000000000000000000000000000008152fd5b5060406003193601126101235761149c61224f565b602491823567ffffffffffffffff81116104fc57366023820112156104fc578060040135926114ca846122ea565b6114d760405191826122c7565b848152602094858201933688838301011161049957818692898993018737830101526001600160a01b03807f0000000000000000000000008d4ce02f9166f05bd7a7da90acfcbdc6c26b76a7168030149081156117bd575b5061145d57868682875416604051928380927fd91078070000000000000000000000000000000000000000000000000000000082528a60048301525afa9081156104a4579082918791611785575b5016330361175b57821694604051907f52d1902d00000000000000000000000000000000000000000000000000000000825280826004818a5afa918291879361172b575b50506115f7578686604051907f4c9c8ce30000000000000000000000000000000000000000000000000000000082526004820152fd5b8590877f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc918281036116fd5750843b156116ce5750805473ffffffffffffffffffffffffffffffffffffffff1916821790556040518592917fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a281511561169857506116949382915190845af461168e613306565b9161347f565b5080f35b9350505050346116a6575080f35b807fb398979f0000000000000000000000000000000000000000000000000000000060049252fd5b82604051907f4c9c8ce30000000000000000000000000000000000000000000000000000000082526004820152fd5b604051907faa1d49a40000000000000000000000000000000000000000000000000000000082526004820152fd5b9080929350813d8311611754575b61174381836122c7565b8101031261049957519038806115c1565b503d611739565b60046040517ff7aa0316000000000000000000000000000000000000000000000000000000008152fd5b809250888092503d83116117b6575b61179e81836122c7565b81010312610499576117b08291612306565b3861157d565b503d611794565b9050817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541614153861152f565b50346101235760406003193601126101235761180561224f565b6001600160a01b0380835416604051927fbcaa0c5500000000000000000000000000000000000000000000000000000000808552600c60048601526020948581602481875afa8015610be457859188916119bc575b5016801561198b5733036119615784906024604051809581938252600c60048301525afa801561045c5784928691611925575b506040517faad3ec960000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024803590820152928391908290879082604481015b0393165af1801561191a576118ed578280f35b813d8311611913575b61190081836122c7565b8101031261190e5738808280f35b600080fd5b503d6118f6565b6040513d85823e3d90fd5b8381939492503d831161195a575b61193d81836122c7565b810103126104675783916119536118da92612306565b909161188d565b503d611933565b60046040517f1a48f084000000000000000000000000000000000000000000000000000000008152fd5b60246040517f92bc2cd0000000000000000000000000000000000000000000000000000000008152600c6004820152fd5b809250878092503d83116119ed575b6119d581836122c7565b810103126110d8576119e78591612306565b3861185a565b503d6119cb565b50346101235780600319360112610123576001600160a01b036020915416604051908152f35b503461012357806003193601126101235760206001600160a01b0360035416604051908152f35b503461012357806003193601126101235760206001600160a01b0360055416604051908152f35b503461012357602090816003193601126101235790611a8561224f565b9180926001600160a01b0380911682526009835260408220928354611aa9816123dd565b94611ab760405196876122c7565b818652845281842084908387015b838310611b7e57505050508291600e5416945b845160ff841690811015611b7557611af0908661244b565b515160405190634378a6e360e01b8252600482015260809081816024818b5afa9182156104a45790611b2e9392918792611b58575b505051906124bc565b9160ff809116908114611b445760010191611ad8565b602484634e487b7160e01b81526011600452fd5b611b6e9250803d106111195761110a81836122c7565b3880611b25565b50604051908152f35b600285600192611b91859c999b9c612427565b81520192019201919097969497611ac5565b503461012357604060031936011261012357611bbd61224f565b60ff825460a01c166104d257611bd2336125a0565b9091611bdd816125a0565b90916001600160a01b0381166001600160a01b0384160361207457611c05906024359061268e565b501561118557602460806001600160a01b03600e541660405192838092634378a6e360e01b8252823560048301525afa9081156104a4578691612055575b506001600160a01b0385166001600160a01b0384161461202b5760608101516154608101809111611f8f57421061200157610e1063ffffffff6020860151160163ffffffff8111611f8f5763ffffffff42911611611fd757602460206001600160a01b0360105416604051928380927fdf89ff780000000000000000000000000000000000000000000000000000000082526001600160a01b038b1660048301525afa8015610be4578790611fa3575b611d159150670de0b6b3a7640000611d0e60075492836124df565b04906124bc565b9384600581020460051485151715611f8f57600b6005860204670de0b6b3a76400008082028290041490151715611f8f57600685028581046006148615171561137657600b90049283670de0b6b3a7640000810204670de0b6b3a76400001484151715611376578060a0899201611d97670de0b6b3a7640000870282516124bc565b90526001600160a01b03600f541690813b156104c3578291611dd091604051948580948193630bcaacd960e21b83528c600484016124f2565b03925af18015611f8457611f6f575b50908160a0889301611e02670de0b6b3a7640000600b60058a02040282516124bc565b905263ffffffff4216908160208201526001600160a01b03600f5416803b1561046757611e499185918a83604051809681958294630bcaacd960e21b8452600484016124f2565b03925af19081156104c7578491611f5b575b505060608201526001600160a01b03600e5416803b156104c357604080517fd4e403b8000000000000000000000000000000000000000000000000000000008152602480356004830152845190820152602084015161ffff908116604483015291840151909116606482015260609092015160848301528290829060a490829084905af180156110a557611f47575b50506001600160a01b03807f89689ae04e5ef625e51d8d11b7135e0c63aad6b927fe1826384fc51e0c86a4ec93670de0b6b3a764000060609481600b60056040519a6024358c52020402602089015202604087015216941692a380f35b611f5090612297565b610467578438611eea565b611f6490612297565b6104c3578238611e5b565b611f7c9097919297612297565b959038611ddf565b6040513d8a823e3d90fd5b602487634e487b7160e01b81526011600452fd5b506020813d602011611fcf575b81611fbd602093836122c7565b810103126110d857611d159051611cf3565b3d9150611fb0565b60046040517ff07010d0000000000000000000000000000000000000000000000000000000008152fd5b60046040517faf13d42b000000000000000000000000000000000000000000000000000000008152fd5b60046040517f4bc676a9000000000000000000000000000000000000000000000000000000008152fd5b61206e915060803d6080116111195761110a81836122c7565b38611c43565b60046040517f762b3b47000000000000000000000000000000000000000000000000000000008152fd5b9050346104fc57602090816003193601126104c3576120bb61224f565b90806001600160a01b03928380600f5416917f5c12cd4b0000000000000000000000000000000000000000000000000000000084521660048301528160246101009485935afa91821561045c578592612221575b5050168083526009808352604084205490612129826123dd565b9261213760405194856122c7565b828452601f19612146846123dd565b01865b8181106121f9575050855b8381106121aa57505050506040519180830190808452825180925280604085019301945b8281106121855784840385f35b85518051855282015163ffffffff168483015294810194604090930192600101612178565b600190828896985283875263ffffffff876121d16121cb8460408b206123f5565b50612427565b80516121dd858d61244b565b5152015116876121ed838b61244b565b51015201959395612154565b869060409896985161220a81612265565b878152878382015282828b01015201969496612149565b6122409250803d10612248575b61223881836122c7565b81019061233a565b50388061210f565b503d61222e565b600435906001600160a01b038216820361190e57565b6040810190811067ffffffffffffffff82111761228157604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff811161228157604052565b60e0810190811067ffffffffffffffff82111761228157604052565b90601f601f19910116810190811067ffffffffffffffff82111761228157604052565b67ffffffffffffffff811161228157601f01601f191660200190565b51906001600160a01b038216820361190e57565b519063ffffffff8216820361190e57565b519061ffff8216820361190e57565b8092910391610100831261190e5760e0601f1961235683612306565b94011261190e576040519061236a826122ab565b6123766020820161231a565b82526123846040820161231a565b60208301526123956060820161231a565b60408301526080810151600681101561190e576123d59160e09160608501526123c060a0820161232b565b608085015260c081015160a085015201612306565b60c082015290565b67ffffffffffffffff81116122815760051b60200190565b80548210156124115760005260206000209060011b0190600090565b634e487b7160e01b600052603260045260246000fd5b9060405161243481612265565b602063ffffffff6001839580548552015416910152565b80518210156124115760209160051b010190565b9081608091031261190e5760405190608082019082821067ffffffffffffffff831117612281576060916040528051835261249c6020820161232b565b60208401526124ad6040820161232b565b60408401520151606082015290565b919082018092116124c957565b634e487b7160e01b600052601160045260246000fd5b818102929181159184041417156124c957565b9092916101008201936001600160a01b03809116835263ffffffff8083511660208501528060208401511660408501526040830151166060840152606082015160068110156125655760e09260c091608086015261ffff60808201511660a086015260a081015182860152015116910152565b634e487b7160e01b600052602160045260246000fd5b919082039182116124c957565b9081602091031261190e5751801515810361190e5790565b9060c0906040516125b0816122ab565b60009281848093528260208201528260408201528260608201528260808201528260a082015201526001600160a01b039283600f54166040519485927f5c12cd4b0000000000000000000000000000000000000000000000000000000084521660048301528160246101009687935afa93841561191a57839461266b575b505063ffffffff83929351161561264157565b60046040517f3e3a049f000000000000000000000000000000000000000000000000000000008152fd5b80919294506126869350903d106122485761223881836122c7565b91388061262e565b90916000926000906001600160a01b03829416918281526009906020916009602052604092604083205495835b8781106126cd575b5050505050505050565b8185528383526126df818787206123f5565b505487146126ef576001016126bb565b99505050505050505090506001919038808080808080806126c3565b906001600160a01b0380921691600092808452602092600b60205260409160408620549186928795600e5416935b8389526009885285892080548810156127ac5787612756916123f5565b5054865190634378a6e360e01b8252600482015260809081816024818a5afa918b83156127a15792612797926009959260019592611b5857505051906124bc565b9701969050612739565b8951903d90823e3d90fd5b50965094509590859350604092508152600b60205220558181036127ce575050565b6127dd6127e292600a546124bc565b61257b565b600a55565b9081602091031261190e57518060010b810361190e5790565b60006001600160a01b03808254169060409081517fbcaa0c55000000000000000000000000000000000000000000000000000000009384825260049460038684015260209260249284828581845afa9182156132fc5789926132c5575b508573ffffffffffffffffffffffffffffffffffffffff19921682600f541617600f558651838152888082015285818681855afa9081156130f3579087918b9161328d575b501682600d541617600d558651838152600a8982015285818681855afa9081156130f3579087918b91613255575b501682600c541617600c55865183815260158982015285818681855afa9081156130f3579087918b9161321d575b501682600e541617600e558651838152858982015285818681855afa9081156130f3579087918b916131e5575b5016826010541617601055865190838252600691828a82015286818781855afa908115612df7579088918c916131ad575b501683601154161760115587517fc4c379cd0000000000000000000000000000000000000000000000000000000080825260198b83015287828881865afa918215612f6d578c9261318e575b5075ffff000000000000000000000000000000000000000084549260a01b1690817fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff84161785558a51908152601a8c82015288818981875afa908115613184577fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9177ffff00000000000000000000000000000000000000000000918f91613157575b5060b01b1692161717825587517f42ab14dd0000000000000000000000000000000000000000000000000000000090818152601d8b82015287818881865afa908115612f6d578c9161312a575b506007558851908152601e8a82015286818781855afa908115612df7578b916130fd575b5060085585600f868b8b5194859384928a84528301525afa9081156130f3578a916130be575b5060015487821690848982168303612fac575b5050505085895416875184815260108a82015286818781855afa908115612df7578b91612f77575b50876002549116908881168203612e7a575b50505085895416875184815260128a82015286818781855afa908115612df7578b91612e45575b50866013878c8c5195869384928b84528301525afa918215612df757918793918c95938692612e01575b50878c8b6005549316928c81168403612d6d575b505050508882549116928982168403612ce9575b50505050908590541691838751809481938252600c8b8301525afa908115612cdf57908392918891612ca4575b5090818560019316612c95575b50875496865195869384927ff2aac76c00000000000000000000000000000000000000000000000000000000845283015288165afa928315612c8c57509174ff0000000000000000000000000000000000000000917fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff938692612c6f575b5050151560a01b169116179055565b612c859250803d10610cd857610cca81836122c7565b3880612c60565b513d86823e3d90fd5b612c9e90613336565b38612be2565b8381939492503d8311612cd8575b612cbc81836122c7565b810103126110d8578291612cd1600192612306565b9091612bd5565b503d612cb2565b85513d89823e3d90fd5b839116179055848851809481937f1a33757d00000000000000000000000000000000000000000000000000000000835260028d8401525af18015612d6357908491612d3a575b908180808b94612ba8565b813d8311612d5c575b612d4d81836122c7565b8101031261190e578238612d2f565b503d612d43565b86513d8a823e3d90fd5b978387600295979996989a16176005558d5195869485937f1a33757d0000000000000000000000000000000000000000000000000000000085528401525af18015612df757918793918c9593612dc6575b878c82612b94565b9093809295503d8311612df0575b612dde81836122c7565b8101031261190e578992869238612dbe565b503d612dd4565b89513d8d823e3d90fd5b929483919496508092503d8311612e3e575b612e1d81836122c7565b81010312612e3a57918a9391612e338894612306565b9038612b80565b8a80fd5b503d612e13565b90508681813d8311612e73575b612e5c81836122c7565b81010312612e3a57612e6d90612306565b38612b56565b503d612e52565b8185821617600255876011888d8d5196879384928c84528301525afa928315612f6d57908c918294612f2f575b50898c541615612eb8575b50612b2f565b161790813b15612e3a57908a88878c94838d5195869485937f36b91f2b0000000000000000000000000000000000000000000000000000000085521680988401525af18015612df757908b91612f1b575b50508289541617885538808a81612eb2565b612f2490612297565b610c9c578938612f09565b89809295508193503d8311612f66575b612f4981836122c7565b81010312612f6257612f5b8c91612306565b9238612ea7565b8b80fd5b503d612f3f565b8a513d8e823e3d90fd5b90508681813d8311612fa5575b612f8e81836122c7565b81010312612e3a57612f9f90612306565b38612b1d565b503d612f84565b16811760015588517ffe9fbb80000000000000000000000000000000000000000000000000000000008152308b82015287818881855afa908115612f6d578c916130a1575b50612ffe575b8084612af5565b803b15612e3a578a80918b8b51809481937f4e606c470000000000000000000000000000000000000000000000000000000083525af18015612df75761308e575b50898091895182898201917ff098767a0000000000000000000000000000000000000000000000000000000083528d815261307981612265565b51925af150613086613306565b503880612ff7565b61309a909a919a612297565b983861303f565b6130b89150883d8a11610cd857610cca81836122c7565b38612ff1565b90508581813d83116130ec575b6130d581836122c7565b81010312610c9c576130e690612306565b38612ae2565b503d6130cb565b88513d8c823e3d90fd5b90508681813d8311613123575b61311481836122c7565b81010312612e3a575138612abc565b503d61310a565b90508781813d8311613150575b61314181836122c7565b81010312612f62575138612a98565b503d613137565b61317791508b3d8d1161317d575b61316f81836122c7565b8101906127e7565b38612a4b565b503d613165565b8b513d8f823e3d90fd5b6131a6919250883d8a1161317d5761316f81836122c7565b90386129a8565b809250888092503d83116131de575b6131c681836122c7565b81010312612e3a576131d88891612306565b3861295c565b503d6131bc565b809250878092503d8311613216575b6131fe81836122c7565b81010312610c9c576132108791612306565b3861292b565b503d6131f4565b809250878092503d831161324e575b61323681836122c7565b81010312610c9c576132488791612306565b386128fe565b503d61322c565b809250878092503d8311613286575b61326e81836122c7565b81010312610c9c576132808791612306565b386128d0565b503d613264565b809250878092503d83116132be575b6132a681836122c7565b81010312610c9c576132b88791612306565b386128a2565b503d61329c565b9091508481813d83116132f5575b6132dd81836122c7565b81010312610d3a576132ee90612306565b903861285d565b503d6132d3565b87513d8b823e3d90fd5b3d15613331573d90613317826122ea565b9161332560405193846122c7565b82523d6000602084013e565b606090565b6001600160a01b0380911690811561345557806001541615613451576003548116806133f05750308203613387575b505b73ffffffffffffffffffffffffffffffffffffffff196003541617600355565b60015416803b1561190e57600080916024604051809481937feb8646980000000000000000000000000000000000000000000000000000000083528760048401525af180156133e45715613365576133de90612297565b38613365565b6040513d6000823e3d90fd5b8091503b1561190e57600080916024604051809481937f3a74bfd70000000000000000000000000000000000000000000000000000000083528760048401525af180156133e457613442575b50613367565b61344b90612297565b3861343c565b5050565b60046040517f05d8ce3d000000000000000000000000000000000000000000000000000000008152fd5b906134be575080511561349457805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580613509575b6134cf575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156134c756fea2646970667358221220eac657888a11f945c3d28c1cfa635e6a3c73413502330d3e631155e87a61258464736f6c63430008190033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.