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:
ClaimManager
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 "../interfaces/IClaimManager.sol";
import "../interfaces/IMunchToken.sol";
import "../interfaces/IAccountManager.sol";
import "../interfaces/IConfigStorage.sol";
import "../interfaces/IBonusManager.sol";
import "./BaseBlastManagerUpgradeable.sol";
import "../interfaces/ISnuggeryManager.sol";
contract ClaimManager is IClaimManager, BaseBlastManagerUpgradeable {
uint256[] POINTS_PER_MIGRATED_NFT;
uint256 POINTS_PER_UNREVEALED_NFT;
Period public currentPeriod;
uint256 public pointsPerPeriod;
IAccountManager accountManager;
ISnuggeryManager snuggeryManager;
IBonusManager bonusManager;
IMunchToken munchToken;
bool _swapEnabled;
uint256 _pointsPerToken;
mapping(address => uint32) _lastClaimPeriod;
mapping(uint32 => uint256) _pointsExcess;
mapping(address => uint256) _points;
modifier onlyValidPeriod() {
if (
(currentPeriod.id != 0 &&
uint32(block.timestamp) > currentPeriod.endTime) ||
uint32(block.timestamp) < currentPeriod.startTime
)
revert InvalidPeriodError(
uint32(block.timestamp),
currentPeriod.startTime,
currentPeriod.endTime
);
_;
}
modifier onlySwappable() {
if (!_swapEnabled) revert SwapDisabledError();
_;
}
constructor() {
_disableInitializers();
}
function initialize(address _configStorage) public override initializer {
BaseBlastManagerUpgradeable.initialize(_configStorage);
_reconfigure();
}
function _reconfigure() internal {
accountManager = IAccountManager(
configStorage.getAddress(StorageKey.AccountManager)
);
bonusManager = IBonusManager(
configStorage.getAddress(StorageKey.BonusManager)
);
snuggeryManager = ISnuggeryManager(
configStorage.getAddress(StorageKey.SnuggeryManager)
);
munchToken = IMunchToken(
configStorage.getAddress(StorageKey.MunchToken)
);
pointsPerPeriod = configStorage.getUint(StorageKey.PointsPerPeriod);
_pointsPerToken = configStorage.getUint(StorageKey.PointsPerToken);
_swapEnabled = configStorage.getBool(StorageKey.SwapEnabled);
POINTS_PER_MIGRATED_NFT = configStorage.getUintArray(
StorageKey.PointsPerMigratedNFT
);
POINTS_PER_UNREVEALED_NFT = configStorage.getUint(
StorageKey.PointsPerUnrevealedNFT
);
super.__BaseBlastManagerUpgradeable_reconfigure();
}
function configUpdated() external override onlyConfigStorage {
_reconfigure();
}
function transferPlayerPoints(
address _from,
address _to
) external override onlyConfiguredContract(StorageKey.AccountManager) {
uint256 tempPoints = _points[_from];
_points[_from] = 0;
_points[_to] = tempPoints;
_lastClaimPeriod[_to] = _lastClaimPeriod[_from];
}
function newPeriod() external override notPaused onlyRole(Role.NewPeriod) {
if (
currentPeriod.endTime != 0 &&
uint32(block.timestamp) < currentPeriod.endTime
) revert CurrentPeriodNotEndedError();
uint256 prevPeriodClaimed = currentPeriod.claimed;
currentPeriod.id++;
uint32 _currentPeriodId = currentPeriod.id;
uint256 _excess;
if (currentPeriod.claimed <= currentPeriod.available) {
_excess = currentPeriod.available - currentPeriod.claimed;
}
_pointsExcess[_currentPeriodId] = _excess;
currentPeriod.startTime = uint32(block.timestamp);
currentPeriod.endTime = uint32(block.timestamp + 1 days);
currentPeriod.available = pointsPerPeriod;
currentPeriod.claimed = 0;
currentPeriod.globalTotalChonk = snuggeryManager.getGlobalTotalChonk();
emit NewPeriodStarted(
_currentPeriodId,
currentPeriod.startTime,
currentPeriod.endTime,
currentPeriod.available,
prevPeriodClaimed,
_excess,
currentPeriod.globalTotalChonk
);
}
function burnNFTsForPoints(
address _player,
uint8[] memory _tokenIdsByRarity
)
external
override
onlyConfiguredContract(StorageKey.MigrationManager)
returns (uint256 _receivedPoints)
{
uint256 totalPoints;
for (uint8 i; i < _tokenIdsByRarity.length; i++) {
totalPoints += (_tokenIdsByRarity[i] * POINTS_PER_MIGRATED_NFT[i]);
}
_points[_player] += totalPoints;
_receivedPoints = totalPoints;
emit NFTsBurnedForPoints(_player, _tokenIdsByRarity, totalPoints);
}
function burnUnrevealedForPoints(
address _player,
uint256 _unrevealed
)
external
override
onlyConfiguredContract(StorageKey.MigrationManager)
returns (uint256 _receivedPoints)
{
uint256 totalPoints = POINTS_PER_UNREVEALED_NFT * _unrevealed;
_points[_player] += totalPoints;
_receivedPoints = totalPoints;
emit UnrevealedSwappedForPoints(_player, _unrevealed, totalPoints);
}
function claimPoints() external override onlyValidPeriod {
address mainAccount = accountManager.getMainAccount(msg.sender);
_claimPoints(mainAccount);
}
/// @inheritdoc IClaimManager
function forceClaimPoints(
address _player
)
external
onlyValidPeriod
onlyConfiguredContract(StorageKey.SnuggeryManager)
{
_claimPoints(_player);
}
function spendPoints(
address _player,
uint256 _spendPoints
) external override onlyConfiguredContract(StorageKey.SnuggeryManager) {
if (_points[_player] < _spendPoints) revert NotEnoughPointsError();
_points[_player] -= _spendPoints;
emit PointsSpent(_player, _spendPoints);
}
function convertPointsToTokens(
uint256 _pointsToConvert
) external notPaused onlySwappable {
uint256 _pointsAvailable = _points[msg.sender];
if (_pointsToConvert == 0 || _pointsAvailable == 0)
revert NoClaimablePointsError();
if (_pointsAvailable < _pointsToConvert) revert NotEnoughPointsError();
if (_pointsPerToken == 0) revert PointsPerTokenNotSetError();
uint256 _tokensToMint = (_pointsToConvert * _pointsPerToken) / 1e12;
if (_tokensToMint == 0) revert PointAmountToSmallError();
_points[msg.sender] -= _pointsToConvert;
munchToken.mint(msg.sender, _tokensToMint);
emit PointsConverted(msg.sender, _pointsToConvert, _tokensToMint);
}
function getCurrentPeriod() external view override returns (Period memory) {
return currentPeriod;
}
function getPoints(
address _player
) external view override returns (uint256) {
return _points[accountManager.getMainAccount(_player)];
}
function _claimPoints(address _player) private {
(, MunchablesCommonLib.Player memory player) = accountManager.getPlayer(
_player
);
uint32 currentPeriodId = currentPeriod.id;
if (_lastClaimPeriod[_player] < currentPeriodId) {
// ignore if previously claimed because check is done for player facing function
uint256 availablePoints = currentPeriod.available +
_pointsExcess[currentPeriodId];
uint256 claimAmount;
if (currentPeriod.globalTotalChonk > 0) {
claimAmount =
(snuggeryManager.getTotalChonk(_player) * availablePoints) /
currentPeriod.globalTotalChonk;
}
if (claimAmount > 0) {
// TODO: Think about ways to keep this within total emission instead of
// adding to the total count
uint256 _referralBonus;
if (player.referrer != address(0)) {
_referralBonus =
(claimAmount * bonusManager.getReferralBonus()) /
1e18;
_points[player.referrer] += _referralBonus;
}
_lastClaimPeriod[_player] = currentPeriodId;
_points[_player] += claimAmount;
currentPeriod.claimed += claimAmount;
emit Claimed(
msg.sender,
_player,
currentPeriodId,
claimAmount,
player.referrer,
_referralBonus
);
}
}
_lastClaimPeriod[_player] = currentPeriodId;
emit ClaimPeriodHit(
_player,
_lastClaimPeriod[_player],
currentPeriod.id
);
}
}// 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);
function transferPlayerPoints(address _from, address _to) external;
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 IMunchToken {
// Temporary...
function mint(address to, uint256 amount) external;
}// 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);
event InitiatedTransfer(address _proposer, address _transferee);
event CancelTransfer(address _proposer, address _transferee);
event ConfirmTransfer(address _proposer, address _transferee);
// 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();
error AccountTransferredError();
error AccountTransferImproperStateError();
error SnuggeryNotEmptyError();
error AccountHasLockedError();
error AccountHasStakedMunchablesError();
}// 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: 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;
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: 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;
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;
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":"AlreadyClaimedError","type":"error"},{"inputs":[],"name":"ContractsPausedError","type":"error"},{"inputs":[],"name":"CurrentPeriodNotEndedError","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":"InvalidGovernorError","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"uint32","name":"_now","type":"uint32"},{"internalType":"uint32","name":"_startTime","type":"uint32"},{"internalType":"uint32","name":"_endTime","type":"uint32"}],"name":"InvalidPeriodError","type":"error"},{"inputs":[],"name":"InvalidRoleError","type":"error"},{"inputs":[],"name":"InvalidSnapshotDataError","type":"error"},{"inputs":[],"name":"NoClaimablePointsError","type":"error"},{"inputs":[],"name":"NoSnapshotDataError","type":"error"},{"inputs":[],"name":"NotAccountManagerError","type":"error"},{"inputs":[],"name":"NotEnoughPointsError","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OnlyStorageError","type":"error"},{"inputs":[],"name":"PointAmountToSmallError","type":"error"},{"inputs":[],"name":"PointsPerTokenNotSetError","type":"error"},{"inputs":[],"name":"SnapshotIsFinalizedError","type":"error"},{"inputs":[],"name":"SnapshotIsNotFinalizedError","type":"error"},{"inputs":[],"name":"SwapDisabledError","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":"address","name":"_oldAccountManager","type":"address"},{"indexed":false,"internalType":"address","name":"_newAccountManager","type":"address"}],"name":"AccountManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_claimModule","type":"address"},{"indexed":false,"internalType":"bool","name":"_isValid","type":"bool"}],"name":"ClaimModuleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_player","type":"address"},{"indexed":false,"internalType":"uint32","name":"_lastClaimPeriod","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_currentPeriod","type":"uint32"}],"name":"ClaimPeriodHit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_sender","type":"address"},{"indexed":true,"internalType":"address","name":"_player","type":"address"},{"indexed":false,"internalType":"uint32","name":"_periodId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"_pointsClaimed","type":"uint256"},{"indexed":true,"internalType":"address","name":"_referrer","type":"address"},{"indexed":false,"internalType":"uint256","name":"_referralBonus","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_oldLockManager","type":"address"},{"indexed":false,"internalType":"address","name":"_newLockManager","type":"address"}],"name":"LockManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_oldMunchToken","type":"address"},{"indexed":false,"internalType":"address","name":"_newMunchToken","type":"address"}],"name":"MunchTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_player","type":"address"},{"indexed":false,"internalType":"uint8[]","name":"_tokenIdsByRarity","type":"uint8[]"},{"indexed":false,"internalType":"uint256","name":"_points","type":"uint256"}],"name":"NFTsBurnedForPoints","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"_periodId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_startTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_endTime","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"_availablePoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_prevPeriodPointsClaimed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_excessPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_totalGlobalChonk","type":"uint256"}],"name":"NewPeriodStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_player","type":"address"},{"indexed":false,"internalType":"uint256","name":"_points","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_tokens","type":"uint256"}],"name":"PointsConverted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newPoints","type":"uint256"}],"name":"PointsPerPeriodSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldPointsPerToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newPointsPerToken","type":"uint256"}],"name":"PointsPerTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_player","type":"address"},{"indexed":false,"internalType":"uint256","name":"_pointsSpent","type":"uint256"}],"name":"PointsSpent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldReferralBonus","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_referralBonus","type":"uint256"}],"name":"ReferralBonusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_enabled","type":"bool"}],"name":"SwapEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_player","type":"address"},{"indexed":false,"internalType":"uint256","name":"_unrevealed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_points","type":"uint256"}],"name":"UnrevealedSwappedForPoints","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_claimModule","type":"address"},{"indexed":false,"internalType":"address","name":"_tokenContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"_yieldClaimed","type":"uint256"}],"name":"YieldClaimed","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":"_player","type":"address"},{"internalType":"uint8[]","name":"_tokenIdsByRarity","type":"uint8[]"}],"name":"burnNFTsForPoints","outputs":[{"internalType":"uint256","name":"_receivedPoints","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"},{"internalType":"uint256","name":"_unrevealed","type":"uint256"}],"name":"burnUnrevealedForPoints","outputs":[{"internalType":"uint256","name":"_receivedPoints","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenContract","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"claimERC20Yield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimPoints","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":"_pointsToConvert","type":"uint256"}],"name":"convertPointsToTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentPeriod","outputs":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"claimed","type":"uint256"},{"internalType":"uint256","name":"globalTotalChonk","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"forceClaimPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getConfiguredGovernor","outputs":[{"internalType":"address","name":"_governor","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentPeriod","outputs":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"claimed","type":"uint256"},{"internalType":"uint256","name":"globalTotalChonk","type":"uint256"}],"internalType":"struct IClaimManager.Period","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"getPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_configStorage","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"newPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pointsPerPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"},{"internalType":"uint256","name":"_spendPoints","type":"uint256"}],"name":"spendPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"}],"name":"transferPlayerPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]Contract Creation Code
60a0806040523460c857306080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff8260401c1660b957506001600160401b036002600160401b0319828216016075575b604051612f9e90816100ce8239608051818181610fad015261109f0152f35b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a13880806056565b63f92ee8a960e01b8152600490fd5b600080fdfe608060408181526004918236101561001657600080fd5b600092833560e01c91826304d092c714611aee575081630604061814611a99578163086146d2146119e25781631abb7b0b1461187a5781631b504564146115f657816331a0edec146115ce5781633cdad82c146115a6578163443b1786146115805781634b03eeb4146113b55781634f1ef2861461102257816352d1902d14610f905781635e11544b14610c535781636455c6fc14610b335781638da52e9314610add578163918d24281461098c578163970567e114610739578163ad3cb1cc146106a7578163ad5c46481461067f578163b930b48214610657578163c4d66de814610365578163cea0ee0c14610346578163e20859fc1461021e578163ee204abb14610157575063fce14af61461012d57600080fd5b346101535781600319360112610153576020906001600160a01b03600154169051908152f35b5080fd5b838334610153576020918260031936011261021b57602483610177611c3a565b6001600160a01b0392839182600e54168751998a9485937f8c93caec00000000000000000000000000000000000000000000000000000000855216908301525afa80156102115782906101d9575b839495501681526015845220549051908152f35b508385813d831161020a575b6101ef8183611cb2565b8101031261015357610202839495611d09565b8594506101c5565b503d6101e5565b83513d84823e3d90fd5b80fd5b91905034610342578060031936011261034257610239611c3a565b91602435926001600160a01b039081851680950361033d5781865416928451809463bcaa0c5560e01b825260038383015281602460209788935afa9081156103335790849189916102f7575b501680156102e05733036102d257509060139291168086526015825283862086815491558587528487205585525263ffffffff818420541691835282209063ffffffff1982541617905580f35b84516306923c2160e21b8152fd5b602482600388519163092bc2cd60e41b8352820152fd5b809250868092503d831161032c575b6103108183611cb2565b81010312610328576103228491611d09565b38610285565b8780fd5b503d610306565b86513d8a823e3d90fd5b600080fd5b8280fd5b505034610153578160031936011261015357602090600d549051908152f35b90503461034257602060031936011261034257610380611c3a565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0091825460ff81861c16159167ffffffffffffffff9081831694851580610650575b60018097149081610646575b15908161063d575b5061062f577fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000938587868316178955610610575b5086549360ff858a1c1615948481168881159182610608575b1490816105fe575b1590816105f5575b506105e6578588838316178a556105c7575b5087549160ff838b1c161594831688811591826105bf575b1490816105b5575b1590816105ac575b5061059e57508116861787556001600160a01b0391908361057f575b501673ffffffffffffffffffffffffffffffffffffffff19885416178755610541575b610503575b6104ba6121d5565b6104c2578380f35b7fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2928268ff0000000000000000196020945416905551908152a13880808380f35b68ff00000000000000001983541683557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d260208551848152a16104b2565b68ff00000000000000001984541684557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d260208651858152a16104ad565b68ffffffffffffffffff1916680100000000000000011787553861048a565b895163f92ee8a960e01b8152fd5b9050153861046e565b303b159150610466565b87925061045e565b68ffffffffffffffffff19166801000000000000000117885538610446565b828a5163f92ee8a960e01b8152fd5b90501538610434565b303b15915061042c565b889250610424565b68ffffffffffffffffff1916680100000000000000011787553861040b565b875163f92ee8a960e01b8152fd5b905015386103d7565b303b1591506103cf565b50846103c3565b5050346101535781600319360112610153576020906001600160a01b03600254169051908152f35b5050346101535781600319360112610153576020906001600160a01b03600654169051908152f35b50503461015357816003193601126101535780516106c481611c96565b600581526020907f352e302e300000000000000000000000000000000000000000000000000000006020820152825193849260208452825192836020860152825b84811061072357505050828201840152601f01601f19168101030190f35b8181018301518882018801528795508201610705565b919050346103425760206003193601126103425781359160ff845460a01c166109655760ff60115460a01c161561093e5733845260156020528184205483158015610936575b61090e5783116108e75760125480156108bf576107a264e8d4a510009185611d1d565b049081156108985733855260156020528285206107c0858254611d53565b9055846001600160a01b036011541691823b156101535784517f40c10f19000000000000000000000000000000000000000000000000000000008152339181019182526020820185905292839182908490829060400103925af1801561088e57610859575b50907f6458c94e9777bbc30aee6f0b0a4509d5a7789f8cdfdedb960debd3573997540d91815193845260208401523392a280f35b936108867f6458c94e9777bbc30aee6f0b0a4509d5a7789f8cdfdedb960debd3573997540d939295611c82565b939091610825565b83513d87823e3d90fd5b82517f83231208000000000000000000000000000000000000000000000000000000008152fd5b5090517f8a9422f4000000000000000000000000000000000000000000000000000000008152fd5b90517f71b8d54c000000000000000000000000000000000000000000000000000000008152fd5b5090517f300583e8000000000000000000000000000000000000000000000000000000008152fd5b50801561077f565b90517f655c1656000000000000000000000000000000000000000000000000000000008152fd5b90517f8f85eea2000000000000000000000000000000000000000000000000000000008152fd5b8383346101535780600319360112610153576109a6611c3a565b6024356001600160a01b0380855416928451809463bcaa0c5560e01b825260078983015281602460209788935afa908115610ad3579083918891610a97575b50168015610a80573303610a7157169283855260158352818186205410610a4957907fe468e4bd9f7603e9acc4484edbd2aa85bc8f378431137b6b9eccb46ef9c4da49929184865260158352808620610a3f838254611d53565b905551908152a280f35b8590517f71b8d54c000000000000000000000000000000000000000000000000000000008152fd5b8685516306923c2160e21b8152fd5b602488600788519163092bc2cd60e41b8352820152fd5b809250868092503d8311610acc575b610ab08183611cb2565b81010312610ac857610ac28391611d09565b896109e5565b8680fd5b503d610aa6565b86513d89823e3d90fd5b919050346103425782600319360112610342576001600160a01b038354163303610b0d5782610b0a6121d5565b80f35b517fe1010280000000000000000000000000000000000000000000000000000000008152fd5b838334610153578060031936011261015357610b4d611c3a565b916024356001600160a01b0380835416958451809763bcaa0c5560e01b825260058383015281602460209a8b935afa908115610c49579083918691610c0d575b50168015610bf65733036102d2575081848092610bcd7fce1788297ab91d0a18f2652d9870130deccb877e50fc7e038e35518608e6669b95600854611d1d565b9716948581526015895220610be3878254611d46565b905581519081528587820152a251908152f35b602482600588519163092bc2cd60e41b8352820152fd5b809250898092503d8311610c42575b610c268183611cb2565b81010312610c3e57610c388391611d09565b89610b8d565b8480fd5b503d610c1c565b86513d87823e3d90fd5b8391503461015357816003193601126101535781549060ff8260a01c16610f69576001600160a01b0380928551907f6288a66c000000000000000000000000000000000000000000000000000000008252601184830152816024816020978894165afa908115610c49579082918691610f31575b50163303610f09576009549463ffffffff918287831c168015159081610efd575b50610ed557600b549183881697848914610ec25784600163ffffffff1998999a011696879116176009558793600a5480851115610eae575b508689526014885284828a2055600954620151804201804211610e9b576bffffffff000000000000000090841b16907fffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffff67ffffffff00000000428c1b1691161717978860095580600d549485600a558b600b55600f54168451988980927ff63ed21e0000000000000000000000000000000000000000000000000000000082525afa968715610e91578a97610e2e575b50907f88df7e235eae4a9cd8c83812aa435d1aaca8a58363a720e135d2f7e9067cb4ff9887969594939260e09998600c5583519889528282821c1690890152821c16908601526060850152608084015260a083015260c0820152a180f35b97965094939291908588813d8311610e8a575b610e4b8183611cb2565b81010312610e8657965195969394929391929091907f88df7e235eae4a9cd8c83812aa435d1aaca8a58363a720e135d2f7e9067cb4ff610dd0565b8980fd5b503d610e41565b83513d8c823e3d90fd5b60248b60118a634e487b7160e01b835252fd5b610ebb9195508490611d53565b9389610d20565b602488601188634e487b7160e01b835252fd5b8382517fa9fbff34000000000000000000000000000000000000000000000000000000008152fd5b90508342161088610ce8565b5083517ff7aa0316000000000000000000000000000000000000000000000000000000008152fd5b809250858092503d8311610f62575b610f4a8183611cb2565b81010312610c3e57610f5c8291611d09565b87610cc7565b503d610f40565b83517f8f85eea2000000000000000000000000000000000000000000000000000000008152fd5b82843461021b578060031936011261021b57506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610ffc57602090517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b517fe07c8dba000000000000000000000000000000000000000000000000000000008152fd5b9180915060031936011261034257611038611c3a565b90602493843567ffffffffffffffff8111610153573660238201121561015357808501359361106685611ced565b61107285519182611cb2565b85815260209586820193368a83830101116112ea578186928b8a93018737830101526001600160a01b03807f000000000000000000000000000000000000000000000000000000000000000016803014908115611387575b5061135f578085541687868b8b8a5194859384927fd91078070000000000000000000000000000000000000000000000000000000084528301525afa90811561135557908291879161131d575b501633036112f5578216958551907f52d1902d00000000000000000000000000000000000000000000000000000000825280828a818b5afa91829187936112c1575b505061118e57505050505051917f4c9c8ce3000000000000000000000000000000000000000000000000000000008352820152fd5b86899689927f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc908181036112935750853b1561126557805473ffffffffffffffffffffffffffffffffffffffff19168317905551869392917fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8580a282511561123057505061122c9382915190845af4611226612d5c565b91612d8c565b5080f35b9350935050503461124057505080f35b7fb398979f000000000000000000000000000000000000000000000000000000008152fd5b5087935051917f4c9c8ce3000000000000000000000000000000000000000000000000000000008352820152fd5b848a918451917faa1d49a4000000000000000000000000000000000000000000000000000000008352820152fd5b9080929350813d83116112ee575b6112d98183611cb2565b810103126112ea5751903880611159565b8580fd5b503d6112cf565b8786517ff7aa0316000000000000000000000000000000000000000000000000000000008152fd5b809250898092503d831161134e575b6113368183611cb2565b810103126112ea576113488291611d09565b38611117565b503d61132c565b87513d88823e3d90fd5b8786517fe07c8dba000000000000000000000000000000000000000000000000000000008152fd5b9050817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54161415386110ca565b8383346101535780600319360112610153576113cf611c3a565b906001600160a01b0393848454169282519363bcaa0c5560e01b96878652600c848701526020958681602481865afa908115610333579082918991611548575b501680156115315733036115225785879860248799989951809581938252600c898301525afa9182156115185790879493929187926114db575b5085517faad3ec960000000000000000000000000000000000000000000000000000000081526001600160a01b0390921693820193845260243560208501529095869384929083906040015b0393165af19081156114d257506114aa578280f35b813d83116114cb575b6114bd8183611cb2565b8101031261021b5781808280f35b503d6114b3565b513d85823e3d90fd5b8581969293503d8311611511575b6114f38183611cb2565b810103126112ea57611495956115098895611d09565b919096611449565b503d6114e9565b85513d88823e3d90fd5b8385516306923c2160e21b8152fd5b602485600c88519163092bc2cd60e41b8352820152fd5b809250888092503d8311611579575b6115618183611cb2565b81010312610328576115738291611d09565b8a61140f565b503d611557565b5050346101535781600319360112610153576001600160a01b0360209254169051908152f35b5050346101535781600319360112610153576020906001600160a01b03600354169051908152f35b5050346101535781600319360112610153576020906001600160a01b03600554169051908152f35b82843461021b578160031936011261021b57611610611c3a565b9260249384359067ffffffffffffffff8211611876573660238301121561187657818301359161163f83611cd5565b9061164c87519283611cb2565b838252602080830191828a60059760051b83010191368311610e86578b01905b828210611859575050506001600160a01b03928982858a54168b519283809263bcaa0c5560e01b825260058d8301525afa90811561184f579085918a91611813575b501680156117fd5733036117ee576007805494998997959691959194885b845160ff90818c1610156117645786611fe08c871b168701015116898b1015611752579061172461172a928a8f528c7fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688015490611d1d565b90611d46565b9860ff80911690811461174057600101986116cc565b8d8c60118d634e487b7160e01b835252fd5b8e8d60328e634e487b7160e01b835252fd5b5093908b9293508c87169283815260158752848120611784878254611d46565b9055845185815292518386018190526060840192915b888282106117d7578888887f6c765e879151a346eb51abbe29d880c53908aac8834abc8c8243bfe46256c94a89808a86888301520390a251908152f35b835160ff168552938401939092019160010161179a565b8689516306923c2160e21b8152fd5b8a8860058c519163092bc2cd60e41b8352820152fd5b809250848092503d8311611848575b61182c8183611cb2565b810103126118445761183e8591611d09565b8c6116ae565b8880fd5b503d611822565b8a513d8b823e3d90fd5b813560ff8116810361187257815290830190830161166c565b8a80fd5b8380fd5b905034610342576020918260031936011261187657611897611c3a565b9260095463ffffffff8082161515806119d3575b80156119c4575b61196b5750506001600160a01b03906024818388541685519283809263bcaa0c5560e01b825260078a8301525afa91821561196157879261192b575b50501680156119145733036119075783610b0a84611d71565b516306923c2160e21b8152fd5b602483600784519163092bc2cd60e41b8352820152fd5b90809250813d831161195a575b6119428183611cb2565b810103126112ea5761195390611d09565b38806118ee565b503d611938565b84513d89823e3d90fd5b83517fcf408ce100000000000000000000000000000000000000000000000000000000815263ffffffff42831681169682019687529383901c8216841660208701529190931c9092161660408301529081906060010390fd5b508082841c16814216106118b2565b508082851c16814216116118ab565b50503461015357816003193601126101535760c09160a08251611a0481611c50565b828152826020820152828482015282606082015282608082015201528051611a2b81611c50565b60095463ffffffff90818116938484526020840192808360201c1684528082860193831c168352600a54926060860193845281600b54956080880196875260a0600c5498019788528451988952511660208801525116908501525160608401525160808301525160a0820152f35b50503461015357816003193601126101535760c0906009549063ffffffff90600a54600b5491600c54938151958181168752818160201c166020880152821c16908501526060840152608083015260a0820152f35b909291503461187657836003193601126118765760095463ffffffff808216151580611c2b575b8015611c1b575b611bc15750505060206001600160a01b03600e54169260248351809581937f8c93caec00000000000000000000000000000000000000000000000000000000835233908301525afa908115611bb857508290611b7d575b610b0a9150611d71565b506020813d602011611bb0575b81611b9760209383611cb2565b8101031261015357611bab610b0a91611d09565b611b73565b3d9150611b8a565b513d84823e3d90fd5b7fcf408ce100000000000000000000000000000000000000000000000000000000835263ffffffff4282168116958401958652602083811c83168216908701529190931c9092169190911660408301529081906060010390fd5b50808260201c1681421610611b1c565b508082851c1681421611611b15565b600435906001600160a01b038216820361033d57565b60c0810190811067ffffffffffffffff821117611c6c57604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff8111611c6c57604052565b6040810190811067ffffffffffffffff821117611c6c57604052565b90601f601f19910116810190811067ffffffffffffffff821117611c6c57604052565b67ffffffffffffffff8111611c6c5760051b60200190565b67ffffffffffffffff8111611c6c57601f01601f191660200190565b51906001600160a01b038216820361033d57565b81810292918115918404141715611d3057565b634e487b7160e01b600052601160045260246000fd5b91908201809211611d3057565b91908203918211611d3057565b519063ffffffff8216820361033d57565b906001600160a01b039182600e5416908360409182519182917f5c12cd4b00000000000000000000000000000000000000000000000000000000835216938460048301528160246101009485935afa9182156121b2576000926120cd575b505063ffffffff908160095416918460005260209160138352838286600020541610611e45575b50847f220d1118acdf679f6c39811187de8f183671c369cacfc7f14e0767bf8aefde269596975060005260138252836000208363ffffffff1982541617905560095416908351928352820152a2565b611e5e600a548560005260148552866000205490611d46565b600c54600091811590811561201a575b50505080611e7d575b50611df6565b60c06000920189815116611f30575b9087989988927f220d1118acdf679f6c39811187de8f183671c369cacfc7f14e0767bf8aefde269960005260138752886000208863ffffffff198254161790556015875288600020611edf848254611d46565b9055611eed83600b54611d46565b600b5551169287519187835286830152878201527fafff6c9789072051de135b49539456a3ee34f9fb6c4c8dd467c38b87de655ee360603392a486959438611e77565b916004858b601054168951928380927f138993030000000000000000000000000000000000000000000000000000000082525afa91821561200f578092611fd7575b505090879899670de0b6b3a7640000611fad7f220d1118acdf679f6c39811187de8f183671c369cacfc7f14e0767bf8aefde269a9484611d1d565b0493818151166000526015875288600020611fc9868254611d46565b905591925099989750611e8c565b9091508582813d8311612008575b611fef8183611cb2565b8101031261021b57505189670de0b6b3a7640000611f72565b503d611fe5565b8851903d90823e3d90fd5b8b600f94929394541690878b60248c51809581937f26342d0b00000000000000000000000000000000000000000000000000000000835260048301525afa80156120c3578390612092575b61206f9250611d1d565b9161207e575004388080611e6e565b80634e487b7160e01b602492526012600452fd5b50908781813d83116120bc575b6120a98183611cb2565b81010312610342579061206f9151612065565b503d61209f565b8a513d85823e3d90fd5b81813d83116121ab575b6120e18183611cb2565b81010390811261034257601f1960e0916120fa84611d09565b5001126101535782519160e0830183811067ffffffffffffffff82111761219757845261212960208301611d60565b8352612136848301611d60565b602084015261214760608301611d60565b848401526080820151600681101561015357606084015260a08201519061ffff8216820361021b5750608083015260c081015160a083015261218b9060e001611d09565b60c08201523880611dcf565b602482634e487b7160e01b81526041600452fd5b503d6120d7565b83513d6000823e3d90fd5b9081602091031261033d5751801515810361033d5790565b60006001600160a01b03808254166040805163bcaa0c5560e01b808252600490600382840152602092602491848284818a5afa91821561267a578992612d25575b508773ffffffffffffffffffffffffffffffffffffffff19921682600e541617600e5585518181528585820152858185818b5afa9081156126fe579089918b91612ced575b50168260105416176010558551818152600785820152858185818b5afa9081156126fe579089918b91612cb5575b501682600f541617600f558551818152600b85820152858185818b5afa9081156126fe579089918b91612c7d575b5016916011549783828a16176011558751907f42ab14dd0000000000000000000000000000000000000000000000000000000091828152602a8882015288818881855afa908115612906578d91612c50575b50600d558851828152602b8882015288818881855afa908115612906578d91612c23575b506012558851997ff2aac76c0000000000000000000000000000000000000000000000000000000095868c52602c898d0152898c8981865afa9b8c15612c1757908e939291849d612bf0575b5090889392917fffffffffffffffffffffff00000000000000000000000000000000000000000074ff00000000000000000000000000000000000000009e8f90151560a01b16921617176011558a51928380927fff74ad5f000000000000000000000000000000000000000000000000000000008252602d8c8301525afa90811561278f578c91612b58575b5080519067ffffffffffffffff8211612b4657680100000000000000008211612b4657889060075483600755808410612b01575b500160078d528c5b828110612acf57505050898b5416908851908152602e8782015287818781855afa90811561278f5791889187938e91612a9b575b50600855895192838092878252600f8b8301525afa908115612a91578b91612a5c575b506001548a821690838c8216830361294a575b50505050888a5416875183815260108782015287818781855afa90811561278f57908692918d91612910575b50888c6002549216928d83168403612814575b5050505050888a541687519083825260128783015287828781845afa91821561278f5786929189918e936127da575b508a519384809288825260138c8301525afa91821561278f57918c939189938592612799575b508c6005549116908d81168203612708575b50508b6006549116918c82168303612684575b505050908990541691848851809481938252600c898301525afa90811561267a578991612639575b50918493918389600197951661262a575b5089549887519687948593845283015289165afa9283156126215750907fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff93929186926125f4575b5050151560a01b169116179055565b6126139250803d1061261a575b61260b8183611cb2565b8101906121bd565b38806125e5565b503d612601565b513d87823e3d90fd5b61263390612e1f565b3861259d565b90508481813d8311612673575b6126508183611cb2565b81010312611844579184939161266860019694611d09565b91935091939461258c565b503d612646565b86513d8b823e3d90fd5b82911617600655858951809481937f1a33757d00000000000000000000000000000000000000000000000000000000835260028b8401525af180156126fe579086916126d5575b9081808c93612564565b813d83116126f7575b6126e88183611cb2565b8101031261033d5784386126cb565b503d6126de565b87513d8c823e3d90fd5b831681176005558a517f1a33757d00000000000000000000000000000000000000000000000000000000815260028a82015292949193918391899183915af1801561278f57918c9391899361275e575b80612551565b9092809294503d8311612788575b6127768183611cb2565b8101031261033d578a91879138612758565b503d61276c565b89513d8e823e3d90fd5b92945092905081813d83116127d3575b6127b38183611cb2565b810103126127cf579187916127c88d94611d09565b903861253f565b8b80fd5b503d6127a9565b9250925081813d831161280d575b6127f28183611cb2565b810103126127cf5790876128068793611d09565b9138612519565b503d6127e8565b83868416176002558b519485809289825260118d8301525afa92831561290657908d9182946128c8575b508c89541615612852575b508887936124ea565b161790813b156127cf578b8b8782938c5194859384927f36b91f2b0000000000000000000000000000000000000000000000000000000084521696878d8401525af1801561278f57908c916128b4575b50508186541617855538808b81612849565b6128bd90611c82565b611872578a386128a2565b8a809295508193503d83116128ff575b6128e28183611cb2565b810103126128fb576128f48d91611d09565b923861283e565b8c80fd5b503d6128d8565b8a513d8f823e3d90fd5b80929350898092503d8311612943575b61292a8183611cb2565b810103126127cf579061293d8692611d09565b386124d7565b503d612920565b16811760015588517ffe9fbb80000000000000000000000000000000000000000000000000000000008152308882015288818881855afa908115612906578d91612a3f575b5061299c575b80836124ab565b803b156127cf578b8091888b51809481937f4e606c470000000000000000000000000000000000000000000000000000000083525af1801561278f57612a2c575b508a80918951828a8201917ff098767a0000000000000000000000000000000000000000000000000000000083528a8152612a1781611c96565b51925af150612a24612d5c565b503880612995565b612a38909b919b611c82565b99386129dd565b612a569150893d8b1161261a5761260b8183611cb2565b3861298f565b90508681813d8311612a8a575b612a738183611cb2565b8101031261187257612a8490611d09565b38612498565b503d612a69565b88513d8d823e3d90fd5b92809294508391503d8311612ac8575b612ab58183611cb2565b810103126127cf57859188915138612475565b503d612aab565b81517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68882015590890190600101612441565b7fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889081019084018f5b828210612b38575050612439565b81558b93506001018f612b2a565b868d60418a634e487b7160e01b835252fd5b90503d808d833e612b698183611cb2565b81019088818303126128fb5780519067ffffffffffffffff8211612bec57019080601f830112156128fb578151612b9f81611cd5565b92612bac8c519485611cb2565b8184528a8085019260051b820101928311612be8578a809101915b838310612bd8575050505038612405565b82518152918101918b9101612bc7565b8e80fd5b8d80fd5b89949392919d50612c0d908c8d3d1061261a5761260b8183611cb2565b9c90919293612379565b8e8c51903d90823e3d90fd5b90508881813d8311612c49575b612c3a8183611cb2565b810103126128fb57513861232d565b503d612c30565b90508881813d8311612c76575b612c678183611cb2565b810103126128fb575138612309565b503d612c5d565b809250878092503d8311612cae575b612c968183611cb2565b81010312610e8657612ca88991611d09565b386122b7565b503d612c8c565b809250878092503d8311612ce6575b612cce8183611cb2565b81010312610e8657612ce08991611d09565b38612289565b503d612cc4565b809250878092503d8311612d1e575b612d068183611cb2565b81010312610e8657612d188991611d09565b3861225b565b503d612cfc565b9091508481813d8311612d55575b612d3d8183611cb2565b8101031261184457612d4e90611d09565b9038612216565b503d612d33565b3d15612d87573d90612d6d82611ced565b91612d7b6040519384611cb2565b82523d6000602084013e565b606090565b90612dcb5750805115612da157805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580612e16575b612ddc575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15612dd4565b6001600160a01b03809116908115612f3e57806001541615612f3a57600354811680612ed95750308203612e70575b505b73ffffffffffffffffffffffffffffffffffffffff196003541617600355565b60015416803b1561033d57600080916024604051809481937feb8646980000000000000000000000000000000000000000000000000000000083528760048401525af18015612ecd5715612e4e57612ec790611c82565b38612e4e565b6040513d6000823e3d90fd5b8091503b1561033d57600080916024604051809481937f3a74bfd70000000000000000000000000000000000000000000000000000000083528760048401525af18015612ecd57612f2b575b50612e50565b612f3490611c82565b38612f25565b5050565b60046040517f05d8ce3d000000000000000000000000000000000000000000000000000000008152fdfea264697066735822122032093746a3882c6e7e01f699630d4d262c0e934537a5a85f5ea7872d21b622ee64736f6c63430008190033
Deployed Bytecode
0x608060408181526004918236101561001657600080fd5b600092833560e01c91826304d092c714611aee575081630604061814611a99578163086146d2146119e25781631abb7b0b1461187a5781631b504564146115f657816331a0edec146115ce5781633cdad82c146115a6578163443b1786146115805781634b03eeb4146113b55781634f1ef2861461102257816352d1902d14610f905781635e11544b14610c535781636455c6fc14610b335781638da52e9314610add578163918d24281461098c578163970567e114610739578163ad3cb1cc146106a7578163ad5c46481461067f578163b930b48214610657578163c4d66de814610365578163cea0ee0c14610346578163e20859fc1461021e578163ee204abb14610157575063fce14af61461012d57600080fd5b346101535781600319360112610153576020906001600160a01b03600154169051908152f35b5080fd5b838334610153576020918260031936011261021b57602483610177611c3a565b6001600160a01b0392839182600e54168751998a9485937f8c93caec00000000000000000000000000000000000000000000000000000000855216908301525afa80156102115782906101d9575b839495501681526015845220549051908152f35b508385813d831161020a575b6101ef8183611cb2565b8101031261015357610202839495611d09565b8594506101c5565b503d6101e5565b83513d84823e3d90fd5b80fd5b91905034610342578060031936011261034257610239611c3a565b91602435926001600160a01b039081851680950361033d5781865416928451809463bcaa0c5560e01b825260038383015281602460209788935afa9081156103335790849189916102f7575b501680156102e05733036102d257509060139291168086526015825283862086815491558587528487205585525263ffffffff818420541691835282209063ffffffff1982541617905580f35b84516306923c2160e21b8152fd5b602482600388519163092bc2cd60e41b8352820152fd5b809250868092503d831161032c575b6103108183611cb2565b81010312610328576103228491611d09565b38610285565b8780fd5b503d610306565b86513d8a823e3d90fd5b600080fd5b8280fd5b505034610153578160031936011261015357602090600d549051908152f35b90503461034257602060031936011261034257610380611c3a565b907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0091825460ff81861c16159167ffffffffffffffff9081831694851580610650575b60018097149081610646575b15908161063d575b5061062f577fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000938587868316178955610610575b5086549360ff858a1c1615948481168881159182610608575b1490816105fe575b1590816105f5575b506105e6578588838316178a556105c7575b5087549160ff838b1c161594831688811591826105bf575b1490816105b5575b1590816105ac575b5061059e57508116861787556001600160a01b0391908361057f575b501673ffffffffffffffffffffffffffffffffffffffff19885416178755610541575b610503575b6104ba6121d5565b6104c2578380f35b7fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2928268ff0000000000000000196020945416905551908152a13880808380f35b68ff00000000000000001983541683557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d260208551848152a16104b2565b68ff00000000000000001984541684557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d260208651858152a16104ad565b68ffffffffffffffffff1916680100000000000000011787553861048a565b895163f92ee8a960e01b8152fd5b9050153861046e565b303b159150610466565b87925061045e565b68ffffffffffffffffff19166801000000000000000117885538610446565b828a5163f92ee8a960e01b8152fd5b90501538610434565b303b15915061042c565b889250610424565b68ffffffffffffffffff1916680100000000000000011787553861040b565b875163f92ee8a960e01b8152fd5b905015386103d7565b303b1591506103cf565b50846103c3565b5050346101535781600319360112610153576020906001600160a01b03600254169051908152f35b5050346101535781600319360112610153576020906001600160a01b03600654169051908152f35b50503461015357816003193601126101535780516106c481611c96565b600581526020907f352e302e300000000000000000000000000000000000000000000000000000006020820152825193849260208452825192836020860152825b84811061072357505050828201840152601f01601f19168101030190f35b8181018301518882018801528795508201610705565b919050346103425760206003193601126103425781359160ff845460a01c166109655760ff60115460a01c161561093e5733845260156020528184205483158015610936575b61090e5783116108e75760125480156108bf576107a264e8d4a510009185611d1d565b049081156108985733855260156020528285206107c0858254611d53565b9055846001600160a01b036011541691823b156101535784517f40c10f19000000000000000000000000000000000000000000000000000000008152339181019182526020820185905292839182908490829060400103925af1801561088e57610859575b50907f6458c94e9777bbc30aee6f0b0a4509d5a7789f8cdfdedb960debd3573997540d91815193845260208401523392a280f35b936108867f6458c94e9777bbc30aee6f0b0a4509d5a7789f8cdfdedb960debd3573997540d939295611c82565b939091610825565b83513d87823e3d90fd5b82517f83231208000000000000000000000000000000000000000000000000000000008152fd5b5090517f8a9422f4000000000000000000000000000000000000000000000000000000008152fd5b90517f71b8d54c000000000000000000000000000000000000000000000000000000008152fd5b5090517f300583e8000000000000000000000000000000000000000000000000000000008152fd5b50801561077f565b90517f655c1656000000000000000000000000000000000000000000000000000000008152fd5b90517f8f85eea2000000000000000000000000000000000000000000000000000000008152fd5b8383346101535780600319360112610153576109a6611c3a565b6024356001600160a01b0380855416928451809463bcaa0c5560e01b825260078983015281602460209788935afa908115610ad3579083918891610a97575b50168015610a80573303610a7157169283855260158352818186205410610a4957907fe468e4bd9f7603e9acc4484edbd2aa85bc8f378431137b6b9eccb46ef9c4da49929184865260158352808620610a3f838254611d53565b905551908152a280f35b8590517f71b8d54c000000000000000000000000000000000000000000000000000000008152fd5b8685516306923c2160e21b8152fd5b602488600788519163092bc2cd60e41b8352820152fd5b809250868092503d8311610acc575b610ab08183611cb2565b81010312610ac857610ac28391611d09565b896109e5565b8680fd5b503d610aa6565b86513d89823e3d90fd5b919050346103425782600319360112610342576001600160a01b038354163303610b0d5782610b0a6121d5565b80f35b517fe1010280000000000000000000000000000000000000000000000000000000008152fd5b838334610153578060031936011261015357610b4d611c3a565b916024356001600160a01b0380835416958451809763bcaa0c5560e01b825260058383015281602460209a8b935afa908115610c49579083918691610c0d575b50168015610bf65733036102d2575081848092610bcd7fce1788297ab91d0a18f2652d9870130deccb877e50fc7e038e35518608e6669b95600854611d1d565b9716948581526015895220610be3878254611d46565b905581519081528587820152a251908152f35b602482600588519163092bc2cd60e41b8352820152fd5b809250898092503d8311610c42575b610c268183611cb2565b81010312610c3e57610c388391611d09565b89610b8d565b8480fd5b503d610c1c565b86513d87823e3d90fd5b8391503461015357816003193601126101535781549060ff8260a01c16610f69576001600160a01b0380928551907f6288a66c000000000000000000000000000000000000000000000000000000008252601184830152816024816020978894165afa908115610c49579082918691610f31575b50163303610f09576009549463ffffffff918287831c168015159081610efd575b50610ed557600b549183881697848914610ec25784600163ffffffff1998999a011696879116176009558793600a5480851115610eae575b508689526014885284828a2055600954620151804201804211610e9b576bffffffff000000000000000090841b16907fffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffff67ffffffff00000000428c1b1691161717978860095580600d549485600a558b600b55600f54168451988980927ff63ed21e0000000000000000000000000000000000000000000000000000000082525afa968715610e91578a97610e2e575b50907f88df7e235eae4a9cd8c83812aa435d1aaca8a58363a720e135d2f7e9067cb4ff9887969594939260e09998600c5583519889528282821c1690890152821c16908601526060850152608084015260a083015260c0820152a180f35b97965094939291908588813d8311610e8a575b610e4b8183611cb2565b81010312610e8657965195969394929391929091907f88df7e235eae4a9cd8c83812aa435d1aaca8a58363a720e135d2f7e9067cb4ff610dd0565b8980fd5b503d610e41565b83513d8c823e3d90fd5b60248b60118a634e487b7160e01b835252fd5b610ebb9195508490611d53565b9389610d20565b602488601188634e487b7160e01b835252fd5b8382517fa9fbff34000000000000000000000000000000000000000000000000000000008152fd5b90508342161088610ce8565b5083517ff7aa0316000000000000000000000000000000000000000000000000000000008152fd5b809250858092503d8311610f62575b610f4a8183611cb2565b81010312610c3e57610f5c8291611d09565b87610cc7565b503d610f40565b83517f8f85eea2000000000000000000000000000000000000000000000000000000008152fd5b82843461021b578060031936011261021b57506001600160a01b037f00000000000000000000000030fc05d18d68be6a07092ae8b00efa06f747572e163003610ffc57602090517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b517fe07c8dba000000000000000000000000000000000000000000000000000000008152fd5b9180915060031936011261034257611038611c3a565b90602493843567ffffffffffffffff8111610153573660238201121561015357808501359361106685611ced565b61107285519182611cb2565b85815260209586820193368a83830101116112ea578186928b8a93018737830101526001600160a01b03807f00000000000000000000000030fc05d18d68be6a07092ae8b00efa06f747572e16803014908115611387575b5061135f578085541687868b8b8a5194859384927fd91078070000000000000000000000000000000000000000000000000000000084528301525afa90811561135557908291879161131d575b501633036112f5578216958551907f52d1902d00000000000000000000000000000000000000000000000000000000825280828a818b5afa91829187936112c1575b505061118e57505050505051917f4c9c8ce3000000000000000000000000000000000000000000000000000000008352820152fd5b86899689927f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc908181036112935750853b1561126557805473ffffffffffffffffffffffffffffffffffffffff19168317905551869392917fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8580a282511561123057505061122c9382915190845af4611226612d5c565b91612d8c565b5080f35b9350935050503461124057505080f35b7fb398979f000000000000000000000000000000000000000000000000000000008152fd5b5087935051917f4c9c8ce3000000000000000000000000000000000000000000000000000000008352820152fd5b848a918451917faa1d49a4000000000000000000000000000000000000000000000000000000008352820152fd5b9080929350813d83116112ee575b6112d98183611cb2565b810103126112ea5751903880611159565b8580fd5b503d6112cf565b8786517ff7aa0316000000000000000000000000000000000000000000000000000000008152fd5b809250898092503d831161134e575b6113368183611cb2565b810103126112ea576113488291611d09565b38611117565b503d61132c565b87513d88823e3d90fd5b8786517fe07c8dba000000000000000000000000000000000000000000000000000000008152fd5b9050817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54161415386110ca565b8383346101535780600319360112610153576113cf611c3a565b906001600160a01b0393848454169282519363bcaa0c5560e01b96878652600c848701526020958681602481865afa908115610333579082918991611548575b501680156115315733036115225785879860248799989951809581938252600c898301525afa9182156115185790879493929187926114db575b5085517faad3ec960000000000000000000000000000000000000000000000000000000081526001600160a01b0390921693820193845260243560208501529095869384929083906040015b0393165af19081156114d257506114aa578280f35b813d83116114cb575b6114bd8183611cb2565b8101031261021b5781808280f35b503d6114b3565b513d85823e3d90fd5b8581969293503d8311611511575b6114f38183611cb2565b810103126112ea57611495956115098895611d09565b919096611449565b503d6114e9565b85513d88823e3d90fd5b8385516306923c2160e21b8152fd5b602485600c88519163092bc2cd60e41b8352820152fd5b809250888092503d8311611579575b6115618183611cb2565b81010312610328576115738291611d09565b8a61140f565b503d611557565b5050346101535781600319360112610153576001600160a01b0360209254169051908152f35b5050346101535781600319360112610153576020906001600160a01b03600354169051908152f35b5050346101535781600319360112610153576020906001600160a01b03600554169051908152f35b82843461021b578160031936011261021b57611610611c3a565b9260249384359067ffffffffffffffff8211611876573660238301121561187657818301359161163f83611cd5565b9061164c87519283611cb2565b838252602080830191828a60059760051b83010191368311610e86578b01905b828210611859575050506001600160a01b03928982858a54168b519283809263bcaa0c5560e01b825260058d8301525afa90811561184f579085918a91611813575b501680156117fd5733036117ee576007805494998997959691959194885b845160ff90818c1610156117645786611fe08c871b168701015116898b1015611752579061172461172a928a8f528c7fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688015490611d1d565b90611d46565b9860ff80911690811461174057600101986116cc565b8d8c60118d634e487b7160e01b835252fd5b8e8d60328e634e487b7160e01b835252fd5b5093908b9293508c87169283815260158752848120611784878254611d46565b9055845185815292518386018190526060840192915b888282106117d7578888887f6c765e879151a346eb51abbe29d880c53908aac8834abc8c8243bfe46256c94a89808a86888301520390a251908152f35b835160ff168552938401939092019160010161179a565b8689516306923c2160e21b8152fd5b8a8860058c519163092bc2cd60e41b8352820152fd5b809250848092503d8311611848575b61182c8183611cb2565b810103126118445761183e8591611d09565b8c6116ae565b8880fd5b503d611822565b8a513d8b823e3d90fd5b813560ff8116810361187257815290830190830161166c565b8a80fd5b8380fd5b905034610342576020918260031936011261187657611897611c3a565b9260095463ffffffff8082161515806119d3575b80156119c4575b61196b5750506001600160a01b03906024818388541685519283809263bcaa0c5560e01b825260078a8301525afa91821561196157879261192b575b50501680156119145733036119075783610b0a84611d71565b516306923c2160e21b8152fd5b602483600784519163092bc2cd60e41b8352820152fd5b90809250813d831161195a575b6119428183611cb2565b810103126112ea5761195390611d09565b38806118ee565b503d611938565b84513d89823e3d90fd5b83517fcf408ce100000000000000000000000000000000000000000000000000000000815263ffffffff42831681169682019687529383901c8216841660208701529190931c9092161660408301529081906060010390fd5b508082841c16814216106118b2565b508082851c16814216116118ab565b50503461015357816003193601126101535760c09160a08251611a0481611c50565b828152826020820152828482015282606082015282608082015201528051611a2b81611c50565b60095463ffffffff90818116938484526020840192808360201c1684528082860193831c168352600a54926060860193845281600b54956080880196875260a0600c5498019788528451988952511660208801525116908501525160608401525160808301525160a0820152f35b50503461015357816003193601126101535760c0906009549063ffffffff90600a54600b5491600c54938151958181168752818160201c166020880152821c16908501526060840152608083015260a0820152f35b909291503461187657836003193601126118765760095463ffffffff808216151580611c2b575b8015611c1b575b611bc15750505060206001600160a01b03600e54169260248351809581937f8c93caec00000000000000000000000000000000000000000000000000000000835233908301525afa908115611bb857508290611b7d575b610b0a9150611d71565b506020813d602011611bb0575b81611b9760209383611cb2565b8101031261015357611bab610b0a91611d09565b611b73565b3d9150611b8a565b513d84823e3d90fd5b7fcf408ce100000000000000000000000000000000000000000000000000000000835263ffffffff4282168116958401958652602083811c83168216908701529190931c9092169190911660408301529081906060010390fd5b50808260201c1681421610611b1c565b508082851c1681421611611b15565b600435906001600160a01b038216820361033d57565b60c0810190811067ffffffffffffffff821117611c6c57604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff8111611c6c57604052565b6040810190811067ffffffffffffffff821117611c6c57604052565b90601f601f19910116810190811067ffffffffffffffff821117611c6c57604052565b67ffffffffffffffff8111611c6c5760051b60200190565b67ffffffffffffffff8111611c6c57601f01601f191660200190565b51906001600160a01b038216820361033d57565b81810292918115918404141715611d3057565b634e487b7160e01b600052601160045260246000fd5b91908201809211611d3057565b91908203918211611d3057565b519063ffffffff8216820361033d57565b906001600160a01b039182600e5416908360409182519182917f5c12cd4b00000000000000000000000000000000000000000000000000000000835216938460048301528160246101009485935afa9182156121b2576000926120cd575b505063ffffffff908160095416918460005260209160138352838286600020541610611e45575b50847f220d1118acdf679f6c39811187de8f183671c369cacfc7f14e0767bf8aefde269596975060005260138252836000208363ffffffff1982541617905560095416908351928352820152a2565b611e5e600a548560005260148552866000205490611d46565b600c54600091811590811561201a575b50505080611e7d575b50611df6565b60c06000920189815116611f30575b9087989988927f220d1118acdf679f6c39811187de8f183671c369cacfc7f14e0767bf8aefde269960005260138752886000208863ffffffff198254161790556015875288600020611edf848254611d46565b9055611eed83600b54611d46565b600b5551169287519187835286830152878201527fafff6c9789072051de135b49539456a3ee34f9fb6c4c8dd467c38b87de655ee360603392a486959438611e77565b916004858b601054168951928380927f138993030000000000000000000000000000000000000000000000000000000082525afa91821561200f578092611fd7575b505090879899670de0b6b3a7640000611fad7f220d1118acdf679f6c39811187de8f183671c369cacfc7f14e0767bf8aefde269a9484611d1d565b0493818151166000526015875288600020611fc9868254611d46565b905591925099989750611e8c565b9091508582813d8311612008575b611fef8183611cb2565b8101031261021b57505189670de0b6b3a7640000611f72565b503d611fe5565b8851903d90823e3d90fd5b8b600f94929394541690878b60248c51809581937f26342d0b00000000000000000000000000000000000000000000000000000000835260048301525afa80156120c3578390612092575b61206f9250611d1d565b9161207e575004388080611e6e565b80634e487b7160e01b602492526012600452fd5b50908781813d83116120bc575b6120a98183611cb2565b81010312610342579061206f9151612065565b503d61209f565b8a513d85823e3d90fd5b81813d83116121ab575b6120e18183611cb2565b81010390811261034257601f1960e0916120fa84611d09565b5001126101535782519160e0830183811067ffffffffffffffff82111761219757845261212960208301611d60565b8352612136848301611d60565b602084015261214760608301611d60565b848401526080820151600681101561015357606084015260a08201519061ffff8216820361021b5750608083015260c081015160a083015261218b9060e001611d09565b60c08201523880611dcf565b602482634e487b7160e01b81526041600452fd5b503d6120d7565b83513d6000823e3d90fd5b9081602091031261033d5751801515810361033d5790565b60006001600160a01b03808254166040805163bcaa0c5560e01b808252600490600382840152602092602491848284818a5afa91821561267a578992612d25575b508773ffffffffffffffffffffffffffffffffffffffff19921682600e541617600e5585518181528585820152858185818b5afa9081156126fe579089918b91612ced575b50168260105416176010558551818152600785820152858185818b5afa9081156126fe579089918b91612cb5575b501682600f541617600f558551818152600b85820152858185818b5afa9081156126fe579089918b91612c7d575b5016916011549783828a16176011558751907f42ab14dd0000000000000000000000000000000000000000000000000000000091828152602a8882015288818881855afa908115612906578d91612c50575b50600d558851828152602b8882015288818881855afa908115612906578d91612c23575b506012558851997ff2aac76c0000000000000000000000000000000000000000000000000000000095868c52602c898d0152898c8981865afa9b8c15612c1757908e939291849d612bf0575b5090889392917fffffffffffffffffffffff00000000000000000000000000000000000000000074ff00000000000000000000000000000000000000009e8f90151560a01b16921617176011558a51928380927fff74ad5f000000000000000000000000000000000000000000000000000000008252602d8c8301525afa90811561278f578c91612b58575b5080519067ffffffffffffffff8211612b4657680100000000000000008211612b4657889060075483600755808410612b01575b500160078d528c5b828110612acf57505050898b5416908851908152602e8782015287818781855afa90811561278f5791889187938e91612a9b575b50600855895192838092878252600f8b8301525afa908115612a91578b91612a5c575b506001548a821690838c8216830361294a575b50505050888a5416875183815260108782015287818781855afa90811561278f57908692918d91612910575b50888c6002549216928d83168403612814575b5050505050888a541687519083825260128783015287828781845afa91821561278f5786929189918e936127da575b508a519384809288825260138c8301525afa91821561278f57918c939189938592612799575b508c6005549116908d81168203612708575b50508b6006549116918c82168303612684575b505050908990541691848851809481938252600c898301525afa90811561267a578991612639575b50918493918389600197951661262a575b5089549887519687948593845283015289165afa9283156126215750907fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff93929186926125f4575b5050151560a01b169116179055565b6126139250803d1061261a575b61260b8183611cb2565b8101906121bd565b38806125e5565b503d612601565b513d87823e3d90fd5b61263390612e1f565b3861259d565b90508481813d8311612673575b6126508183611cb2565b81010312611844579184939161266860019694611d09565b91935091939461258c565b503d612646565b86513d8b823e3d90fd5b82911617600655858951809481937f1a33757d00000000000000000000000000000000000000000000000000000000835260028b8401525af180156126fe579086916126d5575b9081808c93612564565b813d83116126f7575b6126e88183611cb2565b8101031261033d5784386126cb565b503d6126de565b87513d8c823e3d90fd5b831681176005558a517f1a33757d00000000000000000000000000000000000000000000000000000000815260028a82015292949193918391899183915af1801561278f57918c9391899361275e575b80612551565b9092809294503d8311612788575b6127768183611cb2565b8101031261033d578a91879138612758565b503d61276c565b89513d8e823e3d90fd5b92945092905081813d83116127d3575b6127b38183611cb2565b810103126127cf579187916127c88d94611d09565b903861253f565b8b80fd5b503d6127a9565b9250925081813d831161280d575b6127f28183611cb2565b810103126127cf5790876128068793611d09565b9138612519565b503d6127e8565b83868416176002558b519485809289825260118d8301525afa92831561290657908d9182946128c8575b508c89541615612852575b508887936124ea565b161790813b156127cf578b8b8782938c5194859384927f36b91f2b0000000000000000000000000000000000000000000000000000000084521696878d8401525af1801561278f57908c916128b4575b50508186541617855538808b81612849565b6128bd90611c82565b611872578a386128a2565b8a809295508193503d83116128ff575b6128e28183611cb2565b810103126128fb576128f48d91611d09565b923861283e565b8c80fd5b503d6128d8565b8a513d8f823e3d90fd5b80929350898092503d8311612943575b61292a8183611cb2565b810103126127cf579061293d8692611d09565b386124d7565b503d612920565b16811760015588517ffe9fbb80000000000000000000000000000000000000000000000000000000008152308882015288818881855afa908115612906578d91612a3f575b5061299c575b80836124ab565b803b156127cf578b8091888b51809481937f4e606c470000000000000000000000000000000000000000000000000000000083525af1801561278f57612a2c575b508a80918951828a8201917ff098767a0000000000000000000000000000000000000000000000000000000083528a8152612a1781611c96565b51925af150612a24612d5c565b503880612995565b612a38909b919b611c82565b99386129dd565b612a569150893d8b1161261a5761260b8183611cb2565b3861298f565b90508681813d8311612a8a575b612a738183611cb2565b8101031261187257612a8490611d09565b38612498565b503d612a69565b88513d8d823e3d90fd5b92809294508391503d8311612ac8575b612ab58183611cb2565b810103126127cf57859188915138612475565b503d612aab565b81517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68882015590890190600101612441565b7fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889081019084018f5b828210612b38575050612439565b81558b93506001018f612b2a565b868d60418a634e487b7160e01b835252fd5b90503d808d833e612b698183611cb2565b81019088818303126128fb5780519067ffffffffffffffff8211612bec57019080601f830112156128fb578151612b9f81611cd5565b92612bac8c519485611cb2565b8184528a8085019260051b820101928311612be8578a809101915b838310612bd8575050505038612405565b82518152918101918b9101612bc7565b8e80fd5b8d80fd5b89949392919d50612c0d908c8d3d1061261a5761260b8183611cb2565b9c90919293612379565b8e8c51903d90823e3d90fd5b90508881813d8311612c49575b612c3a8183611cb2565b810103126128fb57513861232d565b503d612c30565b90508881813d8311612c76575b612c678183611cb2565b810103126128fb575138612309565b503d612c5d565b809250878092503d8311612cae575b612c968183611cb2565b81010312610e8657612ca88991611d09565b386122b7565b503d612c8c565b809250878092503d8311612ce6575b612cce8183611cb2565b81010312610e8657612ce08991611d09565b38612289565b503d612cc4565b809250878092503d8311612d1e575b612d068183611cb2565b81010312610e8657612d188991611d09565b3861225b565b503d612cfc565b9091508481813d8311612d55575b612d3d8183611cb2565b8101031261184457612d4e90611d09565b9038612216565b503d612d33565b3d15612d87573d90612d6d82611ced565b91612d7b6040519384611cb2565b82523d6000602084013e565b606090565b90612dcb5750805115612da157805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580612e16575b612ddc575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15612dd4565b6001600160a01b03809116908115612f3e57806001541615612f3a57600354811680612ed95750308203612e70575b505b73ffffffffffffffffffffffffffffffffffffffff196003541617600355565b60015416803b1561033d57600080916024604051809481937feb8646980000000000000000000000000000000000000000000000000000000083528760048401525af18015612ecd5715612e4e57612ec790611c82565b38612e4e565b6040513d6000823e3d90fd5b8091503b1561033d57600080916024604051809481937f3a74bfd70000000000000000000000000000000000000000000000000000000083528760048401525af18015612ecd57612f2b575b50612e50565b612f3490611c82565b38612f25565b5050565b60046040517f05d8ce3d000000000000000000000000000000000000000000000000000000008152fdfea264697066735822122032093746a3882c6e7e01f699630d4d262c0e934537a5a85f5ea7872d21b622ee64736f6c63430008190033
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.